I am trying to create a type of an object/interface in which certain key names can be modified by a generic. There are already tons of questions and answers about using generics to define keys iteratively as with [key: T]
or [Key in T]
, but what I'm trying to do is different.
Let's say I have a simple type like this:
type Animal = {
features: {
hasTail: boolean,
color: string,
},
maxAge: number,
habitat: string,
};
Now what if I wanted to change the name of the key hasTail
based on a few different possible options based on a non-iterable string type passed in through a generic. Ideally, I would like to be able to do something like this. (Forgive my ridiculous examples made from poor knowledge of animal classification).
type Animal<T extends "laysEggs" | "hasTail"> {
features: {
[T]: boolean,
color: string,
},
maxAge: number,
habitat: string,
}
This way I could define similar types by saying
type Reptile = Animal<"hasTail">;
type Mammal = Animal<"laysEggs">;
Or I could determine which type of animal a given piece of data was by going
function checkAnimal(a: Animal) {
if ("hasTail" in a.features) {
// now I know it's a Mammal
...
I'm trying to simplify things by giving these ridiculous animal examples, but I have a much more complicated use case that would benefit greatly for this kind of modification through generics.
However, as far as I can see, generics seem to only be used to pass iterable objects to provide a number of keys for a given object? I want to be able to provide a specific name for a specific single key in an object. Any ideas?
CodePudding user response:
So does this work for you?
type Animal<T extends "laysEggs" | "hasTail"> = {
features: {
[K in T]: boolean;
},
maxAge: number,
habitat: string,
} & {
features:{
color: string;
}
}