首页 > 解决方案 > 构造函数接口:没有匹配构造函数的类仍然是可赋值的

问题描述

想象一下,我们有一个接口,它定义了构造函数应该接受哪些参数:

interface Ctr {
    new (num: number): any;
}

然后我们有一个带有默认构造函数的类:

class DefCtr {
}

然后,出于某种原因,我可以将DefCtrclass 分配给 type 的变量Ctr

const Instance: Ctr = DefCtr;

const i = new Instance(1);
console.log(i);

// The output is:
// DefCtr {}

所以Instance是一个DefCtr类(它没有构造函数接受数字)。但是界面迫使我在创建它的实例时传递一个数字(将被忽略)。

有趣的是,这仅在类具有默认构造函数时才有效。例如,这不起作用:

interface Ctr {
    new (num: number): any;
}

class NotDefCtr {
    // Lets create a non-default constructor
    constructor(str: string) {
    }
}

const Instance: Ctr = NotDefCtr; // Error:

// Type 'typeof NotDefCtr' is not assignable to type 'Ctr'.
// Types of parameters 'str' and 'num' are incompatible.
// Type 'number' is not assignable to type 'string'.

错误是有道理的。但从我的角度来看,尝试使用默认构造函数分配一个类时收到错误也是有意义的(因为它没有任何其他构造函数匹配接口)。

标签: typescript

解决方案


TypeScript FAQ 有一个条目:为什么参数较少的函数可以分配给参数较多的函数?. 除了使用 newable 而不是 callable 之外,这是同样的问题。我将把该条目翻译成这种情况:

这是预期和期望的行为。有一个可替代性原则说,如果一个对象X可以用来代替某个对象Y,那么X它就是 的子类型可分配Y

在这种情况下,DefCtr是 的子类型,Ctr因为DefCtr的构造函数可以安全地忽略额外number参数。ButNotDefCtr不是子类型,Ctr因为NotDefCtr的类型表明它需要一个类型的参数string;anumber不能安全地用作 a string,因此它不兼容。

(旁白:事实证明NotDefCtr' 的构造函数实际上忽略了它的输入,所以在运行时不会发生爆炸。但是类型系统并不关心构造函数的特定实现;它看到一个合同的签名说NotDefCtr' 的构造函数是在它的权利范围内期望一个类型的参数string。所以用 替换 a 仍然是一个错误CtrNotDefCtr

好的,希望有帮助;祝你好运!


推荐阅读