Home > Mobile >  How typing a selected object from a list of different objects?
How typing a selected object from a list of different objects?

Time:12-03

I have an object that is going to have field products, this field will be filled with the response returned by different endpoints which each return a type of product. something like:

const products = {
  // each of this kind of products comes from endpoint response
  someProduct: {},
  someOtherProduct: {}
  anotherProduct: {}
}

I Can type all product types like this, according this answer:

interface BaseProduct {
  name: string;
  description: string;
  price: number;
  type: string;
}

interface SomeProduct extends BaseProduct {
  genericAttrOne: string;
  genericAttrTwo: string;
}

interface OtherProduct extends BaseProduct {
  anAttributeOne: string;
  anAttributeTwo: string;
}

interface AnotherProduct extends BaseProduct {
  anotherAttributeOne: string;
  anotherAttributeTwo: string;
}

type Product = SomeProduct | OtherProduct | AnotherProduct;

const productsAsArray: Product[] = [];

the situation here is that sometimes I will go through all the product types(productsAsArray), and I will render it, then user click on some product and I take it as the productSelected. how should I type this productSelected if it can be of any type of product? and for this selectedProduct I will access product-specific properties...

CodePudding user response:

Use discriminated unions to help you narrow your type down.

Here is an example:

interface Base {
  type: string;
  baseProp: string;
}

interface T1 extends Base {
  type: "t1";
  t1prop: string;
}

interface T2 extends Base {
  type: "t2";
  t2prop: string;
}

interface T3 extends Base {
  type: "t3";
  t3prop: string;
}

type union = T1 | T2 | T3;

function list(arr: union[]) {
  const randomArrItem = arr[Math.floor(Math.random() * arr.length)];
  specificMethod(randomArrItem);
}

function specificMethod(t: union) {
  const { type } = t;
  switch (type) {
    case "t1":
      console.log(t.t1prop);
      // console.log(t.t2prop); // error: Property 't2prop' does not exist on type 'T1'. Did you mean 't1prop'?(2551)
      break;
    case "t2":
      console.log(t.t2prop);
      break;
    case "t3":
      console.log(t.t3prop);
      break;
    default:
      throw new Error("wrong type");
  }
}

See TS Playground: https://tsplay.dev/wj4obm

CodePudding user response:

Since they have the same signature, add a new property type that is an enum.

The reason to use an enum is that you can check it with an if or switch case.

const enum ProductType {
  one = "ONE",
  two= "TWO",
  three= "THREE",
}

interface BaseProduct {
  name: string;
  description: string;
  price: number;
}

type ProductOne = BaseProduct & {
  type: ProductType.one,
  prop1: string,
  prop2: string
}

type ProductTwo = BaseProduct & {
  type: ProductType.two,
  prop1: string,
  prop2: string
}

type ProductThree = BaseProduct & {
  type: ProductType.three,
  prop1: string,
  prop2: string
}

type Product = ProductOne | ProductTwo | ProductThree ;

function handleProductSwitch(product: Product){
  switch(product.type){
    case ProductType.one:
      // handle ProductOne
    case ProductType.two:
      // handle ProductTwo
    case ProductType.three:
      // handle ProductThree
    case default:
  }
}

function handleProductIf(product: Product){
  if(product.type === ProductType.one) productOneHandler(product);
  if(product.type === ProductType.two) productTwoHandler(product);
  if(product.type === ProductType.three) productThreeHandler(product);
}
  • Related