PAYATHON 2026

TypeScript 多个泛型参数为何不能只指定第一个并自动推断其余参数?

数据阿明

TypeScript 不支持在这种调用中显式指定 T,同时从实参推断未填写的 U。原签名中的两个类型参数都没有默认值,因此 b<User>(...) 会报类型参数数量不足。

分两次调用时,T 和 P 属于不同的函数。外层显式指定 T,内层不填写类型参数,编译器就能从实参推断 P。

extends 为什么没有让 U 自动变成可省略参数?

原签名是:

function b<T, U extends Partial<T>>(u: U) {
  return u;
}

这段代码中:

  • U 是独立的类型参数。
  • U extends Partial<T> 要求 U 可以赋值给 Partial<T>。
  • 类型参数能否省略,取决于调用时的推断规则以及是否声明了默认类型。

extends 声明的是约束,不会为 U 设置默认类型,也不会开启部分类型参数推断。本次调用显式填写了类型参数列表,而 T、U 都是必填项,因此需要同时提供两个类型参数。

假设 User 定义如下:

type User = {
  name: string;
  age: number;
};

同时指定两个类型参数可以满足原签名:

const result = b<User, { name: string }>({ name: 'string' });
// result 的类型为 { name: string }

不过,这样需要重复描述实参类型。

为什么分两次调用可以保留类型推断?

将两个类型参数放在不同的函数签名中,就可以分别显式指定和自动推断:

function b<T>() {
  return function<P extends Partial<T>>(p: P) {
    return p;
  };
}

const result = b<User>()({ name: 'string' });
// result 的类型为 { name: string }

代码分两步进行类型检查:

  1. b<User>() 确定外层的 T,并返回带有 P extends Partial<User> 约束的泛型函数。
  2. 内层函数从实参 { name: 'string' } 推断 P,再检查它是否满足约束。

这里通常推断出的是 { name: string }。使用泛型本身不会自动保留字符串字面量类型 'string'。

如果要多次使用同一种 T,可以保存外层调用的结果:

const userPartial = b<User>();

const named = userPartial({ name: 'Alice' });
// { name: string }

const aged = userPartial({ age: 30 });
// { age: number }

userPartial({ age: '30' });
// 类型错误:string 不能赋值给 number

给 U 设置默认值能否达到同样效果?

设置默认类型可以消除类型参数数量错误:

function b<T, U extends Partial<T> = Partial<T>>(u: U) {
  return u;
}

const result = b<User>({ name: 'string' });
// result 的类型为 Partial<User>

但在这个调用中,显式指定 T 并省略 U 后,U 会使用默认类型 Partial<User>,不会从对象实参推断为 { name: string }。

如果可以接受 Partial<User> 返回类型,可以使用默认值;如果希望返回类型保留实参实际提供的属性,应使用前面的分层调用写法。

只需要检查参数时,可以简化签名

如果不需要保留实参的具体类型,直接使用 Partial<T> 即可:

function b<T>(u: Partial<T>): Partial<T> {
  return u;
}

const result = b<User>({ name: 'string' });
// result 的类型为 Partial<User>

Partial<T> 只把属性变为可选,不会改变属性原有的值类型,也不会进行运行时校验。extends 约束同样不保证对象只能包含 T 中的属性,不应把它当作严格的字段白名单。

备注:内容仅供参考。