Jamie Birch
Jamie Birch

Reputation: 6102

How to write an abstract class for a component (with extendable state & props)?

I'm trying to write an abstract ReactJS class, then extend it. I'll thus need to extend its props and state (as far as I understand; I'm new to React).

Based on Nitzan's post showing how to extend props from a base class, I made an abstract class Animal:

import * as React from "react";

export interface AnimalProps {
    isHibernatory: boolean;
}

export interface AnimalState {
    shouldHibernate: boolean;
}

// TS2322: Type '{ shouldHibernate: boolean; }' is not assignable to type 'Readonly<S>'.
export abstract class Animal<P extends AnimalProps, S extends AnimalState>
    extends React.Component<P, S> {

    constructor(props: P) {
        super(props);

        this.state = {
            shouldHibernate: props.isHibernatory
        };
    }
}

... And also made a class Cat that extends it:

import * as React from "react";
import {AnimalProps, AnimalState, Animal} from "./Animal";

export interface CatProps extends AnimalProps {
    isHairless: boolean;
}

export interface CatState extends AnimalState {
    shouldSeekWarmth: boolean;
}

export class Cat extends Animal<CatProps, CatState> {

    constructor(props: P) {
        super(props);

        this.state = {
            willHibernate: props.isHibernatory,
            shouldSeekWarmth: props.isHairless
        };
    }
}

However, as commented, the TypeScript compiler throws the error TS2322: Type '{ shouldHibernate: boolean; }' is not assignable to type 'Readonly<S>'. I believe this is because it can't guarantee that S will be readonly once it has extended AnimalState. How else could I write this? Or am I missing a bigger picture?

Upvotes: 9

Views: 23739

Answers (2)

Harry
Harry

Reputation: 5707

I tried to cast the anonymous object to Readonly<S> and the error went away.

this.state = { shouldHibernate: props.isHibernatory } as Readonly<S>;

Upvotes: 7

Mos&#232; Raguzzini
Mos&#232; Raguzzini

Reputation: 15821

React prefers composition over inheritance, may be this is a viable approach in some plain JS patterns but this is not the case.

As you are new to React, take a look at https://reactjs.org/docs/composition-vs-inheritance.html

"At Facebook, we use React in thousands of components, and we haven’t found any use cases where we would recommend creating component inheritance hierarchies."

Upvotes: 10

Related Questions