2

There is a question on SO about creating an array with different types, but I want to create an array with multiple complex types. The answer in the linked to question recommends using a union type, but I don't think that will suffice for a complex type, as typescript documentation says

If we have a value that has a union type, we can only access members that are common to all types in the union. 

I want to create an array of Reports. However some of the reports have different properties from each other, and also several in common. I'm worried if I create it as below then somewhere in the code I might not be able to access the different properties on the subreports.

What's the recommended way to create an array of complex types in Typescript?

interface Reports extends Array<Report>{}

interface Report {
    id: number; 
    timestamp: number;
    type: string;
    subreport: SubReportA | SubReportB | SubReportC
}



interface SubReportA {
values: []
}
interface SubReportB {
random_property: number;
other_random_name: number;
}
interface SubReportC{
values: [];
name: string;
}
4
  • Shouldn't SubReportA etc. be subclasses of SubReport, and then you just have subreport: Subreport? Commented Jun 22, 2017 at 17:11
  • Can you give an example on how you want to use your array? Commented Jun 22, 2017 at 17:15
  • @RodrigoPedrosa map over it and render each member in a Report component inside a list. Commented Jun 22, 2017 at 17:52
  • @torazaburo maybe that would also be a solution. I'll look into it stackoverflow.com/questions/41611737/… Commented Jun 22, 2017 at 17:53

1 Answer 1

3

That would be a use case for discriminated unions. First, we need a base interface for all kinds of sub-reports. I will also be adding a discriminating field kind that can only assume specific values known in compile time "A", "B" and "C".

interface SubReport {
    kind: "A" | "B" | "C";
}

At this point, we can make our interfaces specify one string literal each:

interface SubReportA {
  kind: "A";
  values: []
}

interface SubReportB {
  kind: "B";
  random_property: number;
  other_random_name: number;
}

interface SubReportC{
  kind: "C";
  values: [];
  name: string;
}

The same reasoning could be applied to the original Report type if need be. I'm not sure whether the report's "type" field is supposed to be a discriminator, but it can be moved to the subreport object if it is.

Also, as explained in the link above, discriminated unions allow you to retrieve specific fields once you test on the discriminator.

if (subreport.kind === 'B') {
  console.log(subreport.random_property);
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.