Search code examples
typescriptunion-types

TypeScript Union Type missing properties


I have 3 Types:

export type FooInitialStateType = {
  Id: string;
  Name: string;
  Email: string;
  Password: string
};

export type BarInitialStateType = {
  Id: string;
  Balance: number;
};

export type BazInitialStateType = {
  Id: string;
  Limit: number;
};

Which I then create a Union Type like so:

export type FooBarBazType = FooInitialStateType | BarInitialStateType | BazInitialStateType

I then have a generic method which processes arrays containing all 3 above Types:

  getFooBarBaz (
    events: FooBarBazType[]
  ): {
    foobarbaz0: FooBarBazType;
  } {
    const foobarbaz0 = <FooBarBazType>events[0];
    return {
      foobarbaz0
    };
  }

I then call this generic method from each class (foo, bar, baz):

    const {
      foobarbaz0
    }: {
      foobarbaz0: FooInitialStateType;
    } = this.getFooBarBaz(fooEvents);

I get a TS error:

Type 'FooBarBazType' is not assignable to type 'FooInitialStateType'.

Because FooInitialStateType doesn't contain properties from BarInitialStateType and BazInitialStateType.

Actual questions:

  1. How can I utilise the Union Type for the generic method to accept an array with all 3 Types, but then where I invoke the method, specify what exact Type the returned value should be?

  2. Is a Union Type the correct thing to use here? I have one method that accepts 3 different Types, and produces one Type. I need the invoking function to know, and specify, the returned Type


Solution

  • It's possible that you want getFooBarBaz() to be a generic function where the output type depends on the input type:

    function getFooBarBaz<T extends FooBarBazType>(events: T[]): { foobarbaz0: T; } {
        const foobarbaz0 = events[0];
        return {
            foobarbaz0
        };
    }
    

    Then it might behave the way you'd like:

    const fooEvents = [
        {
            Id: "foo",
            Name: "Foobert",
            Email: "[email protected]",
            Password: "Emb4rr4ss|ngP455w%?d"
        }
    ];
    
    const {
        foobarbaz0
    }: {
        foobarbaz0: FooInitialStateType;
    } = getFooBarBaz(fooEvents); // no error now
    

    Does that help? Good luck!

    Playground link to code