I have a generic entity type, with the generic used to define a field type based on a set of string literals:
type EntityTypes = 'foo' | 'bar' | 'baz';
type EntityMappings = {
foo: string;
bar: number;
baz: Array<string>;
}
type GenericEntity<T extends EntityTypes> = {
type: T;
fieldProperty: EntityMappings[T];
}
What I'm trying to do is require all instances of GenericEntity to have a single type
field (a string literal) that then defines the type of fieldProperty, e.g:
const instance: GenericEntity<'foo'> = {
type: 'foo',
fieldProperty: 'hello',
};
const otherInstance: GenericEntity<'baz'> = {
type: 'baz',
fieldProperty: ['a', 'b', 'c'],
}
However, because T extends EntityTypes
allows for a union of multiple string literal values in EntityTypes, I'm able to do this, which I want to disallow:
const badInstance: GenericEntity<'foo' | 'baz'> = {
type: 'baz',
fieldProperty: 'blah',
};
This compiles because now type
is of type 'foo' | 'baz'
and fieldProperty is of type string | Array<string>
, but the two fields no longer correspond like I intend them to.
Is there a way to restrict the generic declaration on GenericEntity further, to only allow a single unique string literal value? Barring that, is there some other way to insist that any instance of GenericEntity has a type
field and a fieldProperty
field that correspond?
CodePudding user response:
There is currently no direct way to restrict a generic type parameter to a single member of a union. There's an open feature request at microsoft/TypeScript#27808 to support something like T extends oneof EntityTyes
, but that's not implemented yet. If you want to see it happen you might visit that issue and give it a