![](/img/trans.png)
[英]Why typescript does not ensure type safety in a generic higher order component that adds additional properties in React?
[英]React & Typescript: Intersection type with Higher Order Control & Generic Type
當我在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
看起來有點withTestData
費解,但是它做起來相當簡單-它需要一個期望類型為P & ITypeTestProps<TData>
道具的組件,並將其包裝在一個期望類型為P
道具的組件中。 在此測試用例中, P
是ITestComponentProps
。
這是有錯誤的版本:
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>
編輯
這是一個符合我預期的版本-從生成的界面中刪除“數據”。 唯一的區別是類型不是通用的。
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
錯誤已正確警告您錯過了為ITypeTestProps
接口的必需屬性提供值的ITypeTestProps
。
因此,為了解決該問題(如果您的業務邏輯可以沒有問題),可以在ITypeTestProps
接口ITypeTestProps
data
聲明為可選屬性:
export interface ITypeTestProps<TData> {
data?: TData;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.