我想实现一个可以使用函数取对象值的排序函数,但目前我无法推断取值函数的返回值。
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)
================================================ ======
感谢@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)
})