2012-10-18 8 views
9

Grałem trochę z interfejsami z podpisami konstruktem w maszynopisie, i stałem się nieco zdezorientowany, gdy nie następuje typ kontroli:Interfejsy z podpisami konstruktem nie wpisać sprawdzanie

class Foo { 
    constructor() { 
    } 
} 

interface Bar { 
    new(): Bar; 
} 

function Baz(C : Bar) { 
    return new C() 
} 

var o = Baz(Foo); 

Błąd typ :

podanych parametrów nie znaleziono żadnych podpis docelowego połączenia: Construct podpisy 'new() => Foo' Rodzaje i 'Bar' są niezgodne: typ 'Bar' wymaga podpisu zbudować, ale Type Brak "Foo" s one (C: Bar) => Bar

Typ konstruktora Foo to() => Foo, i to jest to, co myślałem, że Bar powiedział. Czy coś mi umyka?

Odpowiedz

1

Problem (przynajmniej z punktu widzenia kompilatora TypeScript) jest sygnatura metody 's new. Jeśli zastąpić definicję Bar z poniższych,

interface Bar { 
    new(): any; 
} 

to działa. Równie dobrze możesz użyć new(): Foo, tylko Bar, ponieważ wartość zwracana nie działa.

5

Oto zaktualizowana wersja kodu z subtelną zmianą.

Definiujemy interfejs Bar z dowolnymi funkcjami i zmiennymi, które prawdopodobnie będą obecne.

Następnie rozszerzamy interfejs Bar o interfejs NewableBar. To właśnie zdefiniował konstruktor, który zwraca wartość Bar.

Ponieważ Foo implementuje Bar i ma konstruktora i Baz wymaga NewableBar, wszystko jest sprawdzone.

To jest trochę bardziej gadatliwe niż any - ale daje ci to, czego potrzebujesz.

interface Bar { 

} 

interface NewableBar extends Bar { 
    new(); 
} 

class Foo implements Bar { 
    constructor() { 

    } 
} 

function Baz(C : NewableBar) { 
    return new C() 
} 

var o = Baz(Foo); 
+0

Zamiast używać "dowolnego", używasz super interfejsu (możesz pominąć 'implements' i' extends', btw). Zgadza się, wszystko w porządku i jest lepsze od "jakiegokolwiek", ale jedna rzecz nadal mnie nurtuje: dlaczego nie możesz pozwolić 'NewableBar :: new()' zwrócić 'NewableBar'? Dlaczego musi to być typ bardziej ogólny ** niż 'NewableBar' (i oczywiście przynajmniej tak ogólny jak' Foo')? –

+0

@AdrianLang Dodałem jawne dziedziczenie i implementacje, aby były jawne, ale masz rację - TypeScript z radością wnioskuje, jeśli wszystko pasuje. Występuje problem z interpretacją, gdy próbujemy traktować sygnaturę 'new()' dla metody jako określonego typu. – Fenton

+0

Ale to zepsuje się, gdy spróbujesz dodać coś do Foo. Edycja: przepraszam, robiłem to źle. Mój podpis konstrukcji powinien brzmieć: 'new (... _: any []): Bar;' – farre

1

Myślę, że wiem, gdzie bierzesz to i myślę, że potrzebujesz subtelnie innego podejścia.

Ten przykład mówi co następuje:

  • Baz koniecznością być przekazywane element, który jest odnawialny.
  • Baz będzie zwrócić Bar
  • Nie potrzeba All Bar, aby być odnawialny, tylko te są przekazywane do Baz

Oto przykład:

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

Jedyne niebezpieczeństwo to podejście polega na tym, że można przekazać coś nieistotnego, które nie było funkcją Bar na Bazę.Ponieważ używasz funkcji dynamicznej, tworząc obiekt z argumentu, jest to w dużej mierze nieuniknione, chyba że chcesz przekazać wstępnie zainicjowany obiekt, w którym to przypadku Baz byłby całkiem szczęśliwie po prostu zaakceptować pasek, a nie neware.

+0

Tak, coś w tym kierunku było tym, co chciałem osiągnąć. Z wyjątkiem tego, że chciałem, aby "Bar" i "Newable" były jednym interfejsem. Dzięki. – farre

1

Wiem, że to stare pytanie, ale dzisiaj potrzebowałem czegoś podobnego i natknąłem się na post. Po pewnym prób i błędów wymyśliłem następujące rozwiązanie:

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

Zasadniczo interfejsy tylko można określić umowę instancji obiektu, tak wymagające pewnego konstruktora istnieć musi być zrobione w funkcji, która będzie wywołanie konstruktora. Metoda ta odgrywa również ładnie z rodzajowych:

function Baz<T extends Bar>(c: new() => T) { 
    return new c(); 
} 

var o = Baz(Foo); 

W powyższym przykładzie zmienna „o” będzie wnioskować jako typ Foo.