1

full example here

type NumericKeysOnly<T> = {
  [K in keyof T]: T[K] extends number | undefined ? K : never;
}[keyof T];

type MetricFieldKey<T> = Exclude<NumericKeysOnly<T>, undefined>;

export type TestType = {
  id: number;
  name?: number;
  description: string;
  createdAt: Date;
  updatedAt: Date;
};

export type TestType2 = TestType & {
  extraParam?: number;
};

export type TestType3 = TestType & {
  megaParam?: number;
};

type RowConfig<T> = {
  label: string;
  fieldName: MetricFieldKey<T>;
  order: number;
};

function TestControl<T extends TestType>({
  data,
  showRows,
}: {
  data: T;
  showRows?: RowConfig<T>[];
}) {
  return (
    showRows &&
    showRows.map((row) => {
      return <div key={row.label}>{data[row.fieldName]}</div>;
    })
  );
}

usage :

   <TestControl
        data={testData3}
        showRows={[
          { label: 'ID', fieldName: 'id', order: 1 },
          { label: 'Name', fieldName: 'name', order: 2 },
          { label: 'Mega Param', fieldName: 'megaParam', order: 6 },
        ]}
      />

It works as expected, showRows allow only specific keys of provided object even if it extends base type.

but in case of array:


export function ArrayTestContainer() {
  return (
    <ComposedTestControl
      datas={[
        {
          label: 'Test Tab 1',
          data: testData,
          showRows: [
            { label: 'ID', fieldName: 'id', order: 1 },
            { label: 'Name', fieldName: 'name', order: 2 },
          ],
        },
        {
          label: 'Test Tab 2',
          data: testData2,
          showRows: [
            { label: 'ID', fieldName: 'id', order: 1 },
            { label: 'Name', fieldName: 'name', order: 2 },
            { label: 'Extra Param', fieldName: 'extraParam', order: 6 },
          ],
        },
        {
          label: 'Test Tab 3',
          data: testData3,
          showRows: [
            { label: 'ID', fieldName: 'id', order: 1 },
            { label: 'Name', fieldName: 'name', order: 2 },
            { label: 'Mega Param', fieldName: 'megaParam', order: 6 },
          ],
        },
      ]}
    />
  );
}

information about exact type lost, and all types threaten as base TestType

is it possible to restore per element data information ? I also not want use "any" tried to use "as const" to make snapshot type, but get even more compile errros with readonly problems. For example cast it to something or use explicit classes instead of types?

4
  • Please edit your code example to be a minimal reproducible example that uses fewer lines of code (the whole thing should fit on a single screen; if people have to scroll to understand the example and cannot see it all at once, it increases the cognitive load. I have very very rarely seen an example that cannot be reduced to fit on one screen. Also, your code should not have errors you're not asking about... Does Type 'T[Exclude<NumericKeysOnly<T>, undefined>]' is not assignable to type 'ReactNode'. matter? If not, it should not be in the example. Commented Jul 18 at 1:49
  • (Pls see prev comment) Presumably you're looking for something like this with a homomorphic mapped array type. Does that meet your needs? If so I could write an answer explaining or find a duplicate, but it would be very very helpful if you could reduce the example from 150 lines of code to something more like 50 at most Commented Jul 18 at 1:58
  • shorten tsplay.dev/m0kERN, removed third type and valid separated case. Type 'T[Exclude<NumericKeysOnly<T>, undefined>]' is not assignable to type 'ReactNode' matter, its second issue with this - how valid to use my generic data. since keys taken from type itself - its should exist and be number. Commented Jul 18 at 9:16
  • 1
    That shortened link still is >100 lines of code. You can still probably get all that code on one screen if you try to conserve vertical space. But I won't worry too much about minimizing the example further. • A Stack Overflow question should focus on one issue; if you have a second issue it should be removed from here and added to a separate question if you want to ask about it. And the error should be removed as well from here (e.g., use a type assertion as shown here). • Does my suggested approach with the mapped type meet your needs, or is something missing? Commented Jul 18 at 11:08

1 Answer 1

0
function ComposedTestControl<
  T extends readonly TestTabConfig<TestType&TestType2&TestType3>[]

works (but

function ComposedTestControl<
  T extends readonly TestTabConfig<TestType|TestType2|TestType3>[]

doesn't), as it creates a keyof type that contains all the permitted keys, i.e. the union of keys (whereas | creates the intersection of keys).

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.