Typescript 具有构造签名而不是类型检查的接口
我一直在玩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
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
作为一个界面。谢谢