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