问题描述
以下代码显然输入有误,但是我无法在其上输入TypeScript错误。我启用了strict
以及strictNullChecks
和strictFunctionTypes
都是不错的选择,但是TS始终坚信此代码既精巧又精巧。
abstract class A {
// You can pass an undefined to any A
public abstract foo(_x: number | undefined);
}
class B extends A {
// B is an A,but it prohibits passing in an undefined.
// Note that if we did `x: string`,TS would flag it as
// an error.
public foo(x: number) {
if (x === undefined) {
throw new Error("Type error!");
}
}
}
function makeAnA(): A {
// This typechecks correct,so B is clearly an A,in
// TS's opinion.
return new B();
}
function test() {
const b = makeAnA();
// b is a B,so this should not be possible
b.foo(undefined);
}
这是预期的行为吗?我可以打开一些选项来将其标记为错误吗?我已经不止一次地咬过我。
解决方法
这是设计决定。所有方法参数的行为都是双变量的。这意味着就ts而言,对于方法(_x: number) => void
是(_x: number | number) => void
的子类型(反之亦然)。这显然是不合理的。
最初,不仅方法参数是双变量的,而且所有函数签名参数也是。为了解决这个问题,在打字稿2.6中添加了strictFuctionTypes
标志。来自PR:
在此PR中,我们引入了--strictFunctionTypes模式,在该模式下,函数类型参数位置被反向检查而不是被双变量检查。更严格的检查适用于所有函数类型,但源于方法或构造函数声明的函数类型除外。 方法专门排除在外,以确保通用类和接口(例如Array)继续保持大多数协变关系。严格检查方法的影响将是一个重大突破,因为大量的泛型类型将变为不变(即使如此,我们可能会继续探索这种更严格的模式)。
(已突出显示)
因此,在这里,我们可以一目了然地决定让方法参数继续保持双变量相关。为了方便。如果没有这种不健全,大多数类将是不变的。例如,如果Array
是不变的,则Array<Dog>
不会是Array<Animal>
的子类型,从而在非常基本的代码中创建各种痛苦点。
虽然绝对不相等,但是如果我们使用函数字段而不是方法(打开strictFunctionTypes
),则会收到Type '(x: number) => void' is not assignable to type '(_x: number | undefined) => void'
abstract class A {
// You can pass an undefined to any A
public foo!: (_x: number | undefined) => void;
}
class B extends A {
// Error here
public foo: (x: number) => void = x => {
if (x === undefined) {
throw new Error("Type error!");
}
}
}
function makeAnA(): A {
//And here
return new B();
}
function test() {
const b = makeAnA();
// b is a B,so this should not be possible
b.foo(undefined);
}
注意:上面的代码仅对strictFunctionTypes
给出错误,因为没有它,所有函数参数都将继续保持双变量状态。