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);
}
}