2012-11-15 92 views
88

我遇到了一些麻烦,如何在界面中定义构造函数。我可能完全误解了一些东西。但是我已经搜索了很长一段时间的答案,我找不到与此相关的任何内容。带构造签名的打字稿接口如何工作?

如何实现的打字稿类如下界面:

interface MyInterface { 
    new (...) : MyInterface; 
} 

安德斯·海尔斯伯格创建包含在这个video(大约14分钟)与此类似的界面。但在我的生活中,我无法在课堂上实现这一点。

我可能误解了一些东西,我没有得到什么?

编辑:

澄清。随着“新(...)”我的意思是“任何事情”。我的问题是,我不能让即使这个工作的最基本的版本:

interface MyInterface { 
    new() : MyInterface; 
} 

class test implements MyInterface { 
    constructor() { } 
} 

这不是编制我,我得到“类‘测试’声明接口‘MyInterface的’,但没有实现:键入“ MyInterface'需要一个构造签名,但是当试图编译它时,Type'test'缺少一个“。

编辑:

所以研究这个更多的给出的反馈后。

interface MyInterface { 
    new() : MyInterface; 
} 

class test implements MyInterface { 
    constructor() => test { return this; } 
} 

是无效的TypeScript,这并不能解决问题。您不能定义构造函数的返回类型。它会返回“测试”。以下签名: class test { 构造函数(){} } 似乎是“new()=> test”(通过将粘贴的代码悬停在在线编辑器中的“class”上而获得)。这就是我们想要的和我认为会是的。

任何人都可以提供这样的例子或类似的东西,它实际上编译?

编辑(再次...):

所以我可能已经想出了一个主意,为什么它有可能在一个界面来定义这一点,但不可能在打字稿class.The以下工作落实:

var MyClass = (function() { 
    function MyClass() { } 
    return MyClass; 
})(); 

interface MyInterface { 
    new() : MyInterface; 
} 

var testFunction = (foo: MyInterface) : void => { } 
var bar = new MyClass(); 
testFunction(bar); 

因此,这是唯一的打字稿的功能,让你的JavaScript接口?还是有可能在TypeScript中实现它,而不必使用JavaScript实现类?

+0

对不起,提前不正确的反馈。我还在寻找,老实说,我最好的猜测是ctor构造不应该能够返回一个类型,并且在界面中指定一个类型的能力可能是一个错误。 – asawyer

+0

@asawyer是的,它似乎很奇怪。然而,即使Anders Hejlsberg会在官方视频中使用一些无法使用的视频,这也更加陌生。 – Nypan

+0

我在codeplex网站上发布了一个问题。 http://typescript.codeplex.com/discussions/403413 – asawyer

回答

93

建设在接口签名是无法实施在课堂上;它们仅用于定义现有的定义了“新”功能的JS API。下面是一个有关接口new签名的示例,它所做的工作:

class Other implements ComesFromString { 
    constructor (public name: string, count: number) { 
    } 
} 

makeObj(Other); // Error! Other's constructor doesn't match StringConstructable 
+0

正如我在上次编辑问题时所怀疑的那样。我认为我们可以称这个问题为答案。 – Nypan

+28

更正式地讲,实现接口的类是关于类的*实例*的合约。由于类的实例不包含构造签名,因此无法满足界面。 –

+7

在TypeScript的手册(文档)中突出显示这将非常好。 – falconepl

3

从设计角度来看,在接口中指定构造函数的要求并不常见。界面应该描述你可以在一个对象上执行的操作。如果需要,可以允许实现接口的不同类需要不同的构造函数参数。

举例来说,如果我有一个接口:

interface ISimplePersistence { 
    load(id: number) : string; 
    save(id: number, data: string): void; 
} 

我有可能实现对数据存储为一个cookie,它不需要构造函数的参数,并存储在数据库中数据的版本,需要一个连接字符串作为构造器参数。

如果你仍然想在一个界面来定义构造函数,有一个肮脏的方式做到这一点,我用它来回答这个问题:

Interfaces with construct signatures not type checking

+0

我同意一般不包括构造函数在接口中的想法。但是,如果不能在TypescriptClass中实现它,为什么还可能呢? (没有使用你的破解) – Nypan

+0

我找不到任何语言规范中暗示可以在接口上指定构造函数的任何东西。 4.11节包含'new'关键字,并且只说明它对创建实例有效,即'var x = new MyClass();'。 – Fenton

+0

@SteveFenton我在规范中也找不到任何东西。编辑 - 发布后不是三秒钟 - “3.5.3.2构造签名”。 – asawyer

45

在我搜索我去寻找如何确切同样的问题:

interface ComesFromString { 
    name: string; 
} 

interface StringConstructable { 
    new(n: string): ComesFromString; 
} 

class MadeFromString implements ComesFromString { 
    constructor (public name: string) { 
     console.log('ctor invoked'); 
    } 
} 

function makeObj(n: StringConstructable) { 
    return new n('hello!'); 
} 

console.log(makeObj(MadeFromString).name); 

本作什么,你可以调用makeObj以创建一个实际的约束TypeScript-Team做到了这一点......

他们声明了一个接口,然后声明一个名称与接口名完全匹配的变量。这也是输入静态函数的方法。从lib.d.ts

例子:

interface Object { 
    toString(): string; 
    toLocaleString(): string; 
    // ... rest ... 
} 
declare var Object: { 
    new (value?: any): Object; 
    (): any; 
    (value: any): any; 
    // ... rest ... 
} 

我想,和它的作品般的魅力。

+1

我使用相同的模式,并且使其不那么难看,只需在单行中写入“} declare {”,因此它看起来像是一个单一的两步式构造 – setec

+1

这应该是公认的答案。更改库以满足接口要求是不合理的。 –

0

要达到预期的行为,您可以使用Decorators,即使这可能不是他们应该使用的。

interface MyInterface { 
    new(); 
} 

function MyInterfaceDecorator(constructor: MyInterface) { 
} 


@MyInterfaceDecorator 
class TestClass { 
    constructor() { } 
} 

编译没有问题。相反,TestClass的下列定义不会被编译。如下定义:TestClass

// error TS2345: Argument of type 'typeof TestClass' is not assignable to parameter of type 'MyInterface'. 
@MyInterfaceDecorator 
class TestClass { 
    constructor (arg: string) { } 
} 

将不会编译。