对于编译器为什么不推断,我没有明确的答案B
。我的直觉是,编译器推断您实际传递给函数的参数的类型要比推断仅与您传入的参数相关的类型要容易得多。基于这种直觉,我会重写要替换的类型B
,Record<K,V>
其中K
是您实际传入的键,并且V
是与该键关联的属性的值的类型。
如果您不知道,Record<K,V>
它是 TypeScript 标准库的一部分,并且定义如下:
type Record<K extends string, T> = {
[P in K]: T;
}
那么函数就变成了:
function foo<A, K extends string, V>(
array: A[],
getter: (ao: A) => Record<K,V>,
key: K, // easier to infer K because you directly pass it in
callback: (value: V) => void
) {
callback(getter(array[0])[key]);
}
这似乎有效:
foo([{ b: { c: 1 } }], a => a.b, "c", v => { });
根据需要推断参数<{ b: { c: number; }; }, "c", number>
。
希望有帮助;祝你好运!
更新
@TitianCernicovaDragomir 指出以下调用:
foo([{ b: { c: 1, d: "" } }], a => a.b, "c", v => { });
被推断为
foo<{ b: { c: number; d: string; }; }, "c" | "d", string | number>(...)
这里的问题是你想要K
只是"c"
,而不是"c" | "d"
,但显然array
参数是在参数之前检查的key
。(我不认为这V
是string | number
实际的问题,因为callback
实际上它会取任何值。如果你传递了一个callback
只取的函数number
并且它失败了,那么这将是一个问题。)
如果您发现某些类型参数的推断顺序错误(意味着编译器使用参数来推断某些内容,但您希望它使用不同的参数),您可以通过将类型与{}
.
在这种情况下,我们可以这样做:
function foo<A, K extends string, V>(
array: A[],
getter: (ao: A) => Record<K & {}, V>, // delay inference of K
key: K,
callback: (value: V) => void
) {
callback(getter(array[0])[key]);
}
现在当我们打电话
foo([{ b: { c: 1, d: "" } }], a => a.b, "c", v => { });
推断为
foo<{ b: { c: number; d: string; }; }, "c", {}>(...)
这工作正常,因为回调不做任何事情。如果我们打电话
foo([{ b: { c: 1, d: "" } }], a => a.b, "c", (v: number): void => { });
然后推断为
foo<{ b: { c: number; d: string; }; }, "c", number>(...)
这很好,对吧?
我们需要支持的任何其他用例?