React与TypeScript - 类型{...}无法分配给类型'Readonly<S>'

13
我在我的应用中使用一个抽象类作为父级React组件,一些子组件都继承自它。
它有一个默认状态和几个类方法,这些方法可以选择性地从扩展组件中重写。
这个抽象组件看起来像这样:
import * as React from 'react';

export interface StatefulProps {
  observers?: Array<(context: any, state: object) => any>;
}
export interface StatefulState {
  machine: {
    [propName: string]: any;
  };
  name: string;
  value?: any;
}

export default abstract class StatefulComponent<P extends StatefulProps, S extends StatefulState> extends React.Component<P, S> {
  static defaultProps = {
    observers: [],
  };

  state = {
    machine: {},
    name: '',
  };

  abstract generateState(stateName: string, stateParam?: any): object;

  shouldComponentUpdate(_: P, nextState: S) {
    const { name } = this.state;
    if (nextState && nextState.name !== name) {
      return true;
    }
    return false;
  }

  goToState = (stateName: string, stateParam?: any) => {
    const { observers } = this.props;
    this.setState(
      {
        name: stateName,
        machine: this.generateState(stateName, stateParam),
      },
      () => {
        if (observers && observers.length) {
          observers.forEach(observer => {
            if (observer instanceof Function) {
              observer(this, this.state);
            }
          });
        }
      }
    );
  }
}

然而,状态是被tslint强调的,在悬停时会显示以下错误:

Property 'state' in type 'StatefulComponent<P, S>' is not assignable to the same property in base type 'Component<P, S, any>'.
Type '{ machine: {}; name: string; }' is not assignable to type 'Readonly<S>'.

我真的想不通它为什么在抱怨……

我对TypeScript还比较新,所以我完全有可能在做事情的方式上犯了很低级的错误,但是任何建议或帮助都将不胜感激!

1个回答

5

您不能将对象文字分配给泛型类型。泛型类型的约束定义了S可能具有的最小属性集,但它可能具有更多属性,其中一些是必需的,请考虑以下派生类:

class MyStatefulComponent extends StatefulComponent<StatefulProps, StatefulState & { newMandatoryProp: number }> {
    constructor(p: StatefulProps){
        super(p);
        this.state.newMandatoryProp // will be undefined beacuse the base class did not initailize it correctly 
    }
    generateState(stateName: string, stateParam?: any): object { return null as any }
}

你可以使用类型断言来实现,但这并不是类型安全的:
export default abstract class StatefulComponent<P extends StatefulProps, S extends StatefulState> extends React.Component<P, S> {
    constructor(props: P) {
        super(props);

        this.state = {
            machine: {},
            name: '',
        } as S;
    }
}

你也可以为创建状态定义一个抽象方法,并将创建完整状态对象的责任传递给派生类。

1
感谢您深思熟虑的回答!我认为采用抽象状态创建者方法,并在派生类中处理它。 - amogower
@amogower 这是最安全的类型选项 :) - Titian Cernicova-Dragomir

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接