typescript - 根据 typescript 中的通用属性选择类型

标签 typescript

如何根据泛型属性选择类型?

enum AnimalType {
  DOG,
  CAT,
  FROG,
  SNAKE,
}

const dog = {
  type: AnimalType.DOG, // type property exists for all animals. other properties are vary for different animals
  legs: 4,
}

const cat = {
  type: AnimalType.CAT,
  tail: 1,
}

const frog = {
  type: AnimalType.FROG,
  canSwim: true,
  tail: 0,
}

const snake = {
  type: AnimalType.SNAKE,
  tail: 'looong',
  age: 2,
}

type Animal<AnimalType> = typeof dog | typeof cat | typeof frog | typeof snake // how to rewrite this type definition?

如何根据AnimalType推断类型?例如Animal<AnimalType.DOG>应等于 typeof dog

可以使用条件类型:

type Animal<T extends AnimalType> = T extends AnimalType.DOG ? typeof dog : T extends AnimalType.CAT ? typeof cat : T extends AnimalType.FROG ? typeof frog : T extends AnimalType.SNAKE ? typeof snake : unknown

但是它看起来太长并且完全无法阅读。希望有更好的解决办法

最佳答案

你可能打算这样做

const dog = {
  type: AnimalType.DOG,
  legs: 4,
}

类型为 {type: AnimalType.DOG, legs: number} 。但 TypeScript 推断出 AnimalType.DOG 的类型变得更宽enum类型AnimalType而不是 literal type AnimalType.DOG .

这意味着有人可以写 dog.type = AnimalType.CAT ,这不好。这也意味着typeof dog没有可用于计算的信息 Animal<T> .

要解决此问题,您需要告诉编译器 type应该给出更具体的文字类型。通常的方法是使用 const assertion关于有问题的字面意思。您可以对完整对象文字 {type: AnimalType.DOG, legs: 4} as const 执行此操作,如果您希望编译器强制执行 dog.legs总是恰好 4 。但至少我们应该为 type 做到这一点属性(property)。产生这个:

const dog = { type: AnimalType.DOG as const, legs: 4 };
const cat = { type: AnimalType.CAT as const, tail: 1 };
const frog = { type: AnimalType.FROG as const, canSwim: true, tail: 0 };
const snake = { type: AnimalType.SNAKE as const, tail: 'looong', age: 2 };

现在是union type typeof dog | typeof cat | typeof frog | typeof snake看起来像:

type SomeAnimal = typeof dog | typeof cat | typeof frog | typeof snake;
/* type SomeAnimal = {
    type: AnimalType.DOG;
    legs: number;
} | {
    type: AnimalType.CAT;
    tail: number;
} | {
    type: AnimalType.FROG;
    canSwim: boolean;
    tail: number;
} | {
    type: AnimalType.SNAKE;
    tail: string;
    age: number;
} */

这让我们可以实现 Animal通过联合过滤 Extract utility type :

type Animal<T extends AnimalType> =
  Extract<SomeAnimal, { type: T }>;

让我们测试一下:

type Dog = Animal<AnimalType.DOG>;
/* type Dog = {
    type: AnimalType.DOG;
    legs: number;
} */

看起来不错。

Playground link to code

关于typescript - 根据 typescript 中的通用属性选择类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/77727851/

相关文章:

function - Angular 2 : TypeError 'this.' is undefined

typescript - 如何将两个 typescript 泛型绑定(bind)在一起

javascript - ionic 3 选项卡中的 subview 在查看子组件时显示两个标题

javascript - 图像裁剪和调整大小

javascript - 如何在 Typescript 中序列化/反序列化复杂对象,例如反序列化对象与序列化对象的类型相同

AngularJS 打印部分页面和数据绑定(bind)

reactjs - 属性 '[Symbol.observable]' 在类型 'Store<ApplicationState>' 中缺失,但在类型 'Store<any, AnyAction>' 中需要。 TS2741

typescript - 泛型参数内的赋值 <T, Keys extends keyof T = keyof T>

typescript - 错误TS5056 : Cannot write file because it would be would be overwritten

javascript - 如何在表单验证时在 Angular 模板中显示 <span> 元素?