TypeScript:无需第二个泛型,能否获取数组参数的具体键联合类型?
问题描述
我想要创建一个泛型函数,该函数使用泛型类型描述对象,并接受该泛型类型的键组成的数组。函数返回另一个函数,后者接受该泛型类型的对象,并返回仅包含传入工厂函数的键的切片。
原始函数示例:
function createSlicer<T extends object>(keys: Array<keyof T>) { return (obj: T) => keys.reduce((acc, key) => ({ ...acc, [key]: obj[key] }), {}); }
期望调用方式:
interface Person { name: string; age: number; gender: string; } // 期望类型:(obj: Person) => Pick<Person, 'name'> const nameSlicer = createSlicer<Person>(['name']); // 期望类型:(obj: Person) => Pick<Person, 'age'> const ageSlicer = createSlicer<Person>(['age']); // 期望类型:(obj: Person) => Pick<Person, 'name' | 'gender'> const nameAndGenderSlicer = createSlicer<Person>(['name', 'gender']);
如果使用第二个泛型K来约束键的类型,可以定义正确的返回类型,但这样调用时要么不指定泛型,要么必须同时指定T和K,无法实现上述仅指定T的调用方式:
function createSlicer<T extends object, K extends keyof T>(keys: K[]): (obj: T) => Pick<T, K> { return (obj: T) => keys.reduce((acc, key) => ({ ...acc, [key]: obj[key] }), {}); }
请问是否可以在不使用第二个泛型类型的情况下,获取传入keys的联合类型,从而为createSlicer定义正确的返回类型?
解决方案
无法完全避免使用第二个泛型参数来精确捕获keys的具体联合类型(因为TypeScript需要一个泛型来保存这个具体的键集合,而非宽泛的keyof T),但可以通过语法技巧实现**仅显式指定T,让编译器自动推断K**的调用体验,以下是两种可行方案:
方案一:使用柯里化(Curried)函数拆分泛型参数
将createSlicer拆分为两层函数:第一层接受显式指定的T,返回的第二层函数自动从传入的keys推断K的类型:
function createSlicer<T extends object>() { return <K extends keyof T>(keys: K[]) => { return (obj: T): Pick<T, K> => { // 断言返回类型为Pick<T, K>,避免TS推断为{} return keys.reduce((acc, key) => ({ ...acc, [key]: obj[key] }), {} as Pick<T, K>); }; }; }
调用方式(仅需指定T):
interface Person { name: string; age: number; gender: string; } const nameSlicer = createSlicer<Person>()(['name']); const ageSlicer = createSlicer<Person>()(['age']); const nameAndGenderSlicer = createSlicer<Person>()(['name', 'gender']);
方案二:使用TypeScript 4.7+的部分类型参数推断
如果你的项目使用TypeScript 4.7或更高版本,可以使用通配符_让编译器自动推断K,仅显式指定T:
function createSlicer<T extends object, K extends keyof T>(keys: K[]): (obj: T) => Pick<T, K> { return (obj: T) => keys.reduce((acc, key) => ({ ...acc, [key]: obj[key] }), {} as Pick<T, K>); }
调用方式:
const nameSlicer = createSlicer<Person, _>(['name']);
内容的提问来源于stack exchange,提问作者returnFalse
相关产品推荐
相关产品推荐

