You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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 };
};

验证场景:

  1. T为undefined时,无参调用合法:
function testUndefined(isOk: boolean): Result<undefined, Error> {
  if (isOk) {
    return Ok(); // ✅ 无报错,符合预期
  }
  return Err(new Error("error"));
}
  1. T为number时,无参调用会报错:
function testNumber(isOk: boolean): Result<number, Error> {
  if (isOk) {
    return Ok(); // ❌ 报错:缺少参数,符合预期
    return Ok(123); // ✅ 正常传参,无报错
  }
  return Err(new Error("error"));
}
  1. 传入类型不匹配时依然报错:
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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 12:05:28