Подтвердить что ты не робот

Расширение компонентов React в TypeScript

Я использую React.js с TypeScript. Есть ли способ создать компоненты React, которые наследуются от других компонентов, но имеют некоторые дополнительные реквизиты/состояния?

То, что я пытаюсь достичь, выглядит примерно так:

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
    }
}

Однако это произойдет, если я вызову this.setState в Derived, я получаю ошибку TypeScript (параметр типа DerivedStates не может быть назначен типу S). Я полагаю, что это не TypeScript -специфическая вещь, а общее ограничение смешивания наследования с дженериками (?). Есть ли безопасный способ для этого?

UPDATE

Решение, на котором я остановился (на основе ответа Дэвида Шеррета):

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 });
    }
}
4b9b3361

Ответ 1

Вы можете установить только несколько свойств состояния сразу в Derived с помощью утверждения типа:

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

Кстати, не нужно иметь разные имена для getInitialState... вы могли бы просто сделать:

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