TypeScript中this is类型断言方法未按预期工作问题
类内
this is类型断言失效的原因及解决方法 问题根源
类内部的isOk()/isFail()方法的类型守卫未按预期生效,核心原因是父类Result<V,E>的value属性被声明为宽泛的V | E类型,当变量被标注为父类类型时,TypeScript无法通过类方法的this is断言自动将父类属性类型窄化为子类的具体类型:
- 在
Result类中定义isOk(): this is Ok<V>时,这里的Ok<V>基于父类泛型参数V,但父类的value类型是V | E,TypeScript会优先遵循父类的属性类型声明,不会因为断言this是子类就自动覆盖该类型。 - 独立的类型守卫函数
isOk<V,E>(result: Result<V,E>): result is Ok<V>则直接将整个Result<V,E>类型窄化为Ok<V>,此时TypeScript会直接使用子类Ok<V>的value类型(即V),因此能正确推断。
解决方法
方案1:用联合类型实现Result模式(更符合TS类型系统)
放弃类继承,改用 discriminated union(区分联合类型)是更简洁可靠的实现方式:
const OK = 0 as const; const FAIL = 1 as const; type Ok<V> = { _flag: typeof OK; value: V; }; type Fail<E> = { _flag: typeof FAIL; value: E; }; type Result<V, E> = Ok<V> | Fail<E>; // 辅助构造函数 function ok<V>(value: V): Ok<V> { return { _flag: OK, value }; } function fail<E>(value: E): Fail<E> { return { _flag: FAIL, value }; } // 使用示例 function fn(foo: boolean): Result<string, number> { if (foo) return ok("OK"); return fail(1); } const res = fn(true); if (res._flag === OK) { const val = res.value; // 类型自动推断为string }
方案2:调整类的泛型与属性声明(保留类实现)
如果坚持使用类,需要修改父类的属性定义,并让子类继承完整的泛型参数,确保类型守卫能正确关联子类的属性类型:
const OK = 0 as const; const FAIL = 1 as const; export abstract class Result<V, E> { public readonly abstract _flag: typeof OK | typeof FAIL; // 去掉父类的value属性声明,由子类直接实现 public abstract get value(): V | E; public isOk(): this is Ok<V, E> { return this._flag === OK; } public isFail(): this is Fail<V, E> { return this._flag === FAIL; } } export class Ok<V, E> extends Result<V, E> { public readonly _flag = OK; constructor(public readonly value: V) { super(); } } export class Fail<V, E> extends Result<V, E> { public readonly _flag = FAIL; constructor(public readonly value: E) { super(); } } // 使用示例 function fn(foo: boolean): Result<string, number> { if (foo) return new Ok<string, number>("OK"); return new Fail<string, number>(1); } const res = fn(true); if (res.isOk()) { const val = res.value; // 类型自动推断为string }
内容的提问来源于stack exchange,提问作者Cristofer
相关产品推荐
相关产品推荐

