cloneElement:类型与 Partial<P> 类型和属性没有共同的属性

wul*_*one 3 typescript definitelytyped reactjs

在类似于以下的代码中,我正在获取Type { foo: number } has no properties in common with type 'Partial<Child> & Attributes'调用的第二个参数cloneElement,但我不明白为什么......在我看来,正在Partial<Child>获取正确形状的道具,但 TypeScript 不同意。

这是来自https://github.com/DefinitelyTyped/DefinitelyTyped的库版本

"@types/react": "16.3.14",
"@types/react-dom": "16.0.5",
Run Code Online (Sandbox Code Playgroud)

这是例子:

import * as React from "react";
interface Props {
  foo: number;
}
class Child extends React.Component<Props> {
    public render(): React.ReactNode {
        return <span>{this.props.foo}</span>;
    }
}
class Parent extends React.Component<Props> {
    public render(): React.ReactNode {
        return React.Children.map(this.props.children, (child: JSX.Element) => this.cloneChild(child));
    }

    public cloneChild(child: React.ReactElement<Child>): React.ReactElement<Child> {
        const newProps = {
            foo: this.props.foo,
        };
        return React.cloneElement<Child>(child, newProps);
    }
}
Run Code Online (Sandbox Code Playgroud)

这是一个错误,还是我错过了什么?

Obl*_*sys 9

ReactElement和的类型参数cloneElement表示 props 的类型而不是组件的类型,因此您可能想要这样:

public cloneChild(child: React.ReactElement<Props>): React.ReactElement<Props> {
    const newProps = {
        foo: this.props.foo,
    };
    return React.cloneElement<Props>(child, newProps);
}
Run Code Online (Sandbox Code Playgroud)

或者,等价地,

public cloneChild(child: React.ReactElement<Props>) {
    const newProps = {
        foo: this.props.foo,
    };
    return React.cloneElement(child, newProps);
}
Run Code Online (Sandbox Code Playgroud)

另外,还有一个不正确的类型转换(child: JSX.Element)childin的类型React.Children.mapReactChild(归结为ReactElement<any> | string | number,),并且通过强制转换为JSX.Element(== ReactElement<any>),您无需考虑可能的字符串或数字子代。由于在或子元素cloneElement上失败,如果您包含例如文本元素: ,则当前代码会给出运行时错误。stringnumber<Parent>x<Child/></Parent>

要消除类型错误而不进行强制转换,您可以检查stringnumber如下所示:

public render() {
    return React.Children.map(this.props.children, (child) =>
      typeof child === 'number' || typeof child === 'string'
      ? child
      : this.cloneChild(child)
    );
}
Run Code Online (Sandbox Code Playgroud)