Search code examples
typescriptunion-types

TS: Pass Union Type To Function That Accepts Subtype


// Example Code: 

type Type1 = {
  a: string;
};

type Type2 = {
  a: string;
  b: number;
};

type Type3 = {
  a: string;
  b: string;
  c: string;
  d: object;
};

type Types = Type1 | Type2 | Type3;

function getType(thing: Types) {
// ...
}

function processByType(thingsToProcess: Types) {
  if (getType(thingsToProcess) === "type1") {
    processType1(thingsToProcess);
  } else if (getType(thingsToProcess) === "type2") {
    processType2(thingsToProcess);
  } else if (getType(thingsToProcess) === "type3") {
    processType3(thingsToProcess);
  } else {
    throw Error("Unknown type");
  }
}

function processType1(t: Type1) {}
function processType2(t: Type2) {}
function processType3(t: Type3) {}

In the above code, ts wont let me pass an object of Type to any function but processType1 since Type1 has attributes in common with the rest.

How can I change my code to make this setup work?


Solution

  • Instead of having if (getType(thingsToProcess) === "type1") {, perform the comparison inside the function so that the function can be used as a type guard.

    // example implementation
    function isType<T extends Types>(thing: Types, a: string): thing is T {
        return thing.a === a;
    }
    
    function processByType(thingsToProcess: Types) {
      if (isType<Type1>(thingsToProcess, "type1")) {
        processType1(thingsToProcess);
      if (isType<Type2>(thingsToProcess, "type2")) {
        processType2(thingsToProcess);
      if (isType<Type3>(thingsToProcess, "type3")) {
        processType3(thingsToProcess);
      } else {
        throw Error("Unknown type");
      }
    }