使用带 void 的函数接口时出现意外的打字稿编译器行为

unexpected typescript compiler behavior when using a function interface with void

如果我用 return type as number 定义一个函数接口,编译器会警告我


interface RequestHandler {
    (): number
}

// the compiler will prompt an error
// because " Type '() => boolean' is not assignable to type 'RequestHandler'" 
const handler: RequestHandler = function (): boolean {
    return false
}

但是,如果我这样做,编译器似乎没问题

interface RequestHandler {
    (): void
}

const handler: RequestHandler = function (): boolean {
    return false
}

起初,我的猜测是一个带有 void return 类型的函数将接受任何 return 类型,根据这个是错误的:

// error TS2322: Type 'boolean' is not assignable to type 'void'
function foo(): void {
    return true
}

我猜我的假设不成立,谁能解释这种行为?


编辑 ABOS 的回答启发了我找到更多关于这种行为的信息 我会放一个新的代码片段作为演示

class Animal {
    eat() {}
}

// Dog is a subtype of Animal
class Dog extends Animal {
    bark() {}
}

interface AnimalBuilder {
    (): Animal
}

interface DogBuilder {
    (): Dog
}
// DogBuilder is a subtype of Animal Builder

declare let animalBuilder: AnimalBuilder
declare let dogBuilder: DogBuilder

// this demonstrate "co-variance"
animalBuilder = dogBuilder // Ok
dogBuilder = animalBuilder // Error

interface AnimalFeeder {
    (animal: Animal): void
}

interface DogFeeder {
    (dog: Dog): void
}
// ...while AnimalFeeder is a subtype of DogFeeder (under "strictFunctionTypes")
// this is called "contra-variance"
// Although counter-intuitive at first glance, it ensures stronger type safety 


declare let animalFeeder: AnimalFeeder
declare let dogFeeder: DogFeeder

// "contravariance"
dogFeeder = animalFeeder // Ok
animalFeeder = dogFeeder // Error when "--strictFunctionTypes"
// Ok when "strictFunctionTypes" is set to false, bi-variance

我的理解:有两种不同的类型兼容性检查。

为了

const handler: RequestHandler = function (): boolean {
    return false
}

根据 Comparing two functions,这里发生的是 return 类型 boolean 的函数可分配给 void。请注意本节底部的示例和语句“类型系统强制源函数的 return 类型是目标类型的 return 类型的子类型。”在这种情况下,void 是 boolean 的子类型。

为了

// error TS2322: Type 'boolean' is not assignable to type 'void'
function foo(): void {
    return true
}

这里发生的是数据类型比较,与第一种情况不同。所以它会像预期的那样抱怨不匹配的类型。