当我将一个类分配给一个接口时,为什么 TypeScript 不会抱怨,其中该接口是该类的超集。
示例:
interface AI {
hello(msg: string | number): void;
}
class A {
hello(msg: string) {}
}
const a = new A();
const b: AI = new A(); // Why not complain here?
a.hello(1); // Argument of type 'number' is not assignable to parameter of type 'string'.
b.hello(1);
在 TypeScript 中,方法总是被检查为双变,这意味着您可以加宽其参数的类型,这是安全的,或者缩小其参数的类型,这是不安全的,如下所示:
interface Iface {
method(msg: string | number): void; // method syntax
}
const obj: Iface = {
method(msg: string) { msg.toUpperCase() } // okay?!
}
obj.method(1); // runtime error
在此示例中,
Iface
有一个需要接受method()
的string | number
,但是obj
(被注释为Iface
)有一个只接受method()
的string
。 编译器不会对此发出警告,并且您会收到运行时错误。 这似乎正是 TypeScript 应该避免的事情,但是(根据文档)在实践中人们很少用双变方法真正做这样不安全的事情。相反,人们倾向于做这样的事情:
class Base {
constructor(public name: string) { }
compare(other: Base) {
return this.name.localeCompare(other.name)
}
}
class Subclass extends Base {
constructor(name: string, public age: number) { super(name); }
compare(other: Subclass) {
return (this.age - other.age) || this.name.localeCompare(other.name)
}
}
当
Subclass
的 compare()
方法接受任何 Subclass
时,BaseClass
的 compare()
方法仅接受 Base
在技术上是不安全的。 但做这种事情是非常有用和常见的,只要不将Subclass
向上转换为Base
,你就不会直接观察到安全孔。
--strictFunctionTypes
编译器选项(--strict
编译器选项套件的一部分)并重构,以便将任何有问题的方法声明重写为函数- 有价值的属性声明:
interface Iface {
method: (msg: string | number) => void; // function-valued prop syntax
}
const obj: Iface = {
method(msg: string) { msg.toUpperCase() } // error!
//~~~~ <-- Type 'string | number' is not assignable to type 'string'.
}
现在,如果您在实现中不安全地缩小方法参数,您将收到警告。 请注意,您仍然可以通过方法语法“实现”该方法; obj
的
method
属性不是箭头函数,您仍然会得到所需的错误。Playground 代码链接