Hyster
Hyster

Reputation: 726

Complex type resolution in Typescript

I have a very complex type defined in my Typescript:

export type DraftCamp = DeepPartial<CampForm> & {
  isActive: false
} & FilesExtension

Which actually is just an interface with some nested values - no unions. Is there anyway to take a peek into this type and see how it actually looks like? Can I do this without manually following all the other types it references?

Upvotes: 1

Views: 361

Answers (1)

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 250366

You can use an Id type that maps over the intersection. There is no guarantee as to what will expand out a mapped type, but this type currently does the trick:

type Id<T> = {} & {
  [P in keyof T]: Id<T[P]>
}

Using Id on an intersection will flatten it out:

type FilesExtension = {
  ext: string
}

// Naive implementation, just filler
type DeepPartial<T> = {
  [P in keyof T]?: DeepPartial<T[P]>
}

type CampForm = {
  foo: {
    bar: string
  }
  baz: {
    bars: string[]
  }
}

type Id<T> = {} & {
  [P in keyof T]: Id<T[P]>
}
export type DraftCamp = Id<DeepPartial<CampForm> & {
  isActive: false
} & FilesExtension>
// Hover over DraftCamp and you will see the expanded version of it:
// type DraftCamp = {
//     foo?: {
//         bar?: string | undefined;
//     } | undefined;
//     baz?: {
//         bars?: (string | undefined)[] | undefined;
//     } | undefined;
//     isActive: false;
//     ext: string;
// }

Playground Link

Note: I have to warn you, there are some arcane assignability rules that differ between an intersection and a flattened out type with the same members, but it does mostly work the same. The idea is that Id is much like a console.log useful for debugging, but don't leave it lying around in production code

Upvotes: 3

Related Questions