1

I have a problem with more advanced Generic types in TypeScript.

What I want to do is an array of data where the data itself controlled by the type like:

[
 {
  type: "T1",
  content: number,
 },
 {
  type: "T2",
  values: {
   id: number,
   ...
  }
 }
]

I kinda get stacked after describing the available types like:

enum DataType {
 T1 = "t1",
 T2 = "t2"
}

So the result must look kinda like this, I guess:

interface DataGeneric<T> {
 [T extends DataType.T1]: { content: number },
 [T extends DataType.T2]: { values: { id: number, ... } },
} ???

interface Data<T extends DataType = any(?)> extends DataGeneric<T>{
 type: DataType,
 // and all the other fields are generic from T = DataType
}
const someData: Data[] | undefined = fetchData();

// suggesting that the `type` of element[1] is "t2"
// and VSCode suggestions works correctly too,
// consider that there is an object-field `values` with `id` key
someData[1].values.id 

Thanks in advance!

3
  • 2
    Have you considered a discriminated union instead of a generic? See typescriptlang.org/docs/handbook/… Commented Dec 19, 2021 at 21:16
  • 1
    It definitely looks like you want a discriminated union instead of generic, like this. If that code meets your needs I could maybe write up an answer. If not, please let me know what's missing. Commented Dec 19, 2021 at 22:43
  • @jcalz Yes, it is! Thanks a lot! Commented Dec 20, 2021 at 0:38

1 Answer 1

1

If you're checking an object's type property against a string or number literal to discriminate what type of data the rest of the object is holding, then you probably want to use a discriminated union instead of generics. That's basically a union type where the members of the union have a common discriminant key. In your case it could look like this:

enum DataType {
  T1 = "t1",
  T2 = "t2"
}

type Data =
  { type: DataType.T1, content: number } |
  { type: DataType.T2, values: { id: number } }

Then when you have a value data of type Data, you can check its type property and the compiler knows that it should narrow data to the right member of the union:

declare const someData: Data[] | undefined;

if (someData) {
  someData.forEach(data => {
    if (data.type === DataType.T1) {
      data.content.toFixed();
    } else {
      data.values.id.toFixed();
    }
  })
}

Playground link to code

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.