如何从其他类型参数推断类型参数?

时间:2021-02-06 12:40:31

标签: typescript

我想实现一个可以使用函数取对象值的排序函数,但目前我无法推断取值函数的返回值。

type TKey<TData> = ((data: TData) => any)

interface SortingConfig<
  TData,
  TExtractor extends TKey<TData>,
  TValue =
    TExtractor extends (data: TData) => infer R ? R : never> {
  extractor: TExtractor,
  comparator?: (a: TValue, b: TValue) => number
}

function test1<TData, TExtractor extends TKey<TData>>(
  value: TData,
  conf: SortingConfig<TData, TExtractor>
) {}

test1({
  a: 1,
  b: "string"
}, {
  // extractor type: (data: {a: number, b: string}) => string
  // The type of comparator is wrong, parameter type should be the return type of extractor
  extractor: data => data.b,
  // comparator type: (a: any, b: any) => any
  // expect: (a: string, b: string) => number
  comparator: (a, b) => a
})

/**
 * This works, but unfortunately I need to write it in the above way
 */
function test2<
  TData,
  TExtractor extends TKey<TData>,
  TValue = TExtractor extends (data: TData) => infer R ? R : never
>(
  data: TData, 
  extractor: TExtractor, 
  comparator: (a: TValue, b: TValue) => number
) {}

// Put the comparator and extractor outside the conf object and it works
// extractor type: (data: {a: number, b: string}) => number
// comparator type: (a: number, b: number) => number
test2({a: 1, b: "string"}, data => data.a, (a, b) => a)

Typescript playground

================================================ ======

感谢@jcalz 指出。我牺牲了 extractor 的推断,来推断比较器。

function test1<TData, TValue>(
  value: TData,
  conf: {
    extractor: (data: TData) => TValue,
    comparator: (a: TValue, b: TValue) => number
  }
) {}

test1({
  a: 1,
  b: "string"
}, {
  // Now you have to supply the type for data (and if you forget, any is frustratingly inferred)
  extractor: (data: { a: number, b: string }) => data.b,
  comparator: (a, b) => a.localeCompare(b)
})

0 个答案:

没有答案