Search code examples
typescriptunion-typesmapped-typesconditional-types

Capture the type of an array so we can map it into an array of union types


class Custom1 { }

class Custom2 { }

class Custom3 { }

class Custom4 { }

class Foo { 
  custom1s: Custom1[];
  custom2s: Custom2[];
  custom3: Custom3;
  custom4: Custom4;
}

type SomeMapping<T> = {
  [P in keyof T]
  : T[P] extends any[] ? object[]
  : (T[P] | object);
}

type FooMapped = SomeMapping<Foo>;

The actual typing is this:

type FooMapped = { 
  custom1s: object[]; 
  custom2s: object[]; 
  custom3: object | Custom3; 
  custom4: object | Custom4; 
}

What I would like this:

type FooMapped = { 
  custom1s: (object | Custom1)[]; 
  custom2s: (object | Custom2)[]; 
  custom3: object | Custom3; 
  custom4: object | Custom4; 
}

How do we capture the type of the array so we can turn it into a union?


Solution

  • To have type

    type FooMapped = { 
      custom1s: Custom1[]; 
      custom2s: Custom2[]; 
      custom3: object | Custom3; 
      custom4: object | Custom4; 
    }
    

    you should do this

    type SomeMapping<T> = {
      [P in keyof T]
      : T[P] extends (infer U)[] ? U[]
      : (T[P] | object);
    }
    

    and to achieve this type

    type FooMapped = { 
      custom1s: (object | Custom1)[]; 
      custom2s: (object | Custom2)[]; 
      custom3: object | Custom3; 
      custom4: object | Custom4; 
    }
    

    do this

    type SomeMapping<T> = {
      [P in keyof T]
      : T[P] extends (infer U)[] ? (U | object)[]
      : (T[P] | object);
    }
    

    Reference: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html (section "Conditional types")