TypeScript如何基于类实例的animalType值实现config属性的类型守卫
解决方案
要实现类实例的属性关联类型收窄,核心是把animalType和config的类型做绑定,打破原来两个独立联合类型的无关联状态,有两种常用实现方式:
方式1:复用现有可辨识联合类型(和你之前对象实现逻辑完全对齐)
直接复用你已经定义好的Smth联合类型,通过构造函数重载+类型断言,让类的实例完全符合可辨识联合的规则:
enum Animal { BIRD = 'bird', DOG = 'dog', } type Base = { id: number } type Smth = Base & ( | { animalType: Animal.BIRD; config: number; } | { animalType: Animal.DOG; config: string; } ); // 内部实现类 class _MyClass { id: number; animalType: Animal; config: number | string; // 构造函数重载,保证初始化时类型就合法 constructor(id: number, animalType: Animal.BIRD, config: number); constructor(id: number, animalType: Animal.DOG, config: string); constructor(id: number, animalType: Animal, config: number | string) { this.id = id; this.animalType = animalType; this.config = config; } } // 导出的类类型对齐Smth联合类型 type MyClass = Smth; const MyClass = _MyClass as { new (id: number, animalType: Animal.BIRD, config: number): MyClass; new (id: number, animalType: Animal.DOG, config: string): MyClass; };
使用效果:
const smthClass = new MyClass(1, Animal.BIRD, 1); if (smthClass.animalType === Animal.BIRD) { smthClass.config = 1; smthClass.config = 'x'; // 触发类型错误,符合预期 }
方式2:泛型条件类型实现(写法更简洁)
通过泛型参数绑定两个属性的类型关系,无需额外定义联合类型:
enum Animal { BIRD = 'bird', DOG = 'dog', } class MyClass<T extends Animal> { id: number; animalType: T; // 用条件类型把config类型和animalType做绑定 config: T extends Animal.BIRD ? number : string; constructor(id: number, animalType: T, config: T extends Animal.BIRD ? number : string) { this.id = id; this.animalType = animalType; this.config = config; } }
使用效果和方式1完全一致:
const smthClass = new MyClass(1, Animal.BIRD, 1); if (smthClass.animalType === Animal.BIRD) { smthClass.config = 1; smthClass.config = 'x'; // 触发类型错误 }
内容的提问来源于stack exchange,提问作者ZiiMakc
相关产品推荐
相关产品推荐

