Jak działają interfejsy typescript z podpisami construct?

Mam problem z rozpracowaniem sposobu definiowania konstruktorów w interfejsach. Chyba coś źle zrozumiałam. Ale od dłuższego czasu szukałem odpowiedzi i nie mogę znaleźć nic z tym związanego.

Jak zaimplementować następujący interfejs w klasie TypeScript:

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

Anders Hejlsberg tworzy interfejs zawierający coś podobnego do tego w tym wideo (około 14 minut). Ale dla mojego życia nie mogę wdrożyć to w klasie.

Prawdopodobnie czegoś nie rozumiem, czego nie rozumiem?

EDIT:

Dla wyjaśnienia. Z "nowym ( ... ) "Miałem na myśli "cokolwiek". Mój problem polega na tym, że nie mogę uzyskać nawet najbardziej podstawowej wersji tego działa:

interface MyInterface {
    new () : MyInterface;
}

class test implements MyInterface {
    constructor () { }
}

To nie jest kompilowanie dla mnie dostaję "Class ' test' deklaruje interfejs 'MyInterface', ale go nie implementuje: Type 'MyInterface' wymaga podpisu konstruktu, ale Type 'test' nie ma " podczas próby kompilacji to.

EDIT:

Więc po zbadaniu tego trochę bardziej biorąc pod uwagę opinie.

interface MyInterface {
    new () : MyInterface;
}

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

Nie jest poprawnym maszynopisem i to nie rozwiązuje problemu. Nie można zdefiniować typu zwracanego konstruktora. Zwróci "test". Podpis:: test klasowy { konstruktor () { } } Wygląda na "new () = > test" (uzyskany przez najechanie kursorem na "class" w edytorze online z wklejonym kodem). I to jest to, czego byśmy chcieli i co myślałem byłoby.

Czy ktoś może podać przykład tego lub czegoś podobnego, gdzie to jest rzeczywiście kompilowane?

EDIT (ponownie...):

Więc mogłem wpaść na pomysł, dlaczego jest możliwe zdefiniowanie tego w interfejsie, ale nie jest możliwe zaimplementowanie w klasie TypeScript.Następujące utwory:

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

interface MyInterface {
    new () : MyInterface;
}

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

Więc jest to tylko cecha maszynopisu, który pozwala na interfejs javascript? Czy jest możliwe zaimplementowanie go w maszynopisie bez konieczności implementacji Klasa korzystająca z javascript?

Author: Nypan, 2012-11-16

5 answers

Sygnatury konstruowania w interfejsach nie są implementowalne w klasach; służą tylko do definiowania istniejących interfejsów API JS, które definiują'nową' funkcję. Oto przykład dotyczący sygnatur interfejsów new, który działa:

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

Tworzy to rzeczywiste ograniczenie dla tego, co można wywołać makeObj za pomocą:

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/doraprojects.net/template/agent.layouts/content.php on line 54
2012-11-15 23:26:41

W poszukiwaniu dokładnie tego samego pytania poszedłem sprawdzić, jak zespół maszynopisu to zrobił...

Deklarują interfejs, a następnie zmienną o nazwie dokładnie odpowiadającej nazwie interfejsu. Jest to również sposób na typowanie funkcji statycznych.

Przykład z lib.d.ts:

interface Object {
    toString(): string;
    toLocaleString(): string;
    // ... rest ...
}
declare var Object: {
    new (value?: any): Object;
    (): any;
    (value: any): any;
    // ... rest ...
}
Próbowałem i działa jak urok.
 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/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-04 10:35:41

Z punktu widzenia projektowania, nie jest zwykle określanie wymagań konstruktora w interfejsie. Interfejs powinien opisywać operacje, które można wykonać na obiekcie. Różne klasy implementujące interfejs powinny mieć możliwość, aby wymagać różnych parametrów konstruktora, jeśli zajdzie taka potrzeba.

Na przykład, gdybym miał Interfejs:

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

Mogę mieć implementacje do przechowywania danych w formie pliku cookie, który nie wymaga żadnych parametrów konstruktora, a wersja, która przechowuje dane w bazie danych, która wymaga łańcucha połączeń jako parametru konstruktora.

Jeśli nadal chcesz definiować konstruktory w interfejsie, jest na to brudny sposób, który użyłem, aby odpowiedzieć na to pytanie:

Interfejsy z podpisami konstruktu Nie sprawdzanie typu

 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/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:19

Cóż interfejs z podpisem konstruktu nie jest przeznaczony do implementacji przez żadną klasę(na pierwszy rzut oka może to wyglądać dziwnie dla facetów z tłem C#/Java, takich jak ja, ale daj mu szansę). Jest nieco inaczej.

Przez chwilę pomyśl o tym jako o interfejsie z sygnaturką wywołania (jak @FunctionalInterface w Java world). Jego celem jest opisanie typu funkcji..tak jakby. Opisywana sygnatura ma być spełniona przez obiekt funkcji...ale nie byle jaki wysoki poziom funkcja lub metoda. Powinna to być funkcja, która wie, jak skonstruować obiekt, funkcję, która zostanie wywołana, gdy używane jest słowo kluczowe new.

Więc interfejs z podpisem konstruktora definiuje podpis konstruktora ! Konstruktor twojej klasy, który powinien być zgodny z podpisem zdefiniowanym w interfejsie(pomyśl o tym, jak konstruktor implementuje interfejs). To jest jak budowniczy lub fabryka !

Oto krótki fragment kodu, który próbuje zademonstrować najczęściej używane:

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/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-18 11:38:03

Aby osiągnąć zamierzone zachowanie, możesz użyć dekoratorów , mimo że prawdopodobnie nie do tego powinny być używane.

To

interface MyInterface {
    new ();
}

function MyInterfaceDecorator(constructor: MyInterface) {
}


@MyInterfaceDecorator
class TestClass {
    constructor () { }
}

Kompiluje bez problemu. Natomiast poniższa definicja dla TestClass

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

Nie będzie kompilowany.

 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/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-21 21:09:00