通用抽象反应组件的类型

时间:2017-12-05 13:31:24

标签: reactjs typescript generics inheritance

这是我的第一个问题,请温柔;)

我有几个共享行为的组件,所以我希望它们都扩展到同一个类,所以我不必复制我的功能:

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

其他类继承此组件,如:

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

我尝试将这些类作为类型传递给函数,如下所示:

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

this.setFoo(BarComponent);

但我的编译器抛出以下错误:

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

如果我没有扩展道具,使得FooComponent不是通用的,但是FooComponents都有不同的道具,如果我将它们设置为任何道具,那么它就不是类型安全的。

有没有办法可以传递派生类的类型,并将它们用作我的基类?

修改

我找到了一种方法来删除我的FooComponents中的所有不同的道具,所以我可以使它成为没有泛型类型的基类,如下所示。

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

这样,原始问题中显示的setFoo函数可以正常工作,不再抛出错误。

感谢您提供的答案,他们给了我一些新的见解。

3 个答案:

答案 0 :(得分:0)

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

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

答案 1 :(得分:0)

你快到了:

React.createElement(foo, whateverProps);

应该做的伎俩。 whateverProps是一个包含foo类的道具的对象。请注意,通过这样做,您将失去一些TypeScript优势,因为编译器将无法针对类的props接口检查道具。

答案 2 :(得分:0)

如果理想是抽象方法,并且在不需要重构的基础上根据抽象方法应用状态,我认为它将为他们服务(并且可能满足他的需要)

1-抽象成分

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-我的扩展班级如此:

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-并最终将组件导入到您的APP.ts / tsx

文件: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-此结果

现在,扩展抽象元素的人员将可以访问添加在抽象元素中的所有功能,并且抽象(父)通过setStateByKey方法可以控制子状态,因为在方法init中进行了配置!