如何使用打字稿为HOC编写通用类型?

时间:2019-07-28 12:44:42

标签: typescript typescript-generics

我正在为现有的UI库编写类型,该UI库具有一个Base组件,该组件以Element作为字符串,并执行<Element {...props} 正确的输入方式是什么?

我尝试使用

编写泛型类型
type AllTypes = HTMLProps<HTMLDivElement> | HTMLProps<HTMLInputElement> // ... And other HTML element types
type BaseTypes <T extends AllTypes> = {
    Element: string;
    props: T;
    className?: string;
    baseClassName?: string;
}


export const BaseComponent = <T extends AllTypes>({
    Element = "div",
    baseClassName,
    className,
    ...props
}: BaseTypes<T> ) => {
    const classNames = [];

    if (baseClassName) {
        classNames.push(baseClassName);
    }
    if (className) {
        classNames.push(className);
    }



    return (
        <Element 
            className={classNames.join(' ')}
            {...props }
        />
    )
}

在另一端

type newType = {
    Element: string;
    props: HTMLProps<HTMLInputElement>,
    className?: string;
    baseClassName?:string;
}

const InputField = (props: newType): ReactElement => {
    return (
        <BaseComponent<HTMLProps<HTMLInputElement>>
            Element="input"
            baseClassName="ff-input"
            {...props}
        />
    );
};

export default InputField;

我遇到错误,例如无法将{className:string}分配给IntrinsicAttributes。

我想知道键入BaseComponent的正确方法,以便根据Element值确定道具类型。任何建议将不胜感激。

1 个答案:

答案 0 :(得分:1)

对于JSX,您不能仅将纯字符串用作Element。如果您想使用字符串,则可以交换执行此操作...

React.createElement(Element, { ...props, className: classNames.join(' ') }, null);

或者,您可以将Element的类型修改为ElementType<any>,例如...

import * as React from 'react';
import { HTMLProps, ReactElement, ElementType } from 'react';

export type BaseProps = {
    Element: ElementType<any>;
    className?: string;
    baseClassName?: string;
}

export const BaseComponent = <T extends {}>({
    Element = "div",
    baseClassName,
    className,
    ...props
}: T & BaseProps) => {
    const classNames = [];

    if (baseClassName) {
        classNames.push(baseClassName);
    }
    if (className) {
        classNames.push(className);
    }

    return <Element { ...{...props, className: classNames.join(' ') } } />;
}

const InputField = (props: HTMLProps<HTMLInputElement>): ReactElement => {
    return (
        <BaseComponent<HTMLProps<HTMLInputElement>>
            Element="input"
            baseClassName="ff-input"
            {...props}
        />
    );
};

export default InputField;