简体   繁体   中英

Using props.children and styled-component "as" prop with typescript

I've looked through several existing solutions and posts and couldn't really find any solution.

So, I'm using React with Typescript and styled-component.

One part of my project is the Heading component. Ideally, I imagined to used it like <Heading level={2}>Hello world!</Heading> wherever I need it.

Here is the simplified Codesandbox Code of it

However, the <S.Heading throws Errors in my Linter, even though it seems to work visually speaking.

Error

This JSX tag's 'children' prop expects type 'never' which requires multiple children, but only a single child was provided.ts(2745)

No overload matches this call. This JSX tag's 'children' prop expects type 'never' which requires multiple children, but only a single child was provided.ts(2769)

Not sure what's wrong about my code since I think I followed most recommendations..

Typescript template literal types are not as smart as you might think. You might expect h${props.level} to evaluate to a union type "h1" | "h2" |... "h1" | "h2" |... based on the type of your props.level variable. Instead it is just string . So you will need an as assertion somewhere in your code in order to declare that this string is a valid key of JSX.IntrinsicElements .

Getting the union "h1" | "h2" |... "h1" | "h2" |... as a type is tough because Props['level'] is a union of number literals rather than string literals. But we don't really need the union because t doesn't really matter which heading type it is. You can use as "h1" and you'll be fine.

export default function Heading(props: Props) {
  return <S.Heading as={`h${props.level}` as "h1"}>{props.children}</S.Heading>;
}

Out of curiosity I wanted to see if I could extract the valid h* tags from JSX.IntrinsicElements . I came up with a solution that almost works based on string length, but I forgot about hr !

type HTag = {
    [K in keyof JSX.IntrinsicElements]: K extends `h${string}${infer B}` ? B extends "" ? K : never : never
}[keyof JSX.IntrinsicElements]

evaluates to:

"h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "hr"

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM