为什么TS中允许使用此代码?
interface IFoo {
foo(a: string | number): void
}
class Bar implements IFoo {
foo(a: string) { }
}
我认为编译器应该抛出错误,因为Bar
的参数a: string
比IFoo
的a: string | number
窄/不可替换.
为什么TS中允许使用此代码?
interface IFoo {
foo(a: string | number): void
}
class Bar implements IFoo {
foo(a: string) { }
}
我认为编译器应该抛出错误,因为Bar
的参数a: string
比IFoo
的a: string | number
窄/不可替换.
这是刻意的设计和故意的行为,由于Function Parameter Bivariance.
比较函数参数的类型时,如果源参数之一可分配给目标参数,则分配成功,反之亦然.[.]
https://www.typescriptlang.org/docs/handbook/type-compatibility.html#function-parameter-bivariance
从本质上讲,这意味着函数类型是以两种方式进行判断的.foo
的类实现不仅可以赋值给IFoo
中的声明,如果它的类型大于narrow,而且如果它是wider,也可以赋值给IFoo
中的声明.仅当接口声明和类类型实现都不可相互赋值时,才会发生类型错误.
interface IFoo {
foo(a: string | number): void;
}
class Bar implements IFoo {
foo(a: string) {}
}
class Baz implements IFoo {
foo(a: string | number | boolean) {}
}
class Invalid implements IFoo {
foo(a: string | boolean) {}
//~~~ Property 'foo' in type 'Invalid' is not assignable...
}
您可以通过启用--strictFunctionTypes
来防止这种情况.
然而,还有一件重要的事情需要注意.严格参数类型判断仅在将foo
声明为arrow function(foo: (a: string | number) => void;
)时有效.
在开发此功能的过程中,我们发现了大量本质上不安全的类层次 struct ,包括DOM中的一些.因此,该设置仅适用于使用函数语法编写的函数,而不适用于使用方法语法编写的函数.
https://www.typescriptlang.org/tsconfig/#strictFunctionTypes
现在,您将得到预期的参数类型判断:
interface IFoo {
foo: (a: string | number) => void; // <- !! function syntax
}
class Bar implements IFoo {
foo(a: string) { }
//~~~ Property 'foo' in type 'Bar' is not assignable...
}