为什么接口中的这​​个箭头函数无法编译?

hos*_*khi 9 oop typescript typescript-typings

箭头函数常规函数在实现接口方面有什么区别,使得代码A导致编译时错误而代码B编译成功。

注意:在tsconfig.json所有严格类型检查选项均已启用的情况下,包括strictFunctionTypes,顺便说一句,它认为通过启用strict所有严格类型检查选项即可启用。

导致编译时错误的代码A

interface SomeInterface {
    someFunction: (par1: string | undefined) => string;
}

class SomeClass implements SomeInterface {
    someFunction(par1: string): string    //invalid function signature
    {
        throw new Error('Method not implemented.');
    }
}
Run Code Online (Sandbox Code Playgroud)

并且,代码B编译成功。

interface SomeInterface {
    someFunction(par1: string | undefined): string;
}

class SomeClass implements SomeInterface {
    someFunction(par1: string): string    //invalid function signature
    {
        throw new Error("Method not implemented.");
    }
}
Run Code Online (Sandbox Code Playgroud)

游乐场链接

jca*_*alz 9

启用后--strictFunctionTypes函数类型的参数将根据维护类型安全的需要进行逆变检查:

class SomeClass implements SomeInterface { // error here
    someFunction(par1: string): string  
    {
        return par1.toUpperCase();
    }
}

const i: SomeInterface = new SomeClass(); // error here
i.someFunction(undefined); // runtime error here, par1 is undefined
Run Code Online (Sandbox Code Playgroud)

但是,正如文档中提到的:

在开发此功能的过程中,我们发现了大量本质上不安全的类层次结构,包括 DOM 中的一些。因此,该设置仅适用于以函数语法编写的函数,不适用于以方法语法编写的函数。


因此,方法类型的参数仍然进行双变检查,即协变和协变,以支持一些常见模式(尽管对于其中一些情况,泛型或多this可能是更好的方法)。一个重要的例子是Array<T>,人们显然喜欢他们的协变数组

interface Animal { species: string }
interface Dog extends Animal { bark(): void };
const scooby: Dog = { species: "dog", bark() { console.log("ROOBY ROO or whatevz") } };
const snoopy: Dog = { species: "dog", bark() { console.log("...") } };
function processAnimals(arr: Animal[]) {
    console.log("I got " + arr.map(x => x.species).join(", ") + ".")
};
const dogs = [scooby, snoopy];
processAnimals(dogs); // okay
Run Code Online (Sandbox Code Playgroud)

这是符合人体工程学且常见的,但从技术上讲,编译器应该拒绝dogs,因为Dog[]这不是有效的Animal[](事实上,像这样的方法push()会做坏事,比如将 a 推CatDog[]引擎盖下)。但如果你沿着这条路走下去,你会发现 TypeScript 到处都是不健全的,即使没有函数参数,因为属性写入也是这样。有关更多详细信息,请参阅此 Q/A


这意味着您不会产生错误,因为使用方法语法:SomeClass2SomeInterface2

class SomeClass2 implements SomeInterface2 { // no error
    someFunction(par1: string): string {
        return par1.toUpperCase();
    }
}
Run Code Online (Sandbox Code Playgroud)

当然,这与之前的稳健性问题完全相同:

const i2: SomeInterface2 = new SomeClass2(); // no error
i2.someFunction(undefined); // runtime error, par1 is undefined
Run Code Online (Sandbox Code Playgroud)

但事实就是这样。为了方便起见,方法在设计上不如函数安全。

Playground 代码链接

  • @Liam 因为 jcalz 用更详细的答案击败了我:),我将在这里链接我关于方差的演讲,也许你会发现它有用 https://www.youtube.com/watch?v=EInunOVRsUU (3认同)