反应生命周期方法的类型安全性

时间:2018-03-08 21:49:35

标签: reactjs typescript

我正在使用TypeScript进行React项目。根据我在type definitions componentWillReceiveProps'中看到的内容第一个参数应该是传递给Component类的相同泛型类型。我认为Component已经实现ComponentLifecycle,但我也尝试直接使用implements ComponentLifecycle,而且我仍然没有达到我期望的类型安全性。

interface Props {
  user: { login: string };
}

class Comp extends React.Component<Props> {
  componentWillReceiveProps({ user }) {
    // I think this should be two errors:
    // `Property `ogin` does not exist on type 
    // Type `string` is not assignable to type 'void';
    return user.ogin;
  }
}

但是我没有得到任何错误,似乎传递到Props的{​​{1}}只能在一个级别维护它们的类型。为了使其工作,我可以这样写:

componentWillReceiveProps

有没有办法让TypeScript正确键入已实现接口的泛型参数?这是类型定义中的错误吗?

1 个答案:

答案 0 :(得分:1)

不,这不是错误。在类型中React.Component的定义是:

class Component<P, S> {
    constructor(props?: P, context?: any);
    setState<K extends keyof S>(
        state: ((prevState: Readonly<S>, props: P) => (Pick<S, K> | S)) | (Pick<S, K> | S),
        callback?: () => any
    ): void;

    forceUpdate(callBack?: () => any): void;
    render(): JSX.Element | null | false;
    props: Readonly<{ children?: ReactNode }> & Readonly<P>;
    state: Readonly<S>;
    context: any;
    refs: {
        [key: string]: ReactInstance
    };
}

生命周期方法及其类型没有任何内容。从typescript的角度来看,你只是用新方法扩展React.Component,它试图从函数中的用户代码推断出参数的类型。当您明确添加类型时,Typescript会理解您的意图并帮助您。我现在只有一种方法可以精确地输入 - 将Component类定义为abstract,并将所有生命周期方法标记为abstract。但是在这种情况下,你必须在子类定义中覆盖这些方法,但是你不想用React做大部分时间。如果您只是在常规类定义上定义生命周期方法,例如React.Component,您仍然可以使用其他参数覆盖此定义,因此typescript不会强制您保持相同的函数形状并阻止您使用未知的参数。我认为只有通过向typescript添加sealed函数属性才能修复它,这将禁止覆盖子代的函数类型。