在 TypeScript 中扩展 React 组件

IT技术 oop generics inheritance reactjs typescript
2021-05-17 03:44:16

我在 TypeScript 中使用 React.js。有没有办法创建继承自其他组件但有一些额外props/状态的 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.setStateDerived,我得到一个错误的typescript(类型的参数DerivedStates是不能分配给类型S)。我想这不是 TypeScript 特定的东西,而是将继承与泛型 (?) 混合使用的一般限制。是否有任何类型安全的解决方法?

更新

我确定的解决方案(基于 David Sherret 的回答):

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 });
    }
}
2个回答

您可以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;
    }
}
import { Component } from 'react'


abstract class TestComponent<P = {}, S = {}, SS = any> extends Component<P, S, SS> {
  abstract test(): string
}


type Props = {
  first: string,
  last: string,
}

type State = {
  fullName: string,
}

class MyTest extends TestComponent<Props, State> {
  constructor(props: Props) {
    super(props)
    this.state = {
      fullName: `${props.first} ${props.last}`
    }
  }

  test() {
    const { fullName } = this.state
    return fullName
  }
}