簡體   English   中英

反應 HOC 和 TypeScript 3.2

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM