使用打字稿进行反应组件子类型检查

Posted

技术标签:

【中文标题】使用打字稿进行反应组件子类型检查【英文标题】:React Component children typecheck with typescript 【发布时间】:2019-03-14 21:08:35 【问题描述】:

这是场景:

我有一个自定义组件:

class MyComponent extends React.Component 
  render () 
    return (
      <SuperComponent>
        <SubComponent1 />  // <- valid child
      </SuperComponent>
    )


class MyComponent extends React.Component 
  render () 
    return (
      <SuperComponent>
        <SubComponent2 />  // <- No! It's not right shape
      </SuperComponent>
    )

并且引用的 SuperComponent 和 SubComponent1 是:

interface superPropsType = 
  children: ReactElement<subPropsType1>

class SuperComponent extends React.Component<superPropsType>  ... 


interface subPropsType1 = 
  name: string

class SubComponent1 extends React.Component<subPropsType1>  ... 


interface subPropsType2 = 
  title: string

class SubComponent2 extends React.Component<subPropsType2>  ... 

我希望 SubComponent1 是 SuperComponent 的唯一有效子代,也就是说,如果我将 &lt;SubComponent2 /&gt; 或其他类型作为 &lt;SuperComponent&gt; 的子代,我希望 typescript 可以抛出错误

似乎 typescript 只检查子级是否应该具有 ReactElement 的类型,但 ts 不会检查该子级的道具形状(即 subPropsType1),也就是说,如果我将字符串或数字放置为SuperComponent 的子组件,ts 会抱怨类型要求不满足,但是如果我在这里放置任何 jsx 标签(将转译为 ReactElement),ts 将保持沉默

有什么想法吗?如果需要在此处发布任何配置,请随时询问

非常感谢任何想法和解决方案

【问题讨论】:

【参考方案1】:

从 TypeScript 3.1 开始,所有 JSX 元素都被硬编码为 JSX.Element 类型,因此无法接受某些 JSX 元素而不接受其他元素。如果你想要这种检查,你将不得不放弃 JSX 语法,定义你自己的元素工厂函数来包装 React.createElement 但为不同的组件类型返回不同的元素类型,然后手动编写对该工厂函数的调用。

有an open suggestion,它可能会在 TypeScript 3.2(将于 2018 年 11 月下旬发布)尽快实现,以便 TypeScript 根据给定组件的工厂函数的实际返回类型为 JSX 元素分配类型类型。如果实现了,您将能够定义自己的工厂函数来包装React.createElement 并使用jsxFactory 编译器选项指定它,您将获得额外的类型信息。或者@types/react 甚至会改变,以便React.createElement 提供更丰富的类型信息,如果这样做不会对不关心功能的项目造成有害后果的话;我们将不得不拭目以待。

【讨论】:

【参考方案2】:

我可能会将SuperPropsType.children 声明为:

children: React.ReactElement<SubPropsType1> | React.ReactElement<SubPropsType1>[];

考虑同时拥有一个和多个孩子的可能性。

无论如何,正如已经指出的那样,这不会按预期工作。

你可以做的是声明一个道具,比如说subComponentProps: SubPropsType1[],传递你需要的道具来创建那些SubComponent1s,而不是它们的JSX,并在SuperComponent中渲染它们:

interface SuperPropsType 
  children?: never;
  subComponentProps?: SubPropsType1[];


...

const SuperComponent: React.FC<SuperPropsType> = ( subComponentProps ) => 
  return (
    ...

     subComponentProps.map(props => <SubComponent1 key= ...   ...props  />) 

    ...
  );
;

【讨论】:

以上是关于使用打字稿进行反应组件子类型检查的主要内容,如果未能解决你的问题,请参考以下文章

打字稿反应组件中的反应/道具类型eslint错误

如何在反应组件(打字稿+ css)中使用向上和向下键切换div焦点

创建一个返回反应组件类的打字稿函数

将钩子传递给子打字稿的问题

如何在带有打字稿的反应功能组件中定义自定义道具?

为我的反应打字稿组件库生成/维护打字稿定义文件