Consider the code snippet below in the playground:
type AvailableTypes = {
'array': Array<any>;
'string': string;
'object': object;
}
class Wrapper<T extends keyof AvailableTypes> {
// Can be of type array, string, or object
private readonly type: T;
// ERROR: Property 'value' has no initializer and is not definitely assigned in the constructor.
private readonly value: AvailableTypes[T];
constructor(type: T) {
this.type = type;
/**
* ERROR:
* TS2322: Type 'never[]' is not assignable to type 'AvailableTypes[T]'.
* Type 'never[]' is not assignable to type 'never'.
*/
switch (type) {
case 'array':
this.value = [];
break;
case 'string':
this.value = '';
break;
case 'object':
this.value = {};
break;
}
}
}
Two significant errors are present:
TS2322: Type 'never[]' is not assignable to type 'AvailableTypes[T]'.
Type 'never[]' is not assignable to type 'never'
Even though AvailableTypes[T]
always corresponds to one of the types defined in AvailableTypes
, with T
being the key.
... and
Property 'value' has no initializer and is not definitely assigned in the constructor.
Despite the requirement for type
to be either a string
, array
, or object.
What could I possibly be overlooking here?
Check out these related SO Threads:
- Typescript Generic Union
- Create union out of interface using tag generic
- TypeScript: use of generic and union types
Update
(update to @jcalz answer)
It should be possible to type-check the value
based on the type
property:
// Inside the Wrapper class, this method should work since `value` can only be an array if the type is 'array':
public pushValue(val: unknown) {
if (this.type === 'array') {
this.value.push(val);
}
}