网站搜索

typescript - 为什么变量是未知的?


请看这个例子。我想知道为什么在函数 test2 中 p 参数是未知的。我原以为 p 会被作为一个数字已知。

interface MyInterface<A,B>{}

class MyClass<A,B> implements MyInterface<A,B> {}

function test1<A,B>(p:MyClass<A,B>, callback:(p:B)=>void){}

function test2<A,B>(p:MyInterface<A,B>, callback:(p:B)=>void){}

const myInstance = new MyClass<string,number>()

test1(myInstance, (p)=>{    
    // Here p is a number
}) 

test2(myInstance, (p)=>{
    // Why is p unknown?
}) 

答案#1

这是因为你的接口是空的;在像 TypeScript 这样的结构类型系统中,空接口会被每个类实现,无论该类实际上拥有什么成员。因此,你的类不仅实现了 MyInterface<A, B>,还实现了 MyInterface<boolean, string> 以及 MyInterface 类型参数的每一种可能赋值,因为它(显而易见地)拥有实现这些类型参数接口所需的所有成员,无论它是否通过 implements 子句显式声明了这一点。

因此,Typescript 无法推断 test2 的 A 和 B 应该是什么类型,因为实际上任何类型都是兼容的;例如,test2<boolean, string>(myInstance, (p) => { /* ... */ }) 可以编译且没有错误,并且 p 的类型是 string。

如果接口有一个成员(并且类实现了它),使得参数化该类的 A 和 B 必须与参数化接口的相同,那么 p 的类型将在两个函数中被正确推断:

interface MyInterface<A,B>{
    foo(x: A, y: B): void;
}

class MyClass<A,B> implements MyInterface<A,B> {
    foo(x: A, y: B): void {}
}

test2(myInstance, (p)=>{
    // p: number
}) 

游乐场链接