2015-09-30 22 views
17

Używam React.js z TypeScript. Czy istnieje sposób tworzenia komponentów React, które dziedziczą z innych komponentów, ale mają dodatkowe rekwizyty/stany?Rozszerzanie komponentów reakcji w TypeScript

Co staram się osiągnąć coś takiego:

interface BaseStates { 
    a: number; 
} 

class GenericBase<S extends BaseStates> extends React.Component<void, S> { 
    protected getBaseInitialState(): BaseStates { 
     return { a: 3 }; 
    } 
} 

class Base extends GenericBase<BaseStates> { 
    getInitialState(): BaseStates { 
     return super.getBaseInitialState(); 
    } 
} 

interface DerivedStates extends BaseStates { 
    b: number; 
} 

class Derived extends GenericBase<DerivedStates> { 
    getInitialState(): DerivedStates { 
     var initialStates = super.getBaseInitialState() as DerivedStates; // unsafe?? 
     initialStates.b = 4; 
     return initialStates 
    } 
} 

Będzie to jednak niepowodzeniem, jeśli zadzwonię this.setState w Derived, pojawia się błąd maszynopis (parametr typu DerivedStates nie jest przypisane do pisania S). Przypuszczam, że nie jest to rzecz specyficzna dla TypeScript, ale ogólne ograniczenie mieszania dziedziczenia z rodzajami (?). Czy istnieje jakieś obejście tego typu?

UPDATE

Rozwiązanie zdecydowałem się na (na podstawie odpowiedzi Davida Sherret):

interface BaseStates { 
    a: number; 
} 

class GenericBase<S extends BaseStates> extends React.Component<void, S> { 
    constructor() { 
     super(); 
     this.state = this.getInitialState(); 
    } 

    getInitialState(): S { 
     return { a: 3 } as S; 
    } 

    update() { 
     this.setState({ a: 7 } as S); 
    } 
} 

interface DerivedStates extends BaseStates { 
    b: number; 
} 

class Derived extends GenericBase<DerivedStates> { 
    getInitialState(): DerivedStates { 
     var initialStates = super.getInitialState(); 
     initialStates.b = 4; 
     return initialStates; 
    } 

    update() { 
     this.setState({ a: 7, b: 4 }); 
    } 
} 

Odpowiedz

10

Można ustawić tylko kilka właściwości stanie naraz w Derived za pomocą Typ twierdzenie:

this.setState({ b: 4 } as DerivedStates); // do this 
this.setState({ a: 7 } as DerivedStates); // or this 
this.setState({ a: 7, b: 4 });   // or this 

Nawiasem mówiąc, nie trzeba mieć różne nazwy dla getInitialState ... możesz po prostu zrobić:

class GenericBase<S extends BaseStates> extends React.Component<void, S> { 
    constructor() { 
     super();   
     this.state = this.getInitialState(); 
    } 

    protected getInitialState() { 
     return { a: 3 } as BaseStates as S; 
    } 
} 

class Derived extends GenericBase<DerivedStates> { 
    getInitialState() { 
     var initialStates = super.getInitialState(); 
     initialStates.b = 4; 
     return initialStates; 
    } 
} 
+0

Dzięki za szybką odpowiedź. Dla twojego rozwiązania pojawia się błąd dla drugiej linii konstruktora: 'type 'BaseStates' nie można przypisać 'S'' co nie jest zaskakujące, ponieważ' S' jest podklasą 'BaseStates' . – Thegaram

+0

@ Thegaram właśnie to naprawiałem. Naprawiono teraz. –

+0

Dzięki! Nadal nie jestem pewien, jak bezpieczne są ci downcastowie, ale na moje pytanie udzielono odpowiedzi. – Thegaram