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

如何在不使用默认类型参数的情况下为函数指定泛型参数与实参

问题描述

我创建了一个包含两个泛型参数和一个函数实参的函数:其中一个泛型参数可由传入的实参推导而来,另一个是可选泛型参数。但遇到了问题:当显式设置第一个泛型参数后,第二个泛型参数不再从传入的实参推导,而是直接使用默认类型(由于可选泛型参数后不能跟必填参数,所以必须设置默认类型)。

示例代码如下:

type Options<
  Lorem extends string|number,
  Ipsum extends string|number
> = {
  lorem?: Lorem
  ipsum?: Ipsum
}

// 预期的函数接口
function someLibrary<
  Modify extends Record<string, unknown> = {},
  Provided extends Options<any, any> = Options<any, any>
>(options: Provided) {
  return new Proxy(options, {}) as Modify & Provided
}

// 场景A:正常工作,自动推导Provided类型
const a = someLibrary({
  lorem: "test",
  ipsum: 123
})

// 场景B:显式指定Modify后,Provided不再从实参推导,而是使用默认类型
const b = someLibrary<{ hi: "there" }>({
  lorem: "test",
  ipsum: 123
})

// 场景C:可行但对用户不友好,需要手动指定Provided类型
const options = {
  lorem: "test",
  ipsum: 123
}
const c = someLibrary<{ hi: "there" }, typeof options>(options)
解答

这是TypeScript的设计限制:当你显式指定部分泛型参数时,TypeScript不会自动推导剩余的泛型参数,而是直接使用它们的默认值(如果已定义)。

以下是几种等效的解决方式:

1. 调换泛型参数顺序+使用占位符(推荐)

把可自动推导的Provided放在泛型参数列表的前面,需要显式指定的Modify放在后面并设置默认值。结合TypeScript 4.7+支持的_占位符,用户可以标记需要自动推导的参数:

type Options<
  Lorem extends string|number,
  Ipsum extends string|number
> = {
  lorem?: Lorem
  ipsum?: Ipsum
}

function someLibrary<
  Provided extends Options<any, any> = Options<any, any>,
  Modify extends Record<string, unknown> = {}
>(options: Provided) {
  return new Proxy(options, {}) as Modify & Provided
}

// 场景B优化:用_让TS自动推导Provided,显式指定Modify
const b = someLibrary<_, { hi: "there" }>({
  lorem: "test",
  ipsum: 123
})

2. 使用函数重载

通过重载定义不同的调用场景,让TS在显式指定部分泛型时仍能推导剩余参数:

type Options<
  Lorem extends string|number,
  Ipsum extends string|number
> = {
  lorem?: Lorem
  ipsum?: Ipsum
}

// 重载1:不指定Modify,自动推导Provided
function someLibrary<Provided extends Options<any, any>>(options: Provided): Provided;
// 重载2:指定Modify,自动推导Provided
function someLibrary<Modify extends Record<string, unknown>, Provided extends Options<any, any>>(options: Provided): Modify & Provided;

// 函数实现
function someLibrary(options: any) {
  return new Proxy(options, {})
}

// 调用场景B:自动推导Provided,同时指定Modify
const b = someLibrary<{ hi: "there" }>({
  lorem: "test",
  ipsum: 123
})

3. 类型断言(不推荐)

让用户对返回值手动做类型断言,这种方式不够直观,仅作为临时替代方案:

const b = someLibrary({
  lorem: "test",
  ipsum: 123
}) as { hi: "there" } & { lorem: string; ipsum: number }

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 21:26:28