TypeScript中为Result类型的Ok函数实现带类型检查的可选参数
在TypeScript中实现带参数条件可选的Rust风格Result类型
我在TypeScript里模仿Rust的Result<T,E>类型,代码如下:
type Result<T, E> = | { ok: true; data: T } | { ok: false; error: E }; const Ok = <T>(data: T): Result<T, never> => { return { ok: true, data }; }; const Err = <E>(error: E): Result<never, E> => { return { ok: false, error }; };
现在想优化Ok()函数:当T是undefined时允许无参调用,但T为其他类型时必须强制传参。直接把参数设为data?: T的话,虽然能满足Result<undefined, Error>场景的无参调用:
function testFunc(isOk: boolean): Result<undefined, Error> { if (isOk) { return Ok(); // 这里希望合法 } return Err(new Error("my error")); }
但会导致T为其他类型时,无参调用Ok()也不会报错,这是我要避免的:
function testFunc(isOk: boolean): Result<number, Error> { if (isOk) { return Ok('hi'); // 这里会报错(string不能赋值给number),符合预期 return Ok(); // 这里不会报错,但需要触发错误 } return Err(new Error("my error")); }
请问仅通过Ok和Err这两个函数,能不能实现这个需求?
可以实现,通过重载Ok函数来区分T为undefined和其他类型的情况:
type Result<T, E> = | { ok: true; data: T } | { ok: false; error: E }; // 重载1:当T为undefined时,允许无参调用 function Ok(): Result<undefined, never>; // 重载2:当T为非undefined类型时,必须传参 function Ok<T>(data: Exclude<T, undefined>): Result<T, never>; // 实现函数 function Ok<T>(data?: T): Result<T | undefined, never> { return { ok: true, data: data as T }; } const Err = <E>(error: E): Result<never, E> => { return { ok: false, error }; };
验证场景:
- T为undefined时,无参调用合法:
function testUndefined(isOk: boolean): Result<undefined, Error> { if (isOk) { return Ok(); // ✅ 无报错,符合预期 } return Err(new Error("error")); }
- T为number时,无参调用会报错:
function testNumber(isOk: boolean): Result<number, Error> { if (isOk) { return Ok(); // ❌ 报错:缺少参数,符合预期 return Ok(123); // ✅ 正常传参,无报错 } return Err(new Error("error")); }
- 传入类型不匹配时依然报错:
function testMismatch(isOk: boolean): Result<number, Error> { if (isOk) { return Ok('hi'); // ❌ 报错:类型"string"的参数不能赋给类型"number"的参数,符合预期 } return Err(new Error("error")); }
原理说明:
- 通过函数重载,我们给
Ok定义了两个不同的调用签名:- 第一个签名不需要参数,返回
Result<undefined, never>,对应T为undefined的场景; - 第二个签名要求必须传入
Exclude<T, undefined>类型的参数(即排除undefined的T),确保非undefined的T必须传参。
- 第一个签名不需要参数,返回
- 实现函数里用可选参数兼容两种情况,但重载签名会在类型检查阶段约束调用方式,达到我们要的效果。
内容的提问来源于stack exchange,提问作者Slava.In
相关产品推荐
相关产品推荐

