#Generic with constraints not working with multiple types

14 messages · Page 1 of 1 (latest)

rustic jackal
#

So, I have two situations in which a component needs a different type for each usage.

So, I have the base component...

const MyComponent = <T extends TypeA | TypeB,>({items}: {items: T[]}) => {

  return (
    <div>
      {items?.map((item: T) => {
        return (
          <div>
            /* Depending on the object, we get the value two different ways */
            /*
               THIS IS THE LINE THAT ERRORS... "sku.name" and "name.
               Basically its saying the one value doesn't exist on the other object.
            */
            <div className={nameClass}>{item.sku?.name || item.name}</div>
          </div>
        );
      })}
    </div>

And I use it like so:

          <MyComponent<TypeA> items={[items]} />

And the other

          <MyComponent<TypeB> items={[itemsWithTypeBShape]} />

I also tried "TypeA & TypeB", but then the error appears here: <MyComponent<TypeA> items={[items]} /> in the TypeA area.

solar heron
#

You need some sort of type guard to figure out whether the item is a TypeA or TypeB

rare grove
rustic jackal
#

That still doesn't work, I am left with this:

 Property 'name' does not exist on type 'TypeA | TypeB'.   Property 'name' does not exist on type 'TypeA'.

#

It's as if no matter which key I try to access, it will error because it can't determine what object type its contrained to.

solar heron
#

Post more info then. What is TypeA and TypeB

rare grove
#

what are the definitions

rustic jackal
#

a much reduced types are:

TypeA

export type TypeA = {
  partner: Partner;
  name: string;
};

TypeB

export type TypeB = {
  id: number | string;
  sku?: {
    id: number;
    name: string;
  };
};

solar heron
#

Something like this

burnt kiteBOT
#
evan.trimboli#6544

Preview:```ts
interface Partner {}

export type TypeA = {
partner: Partner
name: string
}

export type TypeB = {
id: number | string
sku?: {
id: number
name: string
}
}

const doSomething = (o: TypeA | TypeB) => {
if ("id" in o) {
console.log(o.sku?.name)
} else {
console.log(o.partner)
}
}```

rustic jackal
#

I get what ur going for - but its weird that TS can't infer the type even though I am passing it thru as a generic.

brazen garnet
#

TS is just JS with types, so putting aside TS and generic even if they know which call corresponds to which type, the JS code doesn't and you still need to do a runtime check.

verbal pilot
#

@rustic jackal Generics don't narrow the way you might expect, T extends ItemA | ItemB doesn't narrow the same way as ItemA | ItemB as a simple type would.

#

ItemA | ItemB is a constraint on T, but that's not the exact type of T - it could actually be something more exotic like:

type TypeASubtype = TypeA & {
  sku: "whatever"
}

// This is valid - it extends TypeA - but it's going to confuse the `item.sku` logic
const Example = MyComponent<TypeASubtype>({items: []});