Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 835
Jamie Birch Avatar asked Jan 02 '18 13:01

Jamie Birch


People also ask

Can you extend an abstract class?

An abstract class can extend another abstract class. And any concrete subclasses must ensure that all abstract methods are implemented. Abstract classes can themselves have concrete implementations of methods. These methods are inherited just like a method in a non-abstract class.

Does abstract class extend or implement?

A class which is declared as abstract is known as an abstract class. It can have abstract and non-abstract methods. It needs to be extended and its method implemented. It cannot be instantiated.

What happens when objects of abstract classes are subclassed?

When an abstract class is subclassed, the subclass usually provides implementations for all of the abstract methods in its parent class. However, if it does not, then the subclass must also be declared abstract .

How do you pass a state to a component?

Passing State to a Component To pass the state into another component, you can pass it as a prop. Then, inside <ExampleComponent /> , you can access the data as this. props.


2 Answers

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."

like image 51
Mosè Raguzzini Avatar answered Oct 13 '22 00:10

Mosè Raguzzini


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

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

like image 44
Cù Đức Hiếu Avatar answered Oct 13 '22 01:10

Cù Đức Hiếu