简体   繁体   中英

Type of generic abstract react component

This is my first question, please be gentle ;)

I have several components which share behavior, so I would like to have them all extend the same class, so I don't have to duplicate my functionality:

export abstract class FooComponent<P extends {}> extends React.Component<P, {}> {
    foobar: Foobar = new Foobar();
}

Other classes inherit this component like:

export class BarComponent extends FooComponent<{baz?: boolean}> {
    //dostuff
}

I try to pass these classes as a type into a function, like so:

setFoo (foo: typeof FooComponent) {
    let obj = { foo: foo };
    this.foo = <obj.foo />;
}

this.setFoo(BarComponent);

but my compiler throws the following error:

Type 'BarComponent' is not assignable to type 'FooComponent<any>'. Property 'foobar' is missing in type 'BarComponent'.

It works if I don't extend the props, making FooComponent non-generic, but the FooComponents all have different props, which would not be type-safe if I were to set them as any.

Is there a way I can pass the type of my derived classes, and use them as my base class?

Edit


I found a way to remove all the different props in my FooComponents, so I could make it a base class without a generic type as shown below.

export abstract class FooComponent extends React.Component<{baz?: boolean}, {}> {
    foobar: Foobar = new Foobar();
}

This way, the setFoo function as shown in the original question works, and no longer throws an error.

Thanks for the provided answers though, They gave me some new insights.

您可以指定构造函数签名,而不是使用typeof

setFoo <P, T extends FooComponent<P>>(foo: new (... p: any[]) => T)

You're almost there :

React.createElement(foo, whateverProps);

should do the trick. whateverProps is an object that contains, well, props for the foo class. Be aware that by doing this, you lose some of the TypeScript advantages because the compiler won't be able to check the props against the class' props interface.

IF THE IDEAL IS TO ABSTRACT METHODS AND APPLY STATES ON THE BASIS OF ABSTRACT METHODS WITHOUT THE NEED TO RECONSTRUCT, I THINK THAT IT WILL SERVE THEM (AND IT MAY IMPLEMENT TO HIS NEED)

1 - ABSTRACT COMPONENT

import React from 'react';
/**
      * AbstractComponent
      *
      * Abstract mapper component, ie when extending this abstract component its component class
      * will have properties and auxiliary methods in order to streamline and simplify the deve
 * @author Nathan C. do Nascimento <nathannascimento@nodesistemas.com.br>
 */
abstract class AbstractComponent extends React.Component<any, any>
{
    protected init(states:any) {

        this.changeInputVal    = this.changeInputVal.bind(this);
        this.state = states;
    };

    protected changeInputVal(e:any) {
        this.setStateByKey(e.target.id, e.target.value);
    };

    private setStateByKey(key:any, value:any) {
        this.setState({
            [key] : value
        });

        console.log(value);
    }
}

export default AbstractComponent;

1 - SO IN MY EXTENDED CLASS:

import React from 'react';
import AbstractComponent from './AbstractComponent';

export default class Teste extends AbstractComponent
{
    protected constructor(props:any) {
        super(props);

        this.init({
            inputVal : 'INITIAL STATE OF MY INPUT VAL'
        });
    }

    render() {
        return (
            <div id='node-notify-app2'>
                <input value={this.state.inputVal} id='inputVal' name='inputVal' onChange={this.changeInputVal} />
            </div>
        );
    }
}

3 - AND TO FINISH IMPORT THE COMPONENT IN YOU APP.ts/tsx

File: App.tsx

import React from 'react';
import Teste from "../../temp";

/**
 * Component APP
 *
 * @author Nathan C. do Nascimento <nathannascimento@nodesistemas.com.br>
 */
class App extends React.Component {
    render() {
        return (
            <div id='node-notify-app'>
                <Teste />
            </div>
        );
    }
}

export default App;

4 - THIS RESULT

Now all features that added in the abstract element will be accessible to those who extend it, and through the setStateByKey method the abstract (parent) can control the state of the child, since configured in method init!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM