My team has created typescript types definitions for an API that we're using, so we aren't able to touch the source code, just the definitions.
We have a function called add
that essentially adds one or more react components to the main program. The props
property of the object should depend on the component type listed on the component
property.
It looks like this:
add(arg1, arg2, {
//some other args
children: [{
id: string1,
//BackButton can be a functional or class-based component
component: BackButton,
//BackButtonProps will be defined within BackButton
props: BackButtonProps
},
{
id: string2,
//SkipButton can be a functional or class-based component
component: SkipButton,
//SkipButtonProps will be defined within SkipButton
props: SkipButtonProps
}
]
});
For reference, there is an alternate (overloaded) version of the function that only adds one component instead of multiple that I've been able to figure out the typescript for. It looks like this:
add<T>(
id: string,
component: ComponentType<T>,
props: T
): void;
My question is this -- since the number of children components is unknown, how can I use a generic on the add
function so that all the children components are correctly typed (the props
and component
properties match up)?
CodePudding user response:
A generic signature of add
would look like this.
declare function add<T extends any[]>(arg1: any, arg2: any, arg3: {
children: [...{ [K in keyof T]: {
id: string,
component: T[K]
props: React.ComponentProps<T[K]>
}}]
}): void
The generic type T
would store a tuple where each element is a react component. For each element with the index K
of the passed array, the component
type would be used as the type in T[K]
and the props
type would have to be React.ComponentProps<T[K]>
.
Let's see this in action:
const BackButton = (props: {a: string}) => {
return <div></div>
}
const SkipButton = (props: {b: string}) => {
return <div></div>
}
add(0, 0, {
children: [
{
id: "1",
component: BackButton,
props: { a: "123" }
},
{
id: "2",
component: SkipButton,
props: { b: "123" }
},
{
id: "3",
component: SkipButton,
props: { a: "123" } // Error: Type '{ a: string; }' is not assignable to type '{ b: string; }'
}
]
})