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

TypeScript:如何基于同类型中的静态属性值条件定义函数返回类型

实现基于id的条件返回类型检查

当然可以实现你想要的类型检查效果!核心是把Task改成泛型类型,让id的具体值和run的返回类型建立绑定关系,这样TypeScript就能根据id自动推断并校验run的返回值是否符合对应类型。

修改后的类型定义

我们将Task定义为接受一个泛型参数T(约束为Outputs的键),把id的类型指定为T,同时让run的返回类型对应Outputs[T]:

type Outputs = {
  "get-name": { name: string; };
  "get-age": { age: number; };
  "get-favourite-fruits": ("apple" | "strawberry" | "melon")[];
};

// 使用泛型绑定id和run的返回类型
type Task<T extends keyof Outputs = keyof Outputs> = {
  id: T;
  run: () => Outputs[T];
};

验证类型检查效果

现在声明task时,TypeScript会根据id的具体值自动推断泛型参数T,并严格校验run的返回值是否匹配Outputs[T]:

const taskOne: Task = {
  id: "get-name",
  // ✅ 合法:返回值符合Outputs['get-name']
  run: () => {
    return { name: "frankenstein" };
  },
};

const taskTwo: Task = {
  id: "get-age",
  // ✅ 合法:返回值符合Outputs['get-age']
  run: () => {
    return { age: 22 };
  },
};

const taskThree: Task = {
  id: "get-favourite-fruits",
  // ❌ 报错:类型'("apple" | "banana")[]'不可赋值给类型'("apple" | "strawberry" | "melon")[]'
  run: () => {
    return ["apple", "banana"];
  },
};

更简洁的写法:使用辅助函数

如果你不想每次都手动写: Task,可以创建一个辅助函数来自动推断泛型类型,代码会更简洁且类型更可靠:

function createTask<T extends keyof Outputs>(task: Task<T>): Task<T> {
  return task;
}

// 自动推断类型,无需手动指定Task
const taskOne = createTask({
  id: "get-name",
  run: () => ({ name: "frankenstein" }),
});

const taskThree = createTask({
  id: "get-favourite-fruits",
  // ❌ 同样会触发预期的错误
  run: () => ["apple", "banana"],
});

为什么原写法无法生效?

原来的Task类型中,id是keyof Outputs(即所有可能的键的联合类型),而run的返回类型是never。由于never是所有类型的子类型,任何返回值都能被赋值给never,导致TypeScript无法进行有效的类型校验。而泛型的方式将id的具体类型和run的返回类型做了一对一的绑定,让TypeScript能精准判断返回值是否合法。

内容的提问来源于stack exchange,提问作者Jake

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 06:32:32