Reactjs TypeScript中的联合类型道具&;反应

Reactjs TypeScript中的联合类型道具&;反应,reactjs,typescript,Reactjs,Typescript,我有一个带有道具的组件,我想将其限制在字符串的选择范围内,因此我使用联合类型,如下所示: 类型HeadingProps={ 级别?:“h1”|“h2”|“h3”|“h4”|“h5”|“h6” } 常量标题:React.FC=({子级,级别='h2'})=>{ 返回 } 当我这样使用它时,它很好用 你好,世界! 但如果我尝试将其与数组一起使用,则会出现错误: {['h1',h2',h3',h4',h5',h6'].map((级别:string)=>( {level} )} 类型“string

我有一个带有道具的组件,我想将其限制在字符串的选择范围内,因此我使用联合类型,如下所示:

类型HeadingProps={
级别?:“h1”|“h2”|“h3”|“h4”|“h5”|“h6”
}
常量标题:React.FC=({子级,级别='h2'})=>{
返回
}
当我这样使用它时,它很好用

你好,世界!
但如果我尝试将其与数组一起使用,则会出现错误:

{['h1',h2',h3',h4',h5',h6'].map((级别:string)=>(
{level}
)}
类型“string”不可分配给类型“h1”|“h2”|“h3”|“h4”|“h5”|“h6”|未定义”。ts(2322)

我如何拥有道具的类型,以便只有这些字符串是有效的,但当组件在上面这样的数组中使用时,允许传递有效的字符串值

编辑 以下是类型当前的工作方式:

export const HeadingLevels={
h1:`h1`,
h2:`h2`,
h3:`h3`,
h4:`h4`,
h5:`h5`,
h6:`h6`,
}
导出类型级别=标题级别类型的键
类型HeadingProps=BoxProps&{
级别?:级别
}

['h1',h2',h3',h4',h5',h6']
被编译器推断为类型
字符串[]
,因为这通常是正确的操作,如

const arr = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6']; // inferred as string[]
arr.push("h7"); // okay
但是在您的例子中,您希望编译器知道该数组的内容是并且将永远是(只要您使用它),您设置的特定内容

从TypeScript 3.4开始,处理此问题的最简单方法是使用a来告诉编译器您的数组是用来读取特定字符串文字的:

(['h1', 'h2', 'h3', 'h4', 'h5', 'h6'] as const).map((level) => (
    <Heading level={level}>{level}</Heading>
))
(['h1','h2','h3','h4','h5','h6']作为常量)。映射((级别)=>(
{level}
))
这应该可以正常工作。请注意,我已从
级别
中删除了类型注释。您不希望将
级别
扩展到
字符串
,因为这样编译器就不能再确定它是否合适了。相反,让编译器推断
级别
的类型,它将根据您的联合
h1”|“h2”执行此操作|…|“h6”
,根据需要

好吧,希望能有帮助,祝你好运


['h1',h2',h3',h4',h5',h6']
被编译器推断为类型
字符串[]
,因为这通常是正确的操作,如

const arr = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6']; // inferred as string[]
arr.push("h7"); // okay
但是在您的例子中,您希望编译器知道该数组的内容是并且将永远是(只要您使用它),您设置的特定内容

从TypeScript 3.4开始,处理此问题的最简单方法是使用a来告诉编译器您的数组是用来读取特定字符串文字的:

(['h1', 'h2', 'h3', 'h4', 'h5', 'h6'] as const).map((level) => (
    <Heading level={level}>{level}</Heading>
))
(['h1','h2','h3','h4','h5','h6']作为常量)。映射((级别)=>(
{level}
))
这应该可以正常工作。请注意,我已从
级别
中删除了类型注释。您不希望将
级别
扩展到
字符串
,因为这样编译器就不能再确定它是否合适了。相反,让编译器推断
级别
的类型,它将根据您的联合
h1”|“h2”执行此操作|…|“h6”
,根据需要

好吧,希望能有帮助,祝你好运


如果拆分这些类型,可以使用union type(级别)注释映射函数的
level
参数,如下所示:

type Level = 'h1' | 'h2' | 'h3' | 'h4'| 'h5' | 'h6'
type HeadingProps = {
    level?: Level
}

const Heading: React.FC<HeadingProps> = ({children, level = 'h2'}) => {
    return <Box as={level} />
}

{['h1', 'h2', 'h3', 'h4', 'h5', 'h6'].map((level: Level) => (
    <Heading level={level}>{level}</Heading>
))}
类型级别='h1'|'h2'|'h3'|'h4'|'h5'|'h6'
类型HeadingProps={
级别?:级别
}
常量标题:React.FC=({子级,级别='h2'})=>{
返回
}
{['h1','h2','h3','h4','h5','h6'].map((级别:级别)=>(
{level}
))}

如果拆分这些类型,可以使用union type(级别)注释映射函数的
level
参数,如下所示:

type Level = 'h1' | 'h2' | 'h3' | 'h4'| 'h5' | 'h6'
type HeadingProps = {
    level?: Level
}

const Heading: React.FC<HeadingProps> = ({children, level = 'h2'}) => {
    return <Box as={level} />
}

{['h1', 'h2', 'h3', 'h4', 'h5', 'h6'].map((level: Level) => (
    <Heading level={level}>{level}</Heading>
))}
类型级别='h1'|'h2'|'h3'|'h4'|'h5'|'h6'
类型HeadingProps={
级别?:级别
}
常量标题:React.FC=({子级,级别='h2'})=>{
返回
}
{['h1','h2','h3','h4','h5','h6'].map((级别:级别)=>(
{level}
))}

如果将
level:string
替换为
level:HeadingProps.level
,会发生什么?如果将
level:string
替换为
level:HeadingProps.level
,会发生什么?啊,太棒了,是的。我已经尝试过了,但没有从
level
删除类型注释。非常感谢@jcalz:+1:ah fantastic、 是的,这很有效。我试过了,但没有从
级别
删除类型注释。非常感谢@jcalz:+1:是的,我以前有过,但我不希望使用组件的代码必须导入
级别
类型,只是为了在组件中传递字符串。当然,对于字符串和数字之类的原语at可能不是必需的。但是,请记住,如果您偶然发现更复杂的联合(如其他类型的联合),
as const
不会起作用。是的,我以前有过这种情况,但我不希望使用组件的代码必须导入
级别
类型才能在组件中传递字符串。当然,对于可能不需要的字符串和数字等基本体。但是,请记住,如果您偶然发现mor复杂的并集(像其他类型的并集一样),
as const
在这里不会起作用。