简体   繁体   English

使用打字稿对组件子项进行类型检查

[英]React Component children typecheck with typescript

Here is the scenario:这是场景:

I have a custom component:我有一个自定义组件:

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

and the referenced SuperComponent and SubComponent1 are:并且引用的 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> { ... }

I want SubComponent1 to be the only valid child of SuperComponent, that is, I wish typescript can throw an error if I place <SubComponent2 /> or Other types as child of <SuperComponent>我希望 SubComponent1 是 SuperComponent 的唯一有效子级,也就是说,如果我将<SubComponent2 />或其他类型作为<SuperComponent>子级放置,我希望打字稿可以抛出错误

It seems like typescript only check that the child of should have the type of ReactElement, but ts doesn't check the shape of props of that child (which is subPropsType1), that is, if I place a string or number as child of SuperComponent, ts will complaints that type requirement doesn't meet, but if I place any jsx tag here(which will transpiled to ReactElement), ts will keep silent似乎打字稿只检查子项是否应该具有 ReactElement 的类型,但 ts 不检查该子项(即 subPropsType1)的道具的形状,也就是说,如果我放置一个字符串或数字作为 SuperComponent 的子项, ts 会抱怨类型要求不满足,但是如果我在这里放置任何 jsx 标记(将转换为 ReactElement),ts 将保持沉默

Any idea ?任何的想法 ? And if any configs are required to post here, please don't hesitate to ask如果需要在此处发布任何配置,请随时询问

Really appreciate any idea and solution真的很感激任何想法和解决方案

As of TypeScript 3.1, all JSX elements are hard-coded to have the JSX.Element type, so there's no way to accept certain JSX elements and not others.从 TypeScript 3.1 开始,所有 JSX 元素都被硬编码为具有JSX.Element类型,因此无法接受某些 JSX 元素而不接受其他元素。 If you wanted that kind of checking, you would have to give up the JSX syntax, define your own element factory function that wraps React.createElement but returns different element types for different component types, and write calls to that factory function manually.如果你想要这种检查,你将不得不放弃 JSX 语法,定义你自己的元素工厂函数来包装React.createElement但为不同的组件类型返回不同的元素类型,并手动编写对该工厂函数的调用。

There is an open suggestion , which might be implemented as soon as TypeScript 3.2 (to be released in late November 2018), for TypeScript to assign types to JSX elements based on the actual return type of the factory function for the given component type.一个开放的建议,可能会在 TypeScript 3.2(将于 2018 年 11 月下旬发布)后尽快实现,让 TypeScript 根据给定组件类型的工厂函数的实际返回类型为 JSX 元素分配类型。 If that gets implemented, you'll be able to define your own factory function that wraps React.createElement and specify it with the jsxFactory compiler option, and you'll get the additional type information.如果实现了,您将能够定义自己的工厂函数来包装React.createElement并使用jsxFactory编译器选项指定它,您将获得额外的类型信息。 Or maybe @types/react will even change so that React.createElement provides richer type information, if that can be done without harmful consequences to projects that don't care about the functionality;或者@types/react甚至会改变,以便React.createElement提供更丰富的类型信息,如果这样做不会对不关心功能的项目造成有害后果; we'll have to wait and see.我们将不得不拭目以待。

I would probably declare SuperPropsType.children as:我可能会声明SuperPropsType.children为:

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

To account for the possibility of having both a single and multiple children.考虑同时拥有一个孩子和多个孩子的可能性。

In any case, as pointed out already, that won't work as expected.无论如何,正如已经指出的那样,这不会按预期工作。

What you could do instead is declare a prop, let's say subComponentProps: SubPropsType1[] , to pass down the props you need to create those SubComponent1 s, rather than their JSX, and render them inside SuperComponent :你可以做的是声明一个道具,让我们说subComponentProps: SubPropsType1[] ,传递你需要创建那些SubComponent1的道具,而不是它们的 JSX,并在SuperComponent渲染它们:

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

...

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

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

    ...
  );
};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM