Home > OS >  How to pass the correct type via a generic in TypeScript?
How to pass the correct type via a generic in TypeScript?

Time:05-10

Say I have an array of objects and of the keys is called render which can be an optional function that takes a parameter (of which the type is unknown)

const array = [{a: 1}, {b: 2, render: renderFunction}, {c: 3, render: anotherFunction}]

say the 2nd object renderFunction takes a number as a param and anotherFunction takes a string as the param, how do I achieve that with generics?

const array: ArrayType<unknown> = [
  {a: 1},
  {b: 2, render: renderFunction} as MyType<number>,
  {c: 3, render: anotherFunction} as MyType<string>
]

but this doesn't work Type 'unknown' is not assignable to type 'number'

any ideas?

CodePudding user response:

I am assuming you have only one key 'a' other than render in Object.

You can define types like so:

interface ArrayItem {
    a: number;
    render?: (parm: string | number) => void;
}

const func1 = (value: string | number) => { };
const func2 = (value: string | number) => { };

const data: Array<ArrayItem> = [
    { a: 1 },
    { a: 2, render: func1 },
    { a: 3, render: func2 }
];

data[1].render?.("test");
data[2].render?.(23);

And if you want generic function parameter you can put any as parm type. But I would suggest to keep it specific to types you need.

CodePudding user response:

I think that the best would be let TypeScript infer the type, just define ArrayItem as generic:

interface ArrayItem<T> {
    a: number;
    render?: (param: T) => void;
}

Then the parameter may be of any type:

const func1 = (value: string) => { };
const func2 = (value: number) => { };

And we remove the type definition from the assignment, in this way TypeScript will infer it:

const data = [
    { a: 1 } as ArrayItem<never>,
    { a: 2, render: func1 } as ArrayItem<string>,
    { a: 3, render: func2 } as ArrayItem<number>
] as const;

I added as const at the end in this way you'll tell TypeScript that each index of the array has a specific type, in this way the inferred type will be [ArrayItem<never>, ArrayItem<string>, ArrayItem<number>] and not ArrayItem<string>[] | ArrayItem<number>[], which is more desirable.

In the end, you can just use it like:

data[1].render?.("test");
data[2].render?.(23);

And TypeScript will advise you the correct type for each element.

The answer was based on the one provided by @OsamaMalik

  • Related