Typescript 具有构造签名而不是类型检查的接口

Typescript 具有构造签名而不是类型检查的接口,typescript,Typescript,我一直在玩TypeScript中带有构造签名的接口,当以下类型检查失败时,我感到有点困惑: class Foo { constructor () { } } interface Bar { new(): Bar; } function Baz(C : Bar) { return new C() } var o = Baz(Foo); 类型错误为: 提供的参数与调用目标的任何签名不匹配: “new()=>Foo”和“Bar”类型的构造签名是 不兼容:类型“B

我一直在玩TypeScript中带有构造签名的接口,当以下类型检查失败时,我感到有点困惑:

class Foo {
    constructor () {
    }
}

interface Bar {
    new(): Bar;
}

function Baz(C : Bar) {
    return new C()
}

var o = Baz(Foo);
类型错误为:

提供的参数与调用目标的任何签名不匹配: “new()=>Foo”和“Bar”类型的构造签名是 不兼容:类型“Bar”需要构造签名,但类型 “Foo”缺少一个(C:Bar)=>Bar

Foo的构造函数的类型是()=>Foo,这就是我认为Bar所说的。我在这里遗漏了什么吗?

问题(至少从TypeScript编译器的角度来看)是
Bar
新方法的签名。如果将
条的定义替换为以下内容

interface Bar {
  new (): any;
}

它起作用了。您最好使用
new():Foo
,只使用
Bar
,因为返回值不起作用。

这里是代码的更新版本,但有一些细微的变化

我们使用我们希望出现的任何函数和变量定义
Bar
接口

接下来,我们使用
NewableBar
接口扩展
Bar
接口。这只是定义了一个返回
条的构造函数

因为
Foo
实现了
Bar
并且有一个构造函数,
Baz
需要一个
NewableBar
,所以所有内容都会被检查

这比
任何
都要详细一点,但可以提供所需的检查

interface Bar {

}

interface NewableBar extends Bar {
    new();
}

class Foo implements Bar {
    constructor () {

    }
}

function Baz(C : NewableBar) {
    return new C()
}

var o = Baz(Foo);

我想我知道你在做什么,我想你需要一个微妙的不同方法

本例说明如下:

  • Baz必须传递一个可更新的项
  • Baz将返回一个条
  • 并不是所有的酒吧都需要更新,只有那些被传给Baz的
以下是一个例子:

interface Bar {
    sayHello(name: string): void;
}

interface Newable {
    new();
}

class Foo implements Bar {
    constructor () {

    }

    sayHello(name: string) {
        window.alert('Hello ' + name);
    }
}

function Baz(C : Newable) {
    return <Bar> new C()
}

var o = Baz(Foo);
o.sayHello('Bob');
接口栏{
sayHello(名称:string):void;
}
接口可更新{
新的();
}
类Foo实现了Bar{
构造函数(){
}
sayHello(名称:string){
window.alert('Hello'+name);
}
}
函数Baz(C:可更新){
返回新的C()
}
var o=Baz(Foo);
o、 说你好(“鲍勃”);

这种方法的唯一危险是,您可能会将一些非Bar的newable传递给Baz函数。当您通过参数创建对象来使用动态功能时,这在很大程度上是不可避免的,除非您愿意传入一个预初始化的对象,在这种情况下,Baz很乐意接受一个条,而不是一个新的。

我知道这是一个老问题,但我今天需要类似的东西,因此遇到了这篇文章。经过反复试验,我提出了以下解决方案:

interface Bar { 
    sayHello(name: string);
}

class Foo implements Bar {
    sayHello(name: string) {
        window.alert("Hello " + name);
    }
}

function Baz(c: new() => Bar) {
    return new C();
}

var o = Baz(Foo);
o.sayHello("Bob");
基本上,接口只能定义对象实例的约定,因此必须在调用构造函数的函数中要求某个构造函数存在。此方法还可以很好地处理泛型:

function Baz<T extends Bar>(c: new() => T) {
    return new c();
}

var o = Baz(Foo);
函数Baz(c:new()=>T){
返回新的c();
}
var o=Baz(Foo);

在上面的示例中,变量“o”将被推断为Foo类型。

有一个简单的答案。查看您的
界面:

interface Bar {
    new(): Bar;
}
假设您已经创建了一些实现该接口的
Magic

class Magic implements Bar {
    // ...
}
这意味着
Magic
的任何实例都必须遵守
Bar
的规范。假设您有一个名为
Magic
Magic
实例

由于
magic
符合
Bar
的规范,因此
magic
必须是可更新的,这意味着以下必须工作:

const foo = new magic() // lowercase m!
此外,该调用的结果,即
foo
,本身必须符合
条的要求。这意味着以下各项也必须起作用:

const zzz = new foo();
new (new (new (new (new (new (new (new Magic())))))))
很明显,以下几点也必须起作用:

const zzz = new foo();
new (new (new (new (new (new (new (new Magic())))))))

很明显,您的代码不满足这个条件。因此,您的代码不会键入check。

您使用的不是
any
,而是一个超级接口(您可以省去
实现
扩展
,顺便说一句)。我想这没关系,而且比
任何
都好,但有一件事仍然困扰着我:为什么不能让
NewableBar::new()
返回
NewableBar
?为什么它必须是一种比
NewableBar
(显然至少和
Foo
)更通用的类型?@AdrianLang我将显式继承和实现放在显式中,但你是对的-如果所有内容都匹配,TypeScript将很高兴地推断出这些类型。当试图将方法上的
new()
签名视为特定类型时,会出现解释问题。但是,每当您尝试向Foo添加任何内容时,该问题就会中断。编辑:对不起,我做错了。我的构造签名应该是:
new(…\任何[]):Bar
这实际上是因为未初始化的
Foo
没有初始化时创建的函数,因此
Foo
不能替代
new Foo()
。我会根据你的想法,在不同的答案中发布另一个解决方案。是的,我想实现的就是这样的目标。除了我想把
Bar
Newable
作为一个界面。谢谢