反应&打字稿:具有高阶控制的交点类型&通用类型

时间:2017-06-14 03:52:57

标签: reactjs typescript generics

当我使用具有此更高阶的泛型类型时,我收到此错误 控制在React& TypeScript(使用@ types / react 15.0.27):

TS2322:Type '{}' is not assignable to type 'IntrinsicAttributes & 
IntrinsicClassAttributes<Component<ITypeComponentProps, ComponentState>> & ...'.
     Type '{}' is not assignable to type 'Readonly<ITypeComponentProps>'.
     Property 'data' is missing in type '{}'.

我希望我的withTestData函数返回类型React.ComponentClass<ITestComponentProps>的控件(即带有空道具),但它告诉我需要在道具中传递data。但是,当我替换泛型类型ITypeTestProps<TData>时,它按预期工作 下面是非泛型类型ITypeTestProps,TData类型为string

withTestData看起来有点令人费解,但是它做了一些相当简单的事情 - 它需要一个组件,它需要P & ITypeTestProps<TData>类型的道具和 将其包装在期望类型为P的道具的组件中。在此测试用例中,PITestComponentProps

这是带有错误的版本:

import * as React from "react";
import {mount} from "enzyme";

interface ITestComponentProps {}

type HOC<PWrapped, PHoc> = React.ComponentClass<PWrapped & PHoc> | 
    React.SFC<PWrapped & PHoc>;

export interface ITypeTestProps<TData> {
    data: TData;
}

export function withTestData<P, S, TData>(Component: HOC<P, 
    ITypeTestProps<TData>>, data: TData):
    React.ComponentClass<P> {

    class C extends React.Component<P & ITypeTestProps<TData>, S> {

        public render(): JSX.Element {
            return (
                <Component data={data} {...this.props as any} />
            );
        }
    }
    return C;
}

type ITypeComponentProps = ITestComponentProps & ITypeTestProps<String>;

class TestComponent extends React.Component<ITypeComponentProps, {}> {
    public render(): JSX.Element {
        return (<div>Hello, {this.props.data}</div>);
    }
}

describe("withTestData()", () => {

    it("wraps a component", () => {
        const data: string = "World";
        const WrappedTestComponent = withTestData(TestComponent, data);
        // The type mismatch occurs here:
        const wrapper = mount(<WrappedTestComponent />);
        expect(wrapper.text()).toContain(`Hello, ${data}`);
    });

});

我可以通过像这样投射控件来解决它,但我想消除演员:

const WrappedTestComponent = withTestData(TestComponent, data) as 
    React.ComponentClass<ITestComponentProps>

修改

这是一个按照我的预期运作的版本 - 它删除了数据&#34;从生成的界面。唯一的区别是类型不是通用的。

import * as React from "react";
import {mount} from "enzyme";

interface ITestComponentProps {}

type HOC<PWrapped, PHoc> = React.ComponentClass<PWrapped & PHoc> |
    React.SFC<PWrapped & PHoc>;

export interface ITypeTestProps {
    data: string;
}

export function withTestData<P, S, TData>(Component: HOC<P, ITypeTestProps>, data: TData):
    React.ComponentClass<P> {

    class C extends React.Component<P & ITypeTestProps, S> {

        public render(): JSX.Element {
            return (
                <Component data={data} {...this.props as any} />
            );
        }
    }
    return C;
}

type ITypeComponentProps = ITestComponentProps & ITypeTestProps;

class TestComponent extends React.Component<ITypeComponentProps, {}> {
    public render(): JSX.Element {
        return (<div>Hello, {this.props.data}</div>);
    }
}

describe("withTestData()", () => {

    it("wraps a component", () => {
        const data: string = "World";
        const WrappedTestComponent = withTestData(TestComponent, data);
        // The type mismatch occurs here:
        const wrapper = mount(<WrappedTestComponent />);
        expect(wrapper.text()).toContain(`Hello, ${data}`);
    });

});

从零开始运行此示例:

$ npm install -g create-react-app
$ create-react-app my-app --scripts-version=react-scripts-ts
$ cd my-app/
$ npm install @types/react@15.0.27 enzyme --dev

将上述代码复制到文件src/demo.test.tsx

$ npm test

1 个答案:

答案 0 :(得分:0)

错误正确警告您错过了为ITypeTestProps接口的强制属性提供值。

因此,为了解决问题(如果您的业务逻辑没有问题),您可以在data接口中将ITypeTestProps声明为可选属性:

export interface ITypeTestProps<TData> {
    data?: TData;
}