考虑以下代码:
function ensure<TModel, TValue>(accessor: { (obj: TModel): TValue; }) {
}
interface Person {
firstName: string;
lastName: string;
}
ensure((p: Person) => p.firstName); // <-- this works
ensure<Person>(p => p.firstName); // <-- this does not work
Run Code Online (Sandbox Code Playgroud)
为什么最后一行是语法错误?
提供的参数与调用目标的任何签名都不匹配。
为什么 p 被推断为类型any而不是Person?
这是TypeScript 游乐场中代码的链接。
(另一个编辑:部分类型参数推断被废弃/延迟,并且从未进入 TS3.1 或任何版本,直到并包括 TS3.7。哦,好吧)
编辑:TypeScript 3.1 即将推出的功能将允许部分类型参数推断(使您引用的示例工作),有关更多详细信息,请参阅拉取请求。
原始答案(适用于 TypeScript < 3.1):
第一个示例起作用的原因是编译器从传入的匿名 lambda 函数的类型推断出这两个泛型。
不幸的是,在 TypeScript 中使用泛型函数时,要么全有要么全无——你必须提供:
请注意,如果无法推断出类型,则默认情况下假定其类型为: Object,例如:
function example<T>(a: any): T {
return a as T;
}
let test = example(123);
Run Code Online (Sandbox Code Playgroud)
变量test在上面的例子中,将类型{}。
指定泛型类型或在方法中指定参数类型都是处理此问题的正确方法:
ensure<Person, string>(p => p.firstName);
ensure((p: string) => p.firstName);
Run Code Online (Sandbox Code Playgroud)
您引用的错误是正确的,因为:对于 function 不存在只接受一个泛型的签名ensure。
这样做的原因是您可以拥有带有替代签名的函数,这些签名采用不同数量的泛型类型参数:
interface Example {
ensure<TModel, TValue>(accessor: { (obj: TModel): TValue; }): TValue;
ensure<TModel>(accessor: { (obj: TModel): any; }): any;
}
interface Person {
firstName: string;
lastName: string;
}
let test: Example;
// the method 'ensure' has now 2 overloads:
// one that takes in two generics:
test.ensure<Person, string>((p: Person) => p.firstName);
// one that takes only one generic:
test.ensure<Person>(p => p.firstName);
// when not specified, TypeScript tries to infer which one to use,
// and ends up using the first one:
test.ensure((p: Person) => p.firstName);
Run Code Online (Sandbox Code Playgroud)
游乐场如上。
如果 TypeScript 没有强制执行签名匹配,它就不知道应该选择哪个签名。
现在回答你问题的另一部分:为什么在没有明确说明泛型的情况下调用函数时p假设为any:
一个原因是编译器不能对其可能的类型做出任何假设,TModel不受约束并且可以是任何字面意思,因此类型p是any。
您可以将通用方法限制为一个接口,如下所示:
ensure<TModel extends Person, TValue>(accessor: { (obj: TModel): TValue; });
Run Code Online (Sandbox Code Playgroud)
现在,如果您在不指定参数类型或泛型类型的情况下调用该函数,它将被正确推断为Person:
ensure(p => p.firstName); // p is now Person
Run Code Online (Sandbox Code Playgroud)
希望这完全回答了您的问题。
| 归档时间: |
|
| 查看次数: |
9180 次 |
| 最近记录: |