【问题标题】:How to avoid redeclaring props type in React constructor using Typescript如何避免使用 Typescript 在 React 构造函数中重新声明道具类型
【发布时间】:2019-03-19 01:25:24
【问题描述】:

假设我有这样的课程:

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();
}

有没有办法从类扩展中自动推断 props 类型,同时还可以编写构造函数?

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

【问题讨论】:

  • 不推荐使用componentDidMount生命周期方法获取数据吗?
  • 另外,从构造函数中调用方法通常不是最佳实践,因为类的子类可以覆盖方法,但在调用方法之前没有机会进行初始化。
  • @T.J.Crowder 视情况而定。不一定是特定于方法的问题,因为原型方法可以被孩子覆盖。此外,根据我的经验,在 React 中类继承的使用非常有限。
  • @estus - 是的,在 React 组件中,通常最好使用聚合或包含(React 开发人员当然是这么认为的)。但一般而言,养成这种习惯并不是一个好习惯。

标签: reactjs typescript


【解决方案1】:

通常constructor 本身不应该变得“非常难看”,因为类型可以单独定义为typeinterface,以防参数类型很冗长。

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

正如在type definitions 中所见,这会推断出父构造函数的正确类型,即super

所以这个

constructor(props) {
    super(props);
}

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

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

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

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

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

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

虽然this.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 参数被传递给 superthis.propsprops 在 JavaScript 中是可以互换的。它们在 TypeScript 中不可互换。 this.props 可以在构造函数中访问以获取正确类型的道具。

【讨论】:

    【解决方案2】:

    正如 estus 所说,我建议定义接口或类型别名以减少重复。但是请注意,构造函数的 props 参数的类型只能是 Readonly&lt;RouteComponentProps&lt;{ tag: string }&gt;&gt;,因为 TypeScript 编译器会根据 @types/react 中的声明自动添加 children 属性,您可以依赖第二个默认值和RouteComponentProps 的第三种类型参数,就像您在extends 子句中所做的那样。 (可以说,如果构造函数的参数是真正的 props 对象,那么它的类型应该包含children 属性并省略children 属性是虚假的,但省略是常见的做法,甚至出现在React.Component 超级构造函数的声明中。我在一个项目中也省略了Readonly,但似乎不再推荐。)到那时,也许你会决定类型是短的重复一遍就可以了,不值得定义接口或类型别名。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-10-23
      • 1970-01-01
      • 2023-03-28
      • 1970-01-01
      • 2012-04-05
      • 2020-09-13
      • 2017-03-17
      相关资源
      最近更新 更多