TypeScript实现Rust Result枚举时,私有成员类型断言报错求解
用TypeScript实现Rust风格Result枚举的类型推断解决方案
我正在用TypeScript类实现Rust的Result枚举简易版本,代码如下:
class Result<T, E> { private value: T | E; private _ok: boolean; private constructor(f: () => T) { try { this.value = f(); this._ok = true; } catch (e) { this.value = e as E; this._ok = false; } } static from<T, E>(f: () => T) { return new Result<T, E>(f); } is_ok(): this['value'] is T { return this._ok; } unwrap(): T { if (this.is_ok()) return this.value as T; throw new Error("some error"); } }
需求是:当is_ok()返回true时,断言value类型为T;返回false时,value类型为E。但直接断言私有成员value的类型会报错,强制类型转换又无法解决外部用户的类型推断问题,需要更优方案。
最优方案:基于子类实现可辨识联合类型
核心思路是将Result设计为抽象基类,通过OkResult和ErrResult两个子类分别承载成功/失败状态,利用TypeScript的类型谓词自动完成类型缩小:
abstract class Result<T, E> { // 类型谓词:断言当前实例为成功状态的子类 is_ok(): this is OkResult<T, E> { return this instanceof OkResult; } // 类型谓词:断言当前实例为失败状态的子类 is_err(): this is ErrResult<T, E> { return this instanceof ErrResult; } unwrap(): T { if (this.is_ok()) { return this.value; // 自动推断为T类型,无需强制转换 } throw new Error(`Unwrap Err failed: ${this.value}`); } unwrap_err(): E { if (this.is_err()) { return this.value; // 自动推断为E类型 } throw new Error(`Unwrap Ok failed: ${this.value}`); } // 静态工厂方法,统一创建Result实例 static from<T, E>(f: () => T): Result<T, E> { try { return new OkResult(f()); } catch (e) { return new ErrResult(e as E); } } } // 成功状态子类,公开value属性 class OkResult<T, E> extends Result<T, E> { constructor(public value: T) { super(); } } // 失败状态子类,公开value属性 class ErrResult<T, E> extends Result<T, E> { constructor(public value: E) { super(); } }
方案优势
- 自动类型推断:外部用户调用
is_ok()/is_err()后,TypeScript会自动缩小实例类型,无需手动类型转换:const res = Result.from<string, Error>(() => { return Math.random() > 0.5 ? "success" : (() => { throw new Error("fail") })(); }); if (res.is_ok()) { // res.value自动推断为string console.log(res.value.toUpperCase()); } else { // res.value自动推断为Error console.log(res.value.message); } - 符合Rust设计思想:通过子类区分状态,和Rust的Result枚举语义一致,API更直观。
- 可扩展性强:后续可以轻松添加
map、map_err等Rust Result的核心方法。
备选方案:不拆分子类的类型断言实现
如果不想拆分子类,可以通过定义接口描述不同状态的Result,结合类型谓词完成类型缩小:
class Result<T, E> { private value: T | E; private readonly _ok: boolean; private constructor(f: () => T) { try { this.value = f(); this._ok = true; } catch (e) { this.value = e as E; this._ok = false; } } static from<T, E>(f: () => T) { return new Result<T, E>(f); } // 定义成功状态的接口类型 is_ok(): this is Result<T, E> & { getValue(): T } { return this._ok; } // 定义失败状态的接口类型 is_err(): this is Result<T, E> & { getValue(): E } { return !this._ok; } // 提供公共方法获取值,避免直接访问私有成员 getValue(): T | E { return this.value; } unwrap(): T { if (this.is_ok()) { return this.getValue(); // 自动推断为T类型 } throw new Error("Cannot unwrap Err result"); } }
这种方案无需拆分子类,但需要额外的getValue方法,类型谓词的写法也更繁琐,适合对类结构有严格要求的场景。
内容的提问来源于stack exchange,提问作者Yakiyo
相关产品推荐
相关产品推荐

