¿Cómo funcionan las interfaces de typescript con las firmas de construcción?


Estoy teniendo algunos problemas para averiguar cómo definir constructores en interfaces de trabajo. Puede que esté malinterpretando algo. Pero he buscado respuestas por un buen tiempo y no puedo encontrar nada relacionado con esto.

Cómo implementar la siguiente interfaz en una clase TypeScript:

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

Anders Hejlsberg crea una interfaz que contiene algo similar a esto en este video (alrededor de 14 minutos). Pero por la vida de mí no puedo implementar esto en una clase.

Probablemente estoy malinterpretando algo, ¿qué no estoy entendiendo?

EDITAR:

Para aclarar. Con " new ( ... ) "Quise decir " cualquier cosa". Mi problema es que no puedo conseguir incluso la versión más básica de este trabajo:

interface MyInterface {
    new () : MyInterface;
}

class test implements MyInterface {
    constructor () { }
}

Esto no está compilando para mí obtengo "Clase' test 'declara interfaz' MyInterface 'pero no la implementa: El tipo 'MyInterface' requiere una firma de construcción, pero el tipo 'test' carece de una " al intentar compilar se.

EDITAR:

Así que después de investigar esto un poco más dada la retroalimentación.

interface MyInterface {
    new () : MyInterface;
}

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

No es TypeScript válido y esto no resuelve el problema. No se puede definir el tipo de retorno del constructor. Devolverá "prueba". La firma de los siguientes: prueba de clase { constructor () { } } Parece ser " new () = > test "(obtenido al pasar el cursor sobre" class " en el editor en línea con solo ese código pegado). Y esto es lo que querríamos y lo que pensé lo sería.

¿Puede alguien proporcionar un ejemplo de esto o algo similar donde realmente se está compilando?

EDITAR (de nuevo...):

Así que se me podría haber ocurrido una idea de por qué es posible definir esto en una interfaz pero no es posible implementarlo en una clase TypeScript.Las siguientes obras:

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

interface MyInterface {
    new () : MyInterface;
}

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

Entonces, ¿es solo una característica de TypeScript que le permite interactuar con javascript? ¿O es posible implementarlo en TypeScript sin tener que implementar el clase usando javascript?

Author: Nypan, 2012-11-16

5 answers

Las firmas de construcción en interfaces no son implementables en clases; son solo para definir API JS existentes que definen una función 'nueva'capaz. Aquí hay un ejemplo que involucra interfaces new firmas que funcionan:

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);

Esto crea una restricción real para lo que puede invocar makeObj con:

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

makeObj(Other); // Error! Other's constructor doesn't match StringConstructable
 108
Author: Ryan Cavanaugh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-11-15 23:26:41

En mi búsqueda de la misma pregunta fui a ver cómo el Equipo de TypeScript hizo eso...

Están declarando una interfaz y luego una variable con un nombre que coincide exactamente con el nombre de la interfaz. Esta es también la forma de escribir funciones estáticas.

Ejemplo de lib.d.ts:

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

Lo intenté y funciona como encanto.

 49
Author: Nils,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-12-04 10:35:41

Desde la perspectiva del diseño, no es habitual especificar los requisitos del constructor en una interfaz. La interfaz debe describir las operaciones que puede realizar en un objeto. Se debe permitir que las diferentes clases que implementan la interfaz requieran diferentes parámetros de constructor si es necesario.

Por ejemplo, si tuviera una interfaz:

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

Podría tener implementaciones para almacenar los datos como una cookie, que no necesita parámetros de constructor, y una versión que almacena los datos en una base de datos, que necesita una cadena de conexión como parámetro constructor.

Si todavía desea definir constructores en una interfaz, hay una forma sucia de hacer esto, que usé para responder esta pregunta:

Interfaces con firmas de construcción sin comprobación de tipos

 3
Author: user75525,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:47:19

Bueno, una interfaz con una firma de construcción no está destinada a ser implementada por ninguna clase(a primera vista esto podría parecer extraño para los chicos con fondo de C#/Java como yo, pero darle una oportunidad). Es ligeramente diferente.

Por un momento piense en ello como una interfaz con una firma de llamada(como una @FunctionalInterface en el mundo Java). Su propósito es describir un tipo de función..algo así. Se supone que la firma descrita está satisfecha por un objeto de función...pero no cualquier nivel alto función o método. Debería ser una función que sabe cómo construir un objeto, una función que se llama cuando se usa la palabra clave new.

Así que una interfaz con una firma de construcción define la firma de un constructor ! El constructor de su clase que debe cumplir con la firma definida en la interfaz(piense en ello como el constructor implementa la interfaz). ¡Es como un constructor o una fábrica !

Aquí hay un breve fragmento de código que intenta demostrar la uso más común:

interface ClassicInterface { // old school interface like in C#/Java
    method1();
    ...
    methodN();
}

interface Builder { //knows how to construct an object
    // NOTE: pay attention to the return type
    new (myNumberParam: number, myStringParam: string): ClassicInterface
}

class MyImplementation implements ClassicInterface {
    // The constructor looks like the signature described in Builder
    constructor(num: number, s: string) { } // obviously returns an instance of ClassicInterface
    method1() {}
    ...
    methodN() {}
}

class MyOtherImplementation implements ClassicInterface {
    // The constructor looks like the signature described in Builder
    constructor(n: number, s: string) { } // obviously returns an instance of ClassicInterface
    method1() {}
    ...
    methodN() {}
}

// And here is the polymorphism of construction
function instantiateClassicInterface(ctor: Builder, myNumberParam: number, myStringParam: string): ClassicInterface {
    return new ctor(myNumberParam, myStringParam);
}

// And this is how we do it
let iWantTheFirstImpl = instantiateClassicInterface(MyImplementation, 3.14, "smile");
let iWantTheSecondImpl = instantiateClassicInterface(MyOtherImplementation, 42, "vafli");
 1
Author: egelev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-18 11:38:03

Para lograr el comportamiento deseado se podría usar Decoradores, aunque probablemente no sea para lo que se supone que se deben usar.

Esto

interface MyInterface {
    new ();
}

function MyInterfaceDecorator(constructor: MyInterface) {
}


@MyInterfaceDecorator
class TestClass {
    constructor () { }
}

Compila sin problemas. Por el contrario, la siguiente definición para TestClass

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

No compilará.

 0
Author: MarvinDV,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-21 21:09:00