React Native 如何使用typescript测试儿童的特定类型

myzjeezk  于 2023-05-18  发布在  React
关注(0)|答案(2)|浏览(96)

我正在一个大型react原生项目中从PropTypes转换为typescript。该代码有几个组件,它们使用子类进行名称范围和组织。一个简化的例子是:

const styles = StyleSheet.create({
    listItem: ...,
    leftItem: ...,
    contentItem: ...,
    rightItem: ...,
})
const ListItemLeft = ({ children }) => <View style={styles.leftItem}>{children}</View>;
const ListItemContent = ({ children }) => <View style={styles.contentItem}>{children}</View>;
const ListItemRight = ({ children }) => <View style={styles.rightItem}>{children}</View>;
class ListItem extends Component {
    render() {
        let left = null, right = null, content = null;
        const otherChildren = [];
        React.Children.forEach(children, child => {
          if (child) {
            if (child.type.name === Left.name) {
              left = child;
            } else if (child.type.name === Right.name) {
              right = child;
            } else if (child.type.name === Content.name) {
              content = child;
            } else {
              otherChildren.push(child);
            }
          }
        });
        return (
            <div style={styles.listItem}>
                {left}
                {content}
                {right}
                {otherChildren}
            </div>
        );
    }
}
ListItem.Left = ListItemLeft;
ListItem.Content = ListItemContent;
ListItem.Right = ListItemRight;
export default ListItem;

从一个页面使用它看起来像

<ListItem>
    <ListItem.Left>Left content</ListItem.Left>
    <ListItem.Content>Main content</ListItem.Cotent>
    <ListItem.Right>Right content</ListItem.Right>
<ListItem>

当我将其转换为typescript时,我似乎不知道如何测试子项以查看它们是什么类型的项并相应地分配变量。

let left : ListItemLeft | null = null, 
    right : ListItemRight | null  = null,
    content : ListItemContent | null = null;
React.Children.forEach<ReactNode>(children, child => {
    /* how to test child type and assing to left, right, content or other? /*
});
f0ofjuux

f0ofjuux1#

如果您现有的JS代码正在工作,那么在迁移TypeScript之后它可能会继续这样做。然而,TypeScript可能会报告错误,因为对子对象进行了一些不安全的操作,因为它的类型是相当复杂的string | number | boolean | React.ReactElement<any, string | React.JSXElementConstructor<any>> | React.ReactFragment | React.ReactPortal | null | undefined
将if语句更改为例如:if ((typeof child === 'object') && ('type' in child) && (child.type === ListItemLeft)) {应该足以让TypeScript满意,同时如果它有非组件的子组件(如字符串),也会使组件更安全。
请注意,一般来说,与大多数其他类型化语言不同,TypeScript对象不能在运行时查询其类型,因为TypeScript是一种结构类型化语言。这种方法只适用于React提供的type字段。
This answer to a similar problem might also be useful.

zbq4xfa0

zbq4xfa02#

谢谢你,你的回答帮助我看到了森林,尽管树木。对于任何其他寻找示例的人来说,这就是我更新的代码的样子。正如Dan所提到的,React将所需的类型信息(type属性)添加到组件中,并使用React.isValidElement函数使typescript在检查它时感到高兴。

let left: LeftElement | null = null,
  right: RightElement | null = null,
  content: ContentElement | null = null;
const otherChildren: ReactNode[] = [];
React.Children.forEach<ReactNode>(children, child => {
  if (child != null) {
    if (React.isValidElement<ElementProps>(child)) {
      if (child.type == LeftElement) {
        left = child as unknown as LeftElement;
      } else if (child.type == ContentElement) {
        content = child as unknown as ContentElement;
      } else if (child.type == RightElement) {
        right = child as unknown as RightElement;
      } else {
        otherChildren.push(child);
      }
    } else {
      otherChildren.push(child);
    }
  }
});

相关问题