如何避免使用Typescript在React构造函数中重新声明道具类型

时间:2018-10-14 12:47:18

标签: reactjs typescript

假设我有一个这样的课程:

class PeopleByTag extends React.Component<RouteComponentProps<{ tag: string }>

我需要在构造函数中做一些事情,在本例中为获取数据,但是要做到这一点,我需要声明一个props参数,但是如果我不指定类型,它将变成任何类型:

constructor(props) {
    super(props); // props is any
    this.loadData();
}

另一方面,如果我重新声明类型,代码将变得非常难看:

constructor(props: Readonly<{
    children?: React.ReactNode;
}> & Readonly<RouteComponentProps<{
    tag: string;
}, StaticContext, any>>) {
    super(props);
    this.loadData();
}

有没有一种方法可以从类扩展中自动推断道具类型,同时还可以编写构造函数?

我也不想使用过时的生命周期挂钩(即ComponentWillMount)。

2 个答案:

答案 0 :(得分:0)

通常,constructor本身不应该变得“非常丑陋”,因为在参数类型冗长的情况下,类型可以分别定义为typeinterface

无法推断构造函数props参数,因为React.Component<RouteComponentProps<{ tag: string }>>泛型参数引用父类React.Component,而不是当前类。

type definitions中可以看出,这可以推断父构造函数的正确类型,即super

所以这个

constructor(props) {
    super(props);
}

有效。 this.props仍正确输入。

如果使用noImplicitAny编译器选项,则为:

constructor(props: any) {
    super(props);
}

在构造函数中使用props类型的any可能会导致类型错误:

constructor(props: any) {
    super(props);

    props.tag; // ok
    props.nonexistentProp; // ok
}

this.props是类型安全的。

可以使用通用类型来键入类,以在构造函数中维护正确的props类型,但这可以认为是过大的:

export class PeopleByTag<P extends { tag: string }> extends React.Component<P> {
  constructor(props: Readonly<P>) {
    super(props); // props is any

    props.tag; // ok
    props.nonexistentProp; // not ok
    props.children; // not ok, but we rarely ever need children in constructor
  }
}

通过为其提供不兼容的类型来防止在构造函数中使用props可能是有益的:

constructor(props: never) {
    super(props);

    props.tag; // not ok
}

如果将props参数传递给super,则this.propsprops在JavaScript中可以互换。它们在TypeScript中不可互换。 this.props可以在构造函数中访问以正确键入道具。

答案 1 :(得分:0)

我建议定义接口或类型别名以减少重复,如estus所说。但是请注意,构造函数的props参数的类型只能是Readonly<RouteComponentProps<{ tag: string }>>,因为TypeScript编译器将根据children中的声明自动添加@types/react属性,并且您就像您在extends子句中所做的那样,可以依赖RouteComponentProps的第二和第三类型参数的默认值。 (可以说,如果构造函数的参数是真正的props对象,则其类型包含children属性,而忽略children属性是伪造的,但是省略是通常的做法,甚至出现在React.Component超级构造函数的声明中。我也已经在一个项目中省略了Readonly,但似乎不再值得推荐。)在这一点上,也许您'将确定该类型足够短以至于可以重复该操作,并且不值得定义接口或类型别名。

顺便说一下,这里的the open suggestion方法和构造函数参数类型默认为超类的类型。