如何使用泛型字符串(不是可迭代的东西)在 TypeScript 的对象中定义某个键?

How do I use a string generic (not something iterable) to define a certain key in an object in TypeScript?

我正在尝试创建一种 object/interface 类型,其中某些键名可以通过泛型进行修改。已经有大量关于使用泛型迭代定义键的问题和答案,如 [key: T][Key in T],但我想做的是不同的。

假设我有一个像这样的简单类型:

type Animal = {
    features: {
        hasTail: boolean,
        color: string,
    },
    maxAge: number,
    habitat: string,
};

现在,如果我想根据几个不同的可能选项更改密钥 hasTail 的名称,基于通过传入的 不可迭代字符串类型 一个通用的。理想情况下,我希望能够做这样的事情。 (请原谅我对动物分类的了解不足而做出的荒谬例子)。

type Animal<T extends "laysEggs" | "hasTail"> {
    features: {
        [T]: boolean,
        color: string,
    },
    maxAge: number,
    habitat: string,
}

这样我就可以通过说

来定义相似的类型
type Reptile = Animal<"hasTail">;
type Mammal = Animal<"laysEggs">;

或者我可以通过

确定给定数据是哪种动物
function checkAnimal(a: Animal) {
    if ("hasTail" in a.features) {
        // now I know it's a Mammal
    ...

我试图通过给出这些荒谬的动物示例来简化事情,但我有一个更复杂的用例,通过泛型进行这种修改将大大受益。

然而,据我所知,泛型似乎只用于传递可迭代对象,为给定对象提供键数我希望能够为对象中的特定单个键提供特定名称。有什么想法吗?

那么这对你有用吗?

type Animal<T extends "laysEggs" | "hasTail"> = {
    features: {
        [K in T]: boolean;
    },
    maxAge: number,
    habitat: string,
} & {
  features:{
    color: string;
  }
}