#Property 'href' does not exist on type

1 messages · Page 1 of 1 (latest)

bitter yew
#

I'm trying to use discriminated unions to give my React component a dynamic Tag.
But I also need to edit the return in case of a specific tag. But I'm not able to do it; I'll share a minimum reproducible example of my types:

regal fiberBOT
#
mxswat#0

Preview:```ts
import React, {ElementType, ReactNode} from "react"

type TagPropsMap = {
a: JSX.IntrinsicElements["a"]
button: JSX.IntrinsicElements["button"]
}

type TagsUnionType = {
[K in keyof TagPropsMap]: TagPropsMap[K] & {
as: K
buttonType?: "primary" | "second
...```

bitter yew
#

Okay my colleague mentioned me that the issue is that when I was spreading props, it lost it's original type

Here a fixed version:

regal fiberBOT
#
mxswat#0

Preview:```ts
import React, {ElementType, ReactNode} from "react"

type TagPropsMap = {
a: JSX.IntrinsicElements["a"]
button: JSX.IntrinsicElements["button"]
}

type TagsUnionType = {
[K in keyof TagPropsMap]: TagPropsMap[K] & {
as: K
buttonType?: "primary" | "second
...```

regal fiberBOT
#
ascor8522#0

Preview:```ts
import React, {ElementType, ReactNode} from "react"

interface RoundedButtonBaseProps {
buttonType?: "primary" | "secondary"
semiActive?: boolean
}

interface RoundedButtonAProps
extends RoundedButtonBaseProps,
React.HTMLAttributes<HTMLAnchorElement>
...```

eager wave
#

this should be the exact samething, but is a bit cleaner imo

bitter yew
#

That's nice too, but I shared a minimal example.
And I'm actually moving away from that. Since I did not enjoy having 10+ interfaces lying around in my file. And I wanted a way to compress it.

eager wave
#

¯_(ツ)_/¯

#

sometimes it's better to have a more code that is easy to read than less code that is quite harder to read

#

but yeah, sounds like your component is doing a lot of different things then

#

which can sometimes be a sign of bad design

bitter yew
#

,I agree, some times it's better to have more code, but my use case is quite specific and I can't do much about it.

#

I do have one more question if you don't mind.

eager wave
#

sure

bitter yew
# regal fiber

Is there a way to make it so, that the as property has a default value and optional? in this 👆example?

eager wave
#

don't think so

#

you cannot defined default values in interfaces

#

so that would need to be done in the parameters definion or in the function body

bitter yew
#

I was trying to do something like this, but as is still required even when it's undefined

type TagPropsMap = {
  a: JSX.IntrinsicElements['a'] & { href: string };
  button: JSX.IntrinsicElements['button'];
  default: JSX.IntrinsicElements['button'];
  link: LinkProps;
};

type TagsUnionType = {
  [K in keyof TagPropsMap]: TagPropsMap[K] & {
    as: K extends `default` ? undefined : K;
    buttonType?: 'primary' | 'secondary';
    children: ReactNode;
    className?: string;
    semiActive?: boolean;
  };
}[keyof TagPropsMap];
eager wave
#

problem with doing that inside of the parameters definition is that you could provide attributes for one memeber of the enum, then adding the default value would make the whole object incoherent (like passing href a nd defaulting to <button>)

#

I was trying to do something like this, but as is still required even when it's undefined
undefined is different from optional

#

if you want to make it optional, use ?

bitter yew
#

Oh yeah, I need to use ? instead of just undefined 🤦‍♂️

eager wave
bitter yew
#

So, if I do

type TagsUnionType = {
  [K in keyof TagPropsMap]: TagPropsMap[K] & {
    as?: K extends `default` ? undefined : K;
    buttonType?: 'primary' | 'secondary';
    children: ReactNode;
    className?: string;
    semiActive?: boolean;
  };
}[keyof TagPropsMap];

The, component is not falling back to use the button type, and instead allows me to put any prop

eager wave
eager wave
#

¯_(ツ)_/¯

bitter yew
#

Well, I might have to do that 🤔

#

Thank you anyway, I'll look more into it 👍