Search code examples
typescriptcasting

Typescript: casting vs interception


Some coworkers use different method to convert item in Typescript, and I was curious about which method would be the best or the most conventional.

The case is that we have 2 classes A and B with the same parent, and a list with both types. Then when I pick an item I want to access a specific child attributes.

enum Type {
  A = "A",
  B = "B"
}
class Parent {
  type: Type
}
class A extends Parent {
  a: string
}
class B extends Parent {
  b: string
}

array: Parent[] = [...]

So option 1 would be to cast the parent after checking the type

getSpecificAttribute(item: Parent) {
  let result = null;
  switch(item.type) {
    case Type.A: const child = item as A; result = child.a; break;
    case Type.B: const child = item as B; result = child.b; break;
    default: break;
  }
  return result;
}

Option 2 is new to me, using intersection as the parameter type

getSpecificAttribute(item: A & B) {
  let result = null;
  switch(item.type) {
    case Type.A: result = item.a; break;
    case Type.B: result = item.b; break;
    default: break;
  }
  return result;
}

Or other option ?


Solution

  • By defining the type property on each class, no assertion is needed:

    TS Playground link

    enum Type {
      A = "A",
      B = "B",
    }
    
    class Parent {
      constructor (readonly type: Type) {}
    }
    
    class A extends Parent {
      readonly type = Type.A;
      a: string;
    
      constructor (str: string) {
        super(Type.A);
        this.a = str;
      }
    }
    
    class B extends Parent {
      readonly type = Type.B;
      b: string;
      
      constructor (str: string) {
        super(Type.B);
        this.b = str;
      }
    }
    
    function getSpecificAttribute (item: Parent): string | null {
      if (item instanceof A) return item.a;
      if (item instanceof B) return item.b;
      return null;
    }