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, ...。
