网站搜索

javascript - 在 TypeScript 中使用 styled-components 的 'as' 多态属性


我正在尝试实现一个 Typography React 组件。
如你所见,我将 variant 作为输入属性,并将其用作 VariantsMap 对象的索引来获取对应的 HTML 标签名。

然后我使用 styled-components 的 'as' 多态属性将其渲染为所选的 HTML 标签。

但是我一直收到这个错误:
没有匹配此调用的重载。重载 1(共 2 个)‘(props: Omit<Omit<Pick<DetailedHTMLProps<HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, "key" | keyof HTMLAttributes<...>> & { ...; } & { ...; }, never> & Partial<...>, "theme"> & { ...; } & { ...; }): ReactElement<...>’,产生以下错误:类型 ‘string’ 不能赋值给类型 ‘undefined’。

我在 @types/styled-component 中发现,'as' 属性的类型可以是 'never | undefined',而我的 variantsMap 返回的是 string 类型。
但我真的想把这个 'as' 属性和我的特定变体 HTML 标签选择功能一起使用。

有什么办法解决这个问题吗?

const variantMap = {
  h1: 'h1',
  h2: 'h2',
  h3: 'h3',
  h4: 'h4',
  h5: 'h5',
  h6: 'h6',
  subheading1: 'h6',
  subheading2: 'h6',
  body1: 'p',
  body2: 'p',
};

export const Typography = ({ variant : string }) => { 

      const selectedComponent = variantMap[variant];

      return (<TypographyRoot
        as={selectedComponent}
        variant={variant}
        {...props}
      >
        {children}
      </TypographyRoot>);
}

答案#1

首先,export const Typography=({ variant : string }) => {} 是无效的语法。

你只是将解构的 variant 的名称改为 string。你没有提供类型。

即使像这里 export const Typography=({ variant }:{variant: string}) => {} 使用有效的 string 类型,你仍然会遇到错误,原因是 variantMap 期望的键是 h1 | 'h2' | 'h3' ... 这样的键,而 string 的范围要宽得多。我敢打赌,你不想把 foo 字符串赋值给 variant 属性。

为了解决它,你只需使 variantMap 不可变,并对 variantMap 应用适当的约束:

import React from 'react'
import styled from "styled-components";

const Div = styled.div`
  color: red;
`;

const VariantMap = {
  h1: 'h1',
  h2: 'h2',
  h3: 'h3',
  h4: 'h4',
  h5: 'h5',
  h6: 'h6',
  subheading1: 'h6',
  subheading2: 'h6',
  body1: 'p',
  body2: 'p',
} as const;

type Props = {
  variant: keyof typeof VariantMap
}
export const Typography = ({ variant }: Props) => {

  const selectedComponent = VariantMap[variant];

  return <Div
    as={selectedComponent}
  />
}

现在 styled-component 很开心。

操场


将地图设为不可变拯救了我。你能解释一下为什么不将地图设为不可变会让 Typescript 抱怨吗?

没有 as const 时,VariantMap 的所有值都会被推断为 string,而不是字面量 "h1", "h2"。这反过来会影响 selectedComponent,因为这个 const 表示 VariantMap 的一个值。我的意思是,selectedComponent 变成了普通的 string,而不是字符串字面量,而 as 属性则需要严格的字符串字面量 h1, h2, h3, ...。