【问题标题】:How to access React child element props in a type safe manner with TypeScript?如何使用 TypeScript 以类型安全的方式访问 React 子元素道具?
【发布时间】:2020-03-08 03:09:48
【问题描述】:

我正在尝试在我的应用程序中访问 React [Native] 组件的 props(保证是我的自定义类型 ItemTemplate 的元素的实例:

const children = React.Children.toArray(this.props.children);
return children.find(t => t.props.itemKey == key);

但是,当我尝试访问 t.props 时,在第二行中我得到:

Property 'props' does not exist on type 'ReactElement<ItemTemplate, string | ((props: any) => ReactElement<any, string | ... | (new (props: any) => Component<any, any, any>)> | null) | (new (props: any) => Component<any, any, any>)> | ... 13 more ... | (ReactElement<...>[] & ReactPortal)'.
  Property 'props' does not exist on type 'ReactElement<ItemTemplate, string | ((props: any) => ReactElement<any, string | ... | (new (props: any) => Component<any, any, any>)> | null) | (new (props: any) => Component<any, any, any>)>[] & string'.

代码工作正常,但 TypeScript (3.6.3) IntelliSense 出现问题。 为什么?

【问题讨论】:

  • 投反对票的人至少可以解释原因吗?

标签: reactjs typescript react-native react-props typescript-types


【解决方案1】:

在这种情况下,您需要将子项声明或强制转换为 ReactElement。这里我有一个从 nextjs 到自定义 NavLink 的 Link 组件示例:

import { ReactElement, cloneElement } from 'react';
import Link, { LinkProps } from 'next/link';

type NavigationData = {
    currentPath: string;
    pathsToMatch: string[] | string;
    activeClassName: string;
    children: ReactElement;
};

type NavLinkProps = LinkProps & NavigationData;

export default function NavLink({
    currentPath,
    pathsToMatch,
    activeClassName,
    children,
    ...props
}: NavLinkProps): ReactElement {
    function GetActiveLink(
        currentPath: string,
        paths: string | string[],
        activeClassName: string
    ): string {
        if (currentPath === '/' && paths === '/') {
            return activeClassName;
        } else if (currentPath !== '/' && paths.indexOf(currentPath) !== -1) 
        {
            return activeClassName;
        }

        return '';
    }

   let className: string = children.props.className || '';
   className += ` ${GetActiveLink(currentPath, pathsToMatch, activeClassName)}`;

    return <Link {...props}>{cloneElement(children, { className })}</Link>;
}

通过这种方式,您可以在没有任何警告的情况下访问属性道具。

快乐的代码。 :-)

【讨论】:

    【解决方案2】:

    如下使用:

    const children: Array<ReactChild> = React.Children.toArray(this.props.children);
    return children.find(t => t.props.itemKey == key);
    

    或使用您的自定义类型 ItemTemplate:

    const children: Array<ItemTemplate> = React.Children.toArray(this.props.children);
    return children.find(t => t.props.itemKey == key);
    

    【讨论】:

    • 它不起作用。它不能将该类型分配给children: ... Type 'ReactElement ReactElement Component)> | null) | (new (props: any) => Component)>' 缺少类型 'ItemTemplate' 的以下属性:render、context、setState、forceUpdate 和 2 more.ts(2322)
    • 试试这个: const children: any = React.Children.toArray(this.props.children); return children.find(t => t.props.itemKey == key);
    • any 不应使用,除非将 JavaScript 迁移到 TypeScript。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-24
    • 2014-04-26
    • 2021-05-11
    • 2021-09-04
    相关资源
    最近更新 更多