[英]React HOC and TypeScript 3.2
由於 TypeScript 在 v3.2 中改進了它的 JSX 類型檢查,我們現在在正確輸入 HOC 時遇到了問題。
有人可以為 TypeScript 3.2 修復以下 HOC 中的類型嗎?
import { ComponentType } from 'react';
type Props = { custom: string };
type Omit<T, K extends string> = Pick<T, Exclude<keyof T, K>>;
function hoc<P extends Props>(Component: ComponentType<P>) {
return (props: Omit<P, keyof Props>) => {
return <Component {...props} custom="text" />;
}
}
TypeScript 錯誤:
Type '{ custom: string; }' is not assignable to type 'IntrinsicAttributes & P & { children?: ReactNode; }'.
Property 'custom' does not exist on type 'IntrinsicAttributes & P & { children?: ReactNode; }'
基本上,這個想法是將需要“自定義”屬性的組件轉換為不再需要它的組件,因為它將由 HOC 自動注入。
編輯:可能是同一個問題: https://github.com/Microsoft/TypeScript/issues/28748
我確定這不是你希望的答案,但是你可以通過將內部函數中的props
類型更改為any
來使其工作,並將Omit
類型放在外部函數的返回類型注釋中,如這個:
function hoc<P extends Props>(Component: ComponentType<P>): ComponentType<Omit<P, keyof Props>> {
return (props: any) => {
return <Component {...props} custom="text" />;
}
}
這是一個支持轉發引用的 HoC 以及一個玩笑測試。
只有一個as
那是我將輸入道具轉換為包裝組件使用的道具的部分,因為它們可以不同。
請注意T
可以是任意的,因為 React-Native 與 React JS 在如何提供構造函數方面有所不同。 ReactElement 中的“T”類型參數是什么? 是關於T
是什么的相關問題。
import { render } from '@testing-library/react-native';
import { ComponentType, forwardRef, NamedExoticComponent, PropsWithoutRef, ReactElement, Ref, RefAttributes, useEffect, useRef } from 'react';
import { Text, TextProps } from 'react-native';
/**
* This is a simple HoC that is a noop that supports ref forwarding.
* @param Component component to wrap
* @param options options for the HoC building
* @typeParam P the exposed props of the higher order component
* @typeParam Q the props for the wrapped component
* @typeParam T type for ref attribute of the wrapped component
* @typeParam O options for the HoC building
* @returns A named exotic componentwith P props that accepts a ref
*/
function hoc<P, Q, T, O = {}>(Component: ComponentType<Q>, options?: O): NamedExoticComponent<PropsWithoutRef<P> & RefAttributes<T>> {
function wrapped(props: P, ref: Ref<T>): ReactElement<Q> {
// the an unknown as Q here is an example, but P and Q can be different.
const componentProps: Q = props as unknown as Q;
return <Component {...componentProps} ref={ref} />
}
const displayName =
Component.displayName || Component.name || "AnonymousComponent";
wrapped.displayName = displayName;
return forwardRef(wrapped);
}
describe("hoc", () => {
it("should work with text", () => {
const HocText = hoc<TextProps, TextProps, Text>(Text);
const { toJSON } = render(<HocText>simple string</HocText>);
const { toJSON: expectedToJSON } = render(<Text>simple string</Text>)
expect(toJSON()).toStrictEqual(expectedToJSON())
});
it("should pass ref for text", () => {
const callback = jest.fn();
const HocText = hoc<TextProps, TextProps, Text>(Text);
function MyComponent() {
const textRef = useRef<Text>(null);
useEffect(() => {
callback(textRef?.current)
}, []);
return <HocText ref={textRef}>simple string</HocText>
}
const { toJSON } = render(<MyComponent />);
const { toJSON: expectedToJSON } = render(<Text>simple string</Text>)
expect(toJSON()).toStrictEqual(expectedToJSON())
expect(callback).toBeCalledTimes(1);
expect(callback.mock.calls[0][0]).toBeTruthy();
});
it("should work the same way with normal Text", () => {
const callback = jest.fn();
function MyComponent() {
const textRef = useRef<Text>(null);
useEffect(() => {
callback(textRef?.current)
}, []);
return <Text ref={textRef}>simple string</Text>
}
const { toJSON } = render(<MyComponent />);
const { toJSON: expectedToJSON } = render(<Text>simple string</Text>)
expect(toJSON()).toStrictEqual(expectedToJSON())
expect(callback).toBeCalledTimes(1);
expect(callback.mock.calls[0][0]).toBeTruthy();
});
});
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.