TypeScript如何实现类属性要么存在a要么同时存在b和c的约束
TypeScript 实现类互斥属性组合的类型推导方案
TS默认不会推导类构造函数内部的属性赋值逻辑带来的互斥约束,因此需要我们显式声明「存在a就一定不存在b/c,不存在a就一定存在b/c」的规则,以下是两种常用的简洁实现方案:
- 方案1:声明合并+联合类型(改动最小)
直接在类定义前补充实例的联合类型声明,利用TS的声明合并特性,让实例自动获得互斥属性约束,原有业务代码几乎不需要修改:
class SomeClass {} declare function someFunction(b: string, c: string): void // 先声明类的实例类型为互斥的两种组合 type MyClass = | { readonly a: SomeClass; readonly b?: never; readonly c?: never } | { readonly a?: never; readonly b: string; readonly c: string } export class MyClass { readonly a?: SomeClass readonly b?: string readonly c?: string constructor(a: SomeClass) constructor(b: string, c: string) constructor(...args: [SomeClass] | [string, string]) { if(args.length === 1) { this.a = args[0] } else { this.b = args[0] this.c = args[1] } } echo() { if (this.a instanceof SomeClass) { // 此分支下a一定存在 } else { // TS自动识别b、c一定为非空string,无报错 someFunction(this.b, this.c) } } }
- 方案2:自定义类型守卫(复用性更强)
如果你的类有多个方法都需要用到这个属性判断,可以封装一个私有的类型守卫方法,后续所有判断都可以复用,不需要重复写类型判断逻辑:
export class MyClass { readonly a?: SomeClass readonly b?: string readonly c?: string constructor(a: SomeClass) constructor(b: string, c: string) constructor(...args: [SomeClass] | [string, string]) { if(args.length === 1) { this.a = args[0] } else { this.b = args[0] this.c = args[1] } } // 自定义类型守卫,明确互斥规则 private hasA(): this is { readonly a: SomeClass } { return this.a instanceof SomeClass } echo() { if (this.hasA()) { // a存在的分支逻辑 } else { // b、c自动推导为非空string someFunction(this.b, this.c) } } }
临时调试可以用非空断言
someFunction(this.b!, this.c!)快速解决报错,但这种写法会跳过TS校验,后续如果修改构造函数逻辑可能引入隐藏风险,不推荐长期使用。
内容的提问来源于stack exchange,提问作者Get Off My Lawn
相关产品推荐
相关产品推荐

