如何在不使用默认类型参数的情况下为函数指定泛型参数与实参
问题描述
我创建了一个包含两个泛型参数和一个函数实参的函数:其中一个泛型参数可由传入的实参推导而来,另一个是可选泛型参数。但遇到了问题:当显式设置第一个泛型参数后,第二个泛型参数不再从传入的实参推导,而是直接使用默认类型(由于可选泛型参数后不能跟必填参数,所以必须设置默认类型)。
示例代码如下:
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
相关产品推荐
相关产品推荐

