2014-04-11 10 views
7

To jest coś, co robiłem w starszych wersjach TypeScript i używam tej metody w C#, ale nie działa ona w najnowszej 1.0 wersji TypeScript.Obchodzenie się z brakiem wsparcia dla ograniczenia typu to self

Oto, co sprawdziło się w przeszłości:

class Base<T extends Base<T>> { 
    public children : Array<T>; 

    doAction() { 
     this.children[0].promise(); // used to work 
    } 

    promise() : T { 
     return this; // used to work 
    } 
} 

class Child extends Base<Child> { 
    public myString: string; 
} 

new Child().promise().myString; // used to work 

Wszystko wykorzystywane do pracy w harmonii.

Teraz w maszynopisie 1.0 otrzymuję ten błąd w sprawie definicji Base<T extends Base<T>>:

Ograniczenie parametru typu nie mogą odwoływać się do dowolnego parametru typ z tej samej listy parametrów typu.

Jak mogę naprawić tę przykładową klasę, aby działała, nie wymagając żadnych rzutów poza klasami lub rzucając cokolwiek na "dowolny"? Może ten wzór powinien zostać zmieniony?

+0

pamiętać, że ten wzór nie będzie już konieczna, gdy maszynopis podtrzymuje [to] polimorficzny (https: // github. com/Microsoft/TypeScript/pull/4910) w TS1.7. –

Odpowiedz

10

Już nie wolno używać T tutaj:

class Base<T extends Base<T>> 
--------------------------^ 

albo trzeba dokonać klasa nierodzajową lub zastosowanie:

class Base<T extends Base<any>> 

Powodem tego było, aby kompilator prostszy:

W naszych ciągłych wysiłkach zmierzających do uproszczenia języka upraszczamy to, co generyczne ograniczenia mogą pociągać za sobą.

Dodatkowy narzut w zakresie sprawdzania typów, raportowania błędów i złożoności projektu nie dodał wystarczającej dodatkowej ekspresywności, aby był opłacalny dla wersji 1.0. Możemy to powtórzyć w przyszłych wersjach TypeScript.

- Breaking Changes Wiki

+0

Dzięki. To nie jest tak miłe, ale udało mi się sprawić, żeby wszystko działało, wykonując 'Base >'. Musiałem wykonać rzut na każdą, ale to nie jest wielka sprawa w klasie bazowej: http://goo.gl/8JSLxq –

6

przyjąłem odpowiedź Steve'a ponieważ zasugerował użycie Base<T extends Base<any>>, ale chciałem zachować kopię zmiany kodu, że problem został rozwiązany na przepełnienie stosu:

class Base<T extends Base<any>> { // 1. Set as any 
    children: Array<T>; 

    doAction() { 
     this.children[0].promise(); 
    } 

    promise(): T { 
     return <any> this; // 2. cast to any 
    } 
} 

class Child extends Base<Child> { 
    public myString: string; 
} 

new Child().promise().myString; 

To wymaga rzutu na każdą, ale nie jest tak źle, ponieważ jest tylko w klasie bazowej. Ta zmiana nie wpływa na nic, używając klas Child lub Base, więc ogólnie była to idealna alternatywa.


Aktualizacja W TS 1.7+ można to zrobić za pomocą polymorphic this:

class Base { 
    children: Array<this>; 

    doAction() { 
     this.children[0].promise(); 
    } 

    promise(): this { 
     return this; 
    } 
} 

class Child extends Base { 
    public myString: string; 
} 

new Child().promise().myString; 
+0

niesamowity gość, dzięki –

0

promise() : T { return this; } jest bardzo słaby założenie, że może być łatwo złamane, ponieważ rzutowanie w dół zdefiniowane w klasie bazowej tylko nie może pracować dla żadnej podklasy

Na przykład w tobie, jeśli ktoś definiuje class SuperChild extends Child {}, wtedy promise() z SuperChild da ci Child zamiast SuperChild.

Poza tym tutaj jest jak można zrobić to działa tak jak wcześniej do:

class Base<T> { 
    public children : Array<T>; 

    constructor(
     private toSelf:() => T, 
     private toBase: (something: T) => Base<T> 
    ) { 
    } 


    doAction() { 
     this.toBase(this.children[0]).promise(); // used to work 
    } 

    promise() : T { 
     return this.toSelf(); // 
    } 
} 

class Child extends Base<Child> { 
    public myString: string; 
} 

function toThis() { return this; } 

new Child(toThis, x => x).promise().myString; // used to work 
Powiązane problemy