从情感风格的组件中省略特定的道具?

Omit specific prop from an emotion styled component?

我有一个 BoxWithAs 组件,定义如下:

const BoxWithAs = styled.div(
  {
    WebkitFontSmoothing: 'antialiased',
    MozOsxFontSmoothing: 'grayscale'
    // And more …
  }
);

很好,但现在我想弃用来自 @emotion/styled 的默认道具之一,特别是 as 道具。

我这样做了:

type BoxWithAsType = typeof BoxWithAs;
type BoxProps = Omit<React.ComponentProps<BoxWithAsType>, 'as'>;

/**
 * Component that does it all.
 */
const Box = (props: BoxProps) => {
  return <BoxWithAs {...props}>{props.children}</BoxWithAs>;
};

它确实删除了道具...

...但现在组件本身丢失了所有 StyledComponent 类型信息。

我如何构建它才能实现两者?我的最终目标是弃用 as 道具,而是鼓励使用 .withComponent(出于 Typescript 原因)。

如果我们将鼠标悬停在 BoxWithAs 上,我们会看到它属于这种类型:

StyledComponent<{
    theme?: Theme | undefined;
    as?: React.ElementType<any> | undefined;
}, React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {}>

所以你可以这样做:

type BoxWithoutAs = StyledComponent<{
    theme?: Theme | undefined;
}, React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {}>;

const Box = BoxWithAs as BoxWithoutAs;

但是那种真的又长又笨重。我们尝试简化它并使它更干燥:

StyledComponent<Omit<React.ComponentProps<BoxWithAsType>, "as">, React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {}>

这并没有好多少,而且可以说更糟。如果我们可以推断出其他两个参数而不是让我们输入完整的参数,那将会有所帮助。

我们可以使用辅助实用程序类型:

type OmitProps<Component, Props extends PropertyKey> = Component extends StyledComponent<infer P, infer S, infer J> ? StyledComponent<Omit<P, Props>, S, J> : never;

现在,TypeScript 会为我们推断出其他两个参数,我们可以使用 Omit<P, Props> 来省略我们希望的任何道具。

const Box = BoxWithAs as OmitProps<BoxWithAsType, "as">;

似乎工作正常!

Playground