首页 > 解决方案 > 将类名注入样式化组件时的输入

问题描述

请帮我修正我的打字错误。

我想将类名注入到样式化的组件中。我做了这个功能:

type IntrinsicElementsKeys = keyof { div: any, a: any } /* could be keyof JSX.IntrinsicElements */

export function elementWithClass(e: IntrinsicElementsKeys, customClassName: string) {
    /* [2] if I don't force the type ts does not allow me to call se.attrs() */
    const se = styled[e] as ThemedStyledFunction<typeof e, any>
    
    const res = se.attrs(props => ({
        className: customClassName + " " + (props.className || "")
    }))``

    /* [1] if I don't force "any" then I cannot use native props such as "href" */
    return res as any;
}

我想摆脱 [1] 处的“任何”,但如果我这样做并调用组件如下:

const Link = elementWithClass("a", "rick-roll")

const MyElement: React.FC<{ /* props */ }> = props => <Link href="http://rick-roll.com">rick</Link>

然后 TS 抱怨“href”是一个未知的道具。

所以我的问题是:我如何修复我的打字?

注 1:如果我删除 [2] 处的“as”,那么 TS 会抱怨

Each member of the union type '(<U, NewA extends Partial<Pick<DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "key" | keyof HTMLAttributes<...>> & { ...; } & U> & { ...; } = {}>(attrs: Attrs<...>) => ThemedStyledFunction<...>) | (<U, NewA extends Partial<...> & { ...; } = {}>(attrs: Attrs<...>) => ThemedStyledFunction<...>)' has signatures, but none of those signatures are compatible with each other.

注意 2:这个问题类似于将 tailwind 类用于样式组件 ,但更具体地说明了如何使用我使用的特定方法来修复打字。

标签: reactjstypescriptstyled-components

解决方案


因此,您首先应该考虑的是,如果您希望返回类型根据输入而有所不同,那么您很可能应该包括 generics

所以,让我们解决这个问题!

type IntrinsicElementsKeys = "div" | "a"; /* could be keyof JSX.IntrinsicElements */

// 1st step, let's introduce the generic inside the function
export function elementWithClass<T extends IntrinsicElementsKeys>(e: T, customClassName: string) {

// 2nd step, let's pass it in ThemedStyledFunction
    const se = styled[e] as ThemedStyledFunction<T, any>;

// 3rd step, pass in the generic into the `attrs` function
    const res = se.attrs<T>(props => ({
        className: customClassName + " " + (props.className || "")
    }))``

    /* [1] if I don't force "any" then I cannot use native props such as "href" */
    return res;
}

const Link = elementWithClass("a", "rick-roll")
const MyElement: React.FC<{ /* props */ }> = props => <Link href="http://rick-roll.com">rick</Link> // all good

const Link1 = elementWithClass("div", "rick-roll")
const MyElement1: React.FC<{ /* props */ }> = props => <Link1 href="http://rick-roll.com">rick</Link1> // error

只要按照下面的步骤,道具类型就可以推断出来了!

  1. 引入一个泛型来接收元素;
  2. 将泛型添加到ThemedStyledFunction;
  3. 将泛型添加到attrs函数中;

这是一个游乐场链接,您也可以用来玩耍。


推荐阅读