Imagine the following code (playground):
type AvailableTypes = {
'array': Array<any>;
'string': string;
'object': object;
}
class Wrapper<T extends keyof AvailableTypes> {
// Is either 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;
}
}
}
There are two major errors:
TS2322: Type 'never[]' is not assignable to type 'AvailableTypes[T]'.
Type 'never[]' is not assignable to type 'never'
Even if AvailableTypes[T] always resolves to a one of the types declared in AvailableTypes, with T being the key of it.
... and
Property 'value' has no initializer and is not definitely assigned in the constructor.
Although type is mandatory and need to be either string, array or object.
What am I missing here?
Possible 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:
// In the Wrapper class, should work since value can only be an array if type is 'array':
public pushValue(val: unknown) {
if (this.type === 'array') {
this.value.push(val);
}
}