为什么 TypeScript 在将类分配给接口时不会抱怨,而该接口接受的参数值多于该类?

问题描述 投票:0回答:1

当我将一个类分配给一个接口时,为什么 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
1个回答
4
投票

在 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 代码链接

© www.soinside.com 2019 - 2024. All rights reserved.