根据函数重载签名中的对象值推断键类型

时间:2019-07-13 18:35:28

标签: typescript generics overloading

我有一个用于映射可迭代值的函数,与Array.prototype.map()非常相似,但是由于示例中的这些细节无关紧要,因此本示例将其简化为基本等效:

function select <T, U> (array: T[], selectFn: (value: T, index: number, array: T[]) => U, thisArg?: unknown): U[] {
  return array.map(selectKeyOrFn, thisArg);
}

select(['foo', 'bar'], s => s.length);

到目前为止,太好了。一切都会编译。现在,我想接受一个函数或第二个参数的keyof T。我不确定如何最好地为此过载签名定义类型参数,但这是我失败的方法:

type KeyOfValue<T, U extends T[keyof T]> = U extends T[infer K] ? K : never;

function select <T, U extends T[keyof T]> (array: T[], selectKey: KeyOfValue<T, U>): U[]
function select <T, U> (array: T[], selectFn: (value: T, index: number, array: T[]) => U, thisArg?: unknown): U[]
function select <T, U> (array: T[], selectKeyOrFn: (U extends T[keyof T] ? KeyOfValue<T, U> : never) | ((value: T, index: number, array: T[]) => U), thisArg?: unknown): U[] {
  return typeof selectKeyOrFn === 'function'
    ? array.map(selectKeyOrFn, thisArg)
    : array.map(value => value[selectKeyOrFn]);
}

select(['foo', 'bar'], 'length');
select(['foo', 'bar'], s => s.length);

主要问题似乎是我的KeyOfValue类型不允许我尝试将infer K用作索引T的语法:

  

类型“ K”不能用于索引类型“ T”。

如何成功原型化此重载函数?我不希望求助于KeyOfValue之类的帮助程序类型,但目前我想不出解决办法。

1 个答案:

答案 0 :(得分:1)

我认为您在这里使条件类型变得过于复杂。为键设置类型参数并使用类型查询会更好。同样,对于实现签名,您可以合并两个重载签名,而不必使用相同的book作为返回类型:

U