Typescript 根据类的属性,类的泛型类型参数推断失败
我有一个相当简单的例子,Typescript不推断类型。我想知道为什么Typescript会这样 类型脚本类型推断失败的情况 如果您有以下类声明:Typescript 根据类的属性,类的泛型类型参数推断失败,typescript,Typescript,我有一个相当简单的例子,Typescript不推断类型。我想知道为什么Typescript会这样 类型脚本类型推断失败的情况 如果您有以下类声明: 声明类 { grunt():void } 声明抽象类部分{} 声明类Hoof扩展部分{} 以及以下功能: 声明函数getOwner(part:part):T; 然后,以下代码在Typescript编译器中失败: getOwner(newhoof()) .grunt(); 这是因为Typescript推断getOwner的返回类型为未知,而不是猪
声明类
{
grunt():void
}
声明抽象类部分{}
声明类Hoof扩展部分{}
以及以下功能:
声明函数getOwner(part:part):T;
然后,以下代码在Typescript编译器中失败:
getOwner(newhoof())
.grunt();
这是因为Typescript推断getOwner的返回类型为未知
,而不是猪
奇怪但有效的解决方案
但是,如果我只是在部分的声明中添加一个属性animal:T
,代码将开始工作
换句话说,如果部分的声明变成:
声明抽象类部分
{
动物:T
}
Typescript将能够推断getOwner(newhoof())
的返回类型。我已经验证了Typescript 3.9.7和4.1.3的这种行为
问题:
为什么Typescript的行为是这样的?它是否应该保留泛型类型信息,即使T
没有出现在任何类成员的签名中?请参阅以获取规范答案
TypeScript的类型系统主要是结构化的,而不是名义上的。这意味着,如果比较类型A
和B
,当且仅当它们具有相同的结构(例如,两者都是具有相同键和相同值类型的成员的对象类型)时,才认为它们是相同的类型。命名什么类型的A
和B
(例如,我使用像“A
”和“B
”这样的名称是不相关的)或者它们被声明在哪里(例如,拥有像接口A{A:string}
和接口B{A:string}
这样的单独声明不会使它们成为单独的类型)
特别是,鉴于《宣言》
declare abstract class Part<T> { }
但以下任何一项都不会产生任何编译器错误:
var okay: Part<Swine>;
var okay: {}; // no error
var okay: Part<string>; // no error
var okay: Part<unknown>; // no error
声明抽象类部分{}
的翻译就是(T:string)=>“{}”
)。由于part(“猪”)
产生与part(“string”}
或其他任何东西相同的输出,即字符串“{}”
,因此无法编写反向函数getOwnerType()
函数的输出实际上取决于其输入,因此情况变得更加合理:
function part(T: string): string {
return "{animal: " + T + "}";
}
const hoof = part("Swine");
function getOwnerType(partT: string): string {
return (partT.match(/^{animal: (.*)}$/) ?? ["", "unknown"])[1];
}
console.log(getOwnerType(hoof)); // Swine
function part(T: string): string {
return "{}";
}
const hoof = part("Swine");
function getOwnerType(partT: string): string {
// how would you implement this ???
return "unknown";
}
console.log(getOwnerType(hoof)); // unknown
function part(T: string): string {
return "{animal: " + T + "}";
}
const hoof = part("Swine");
function getOwnerType(partT: string): string {
return (partT.match(/^{animal: (.*)}$/) ?? ["", "unknown"])[1];
}
console.log(getOwnerType(hoof)); // Swine