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

typeof操作符与泛型的异常表现探究

TypeScript中o1与o2类型推导差异的原因

在以下TypeScript代码中,函数fn里的o1和o2都是调用对应类型的函数得到的结果,但类型推导却一个是Returns[T],另一个是FooData | BarData | BazData,具体代码如下:

type MyUnion = 'foo' | 'bar' | 'baz';

type GenericData = { whatever: 'whatever' };
type FooData = { foo: 'foo' };
type BarData = { bar: 'bar' };
type BazData = { baz: 'baz' };

type MyData = {
    foo: FooData;
    bar: BarData;
    baz: BazData;
}

const builders = {
  foo: (_data: GenericData) => ({} as FooData),
  bar: (_data: GenericData) => ({} as BarData),
  baz: (_data: GenericData) => ({} as BazData),
};

type Returns = {
  [Prop in keyof typeof builders]: ReturnType<typeof builders[Prop]>;
};

type Builders = {
  [Prop in MyUnion]: (_data: GenericData) => Returns[Prop];
};

type Builders2 = {
  [Prop in MyUnion]: (typeof builders)[Prop];
};

declare const d: GenericData;

function fn<T extends MyUnion>() {
  const b1 = {} as Builders[T];
  const b2 = {} as Builders2[T];

  const o1 = b1(d);
      // ^? const o1: Returns[T]
  const o2 = b2(d);
      // ^? const o2: FooData | BarData | BazData
}

核心差异:映射类型中类型关联的保持方式

1. Builders的类型定义保留了Prop与返回值的强关联

Builders是一个映射类型,它为MyUnion中的每个Prop显式定义了函数类型:(_data: GenericData) => Returns[Prop]。这里的Returns[Prop]和当前遍历的Prop是直接绑定的——当用泛型T索引Builders[T]时,TypeScript会完整保留这种“T对应的返回值就是Returns[T]”的关联关系。因此调用b1(d)时,返回类型会被推导为和T绑定的Returns[T],不会直接展开成联合类型。

2. Builders2的类型定义丢失了Prop与返回值的关联

Builders2的定义是{ [Prop in MyUnion]: (typeof builders)[Prop] },typeof builders的实际类型是包含三个具体函数的对象:

{
  foo: (_data: GenericData) => FooData;
  bar: (_data: GenericData) => BarData;
  baz: (_data: GenericData) => BazData;
}

当用泛型T索引Builders2[T]时,TypeScript会将其解析为三个函数类型的联合:(typeof builders)['foo'] | (typeof builders)['bar'] | (typeof builders)['baz']。

根据TypeScript的规则,调用函数类型的联合时,返回值会是所有函数返回值的联合类型——因为TypeScript无法确定你调用的是联合中的哪一个具体函数,只能将返回值推导为所有可能的返回值集合,也就是FooData | BarData | BazData。

总结

  • Builders[T]是单一函数类型,返回值与T强绑定,调用后得到Returns[T]。
  • Builders2[T]是多个函数类型的联合,调用联合函数时返回所有可能的返回值联合,因此得到FooData | BarData | BazData。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 08:29:51