How can I make an array of subtypes, if the base class has a Generic parameter?
The following code illustrates what I'm trying to archive:
Full code:
type Type <T> = {
new(...args: any[]): T
}
type Data = {
[value: string]: any;
}
type Component<T extends Data> = {
data: T;
}
component 1
type MyComponentData = {
id: number;
}
class MyComponent implements Component<MyComponentData> {
data = {
id: 0
}
}
component 2
type MyComponent2Data = {
resource: string;
}
class MyComponent2 implements Component<MyComponent2Data> {
data = {
resource: ''
}
}
Attempt 1: id should be actually a number, but type is not checked
type ComponentRegistry = {
label: string,
component: Type<Component<Data>>,
defaultData: () => Data
}
const components: ComponentRegistry[] = [
{
label: 'Example 1',
component: MyComponent,
defaultData: () => (
{
id: '123'
}
)
},
{
label: 'Example 2',
component: MyComponent2,
defaultData: () => (
{id: '123'}
)
}
]
Attempt 2: id should be actually a number, but type is not checked
type ComponentRegistry2<T> = {
label: string,
component: Type<Component<T>>,
defaultData: () => T
}
const components2: ComponentRegistry2<Data>[] = [
{
label: 'Example 1',
component: MyComponent,
defaultData: () => (
{
id: '123'
}
)
},
{
label: 'Example 2',
component: MyComponent2,
defaultData: () => (
{id: '123'}
)
}
]
Attempt 3
line 11: '{ id: number; }' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'Data'
type extractGeneric<Type> = Type extends Component<infer X> ? X : never
type ComponentRegistry3 = {
label: string,
component<T extends Data>() : Type<Component<T>>,
defaultData: () => extractGeneric<extractGeneric<ReturnType<ComponentRegistry3['component']>>>
}
const components3: ComponentRegistry3[] = [
{
label: 'Example 1',
component: () => MyComponent,
defaultData: () => (
{
id: '123' // Type 'string' is not assignable to type 'never'.
}
)
}
]