Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I see the full expanded contract of a Typescript type?

If I have a collection of types that looks a bit like this, only more verbose:

type ValidValues = string | number | null type ValidTypes = "text" | "time" | "unknown"  type Decorated = {   name?: string | null   type?: ValidTypes   value?: ValidValues   title: string   start: number }  type Injected = {   extras: object }  // overriding the types from Decorated type Text = Decorated & Injected & {   name: string   type: "text"   value: string } 

My actual code has more going on, but this shows the core idea. I don't want to have to trust myself to get the relationships between types just right. I want tooling to show me what the type definition for Text "evaluates" to, after all the type algebra.

So for the above example, I'm hoping the fields specified in Text will override the previous declarations made in the Decorated type, and the output of my hypothetical tooltip would (I hope) show me something like this:

{   name: string   type: "text"   value: string   title: string   start: number   extras: object } 

Is there any convenient way to get this information?

like image 537
suddjian Avatar asked Aug 27 '19 23:08

suddjian


People also ask

What is type guard in TypeScript?

A type guard is a TypeScript technique used to get information about the type of a variable, usually within a conditional block. Type guards are regular functions that return a boolean, taking a type and telling TypeScript if it can be narrowed down to something more specific.

What is type alias in TypeScript?

In Typescript, Type aliases give a type a new name. They are similar to interfaces in that they can be used to name primitives and any other kinds that you'd have to define by hand otherwise. Aliasing doesn't truly create a new type; instead, it gives that type a new name.

What is the extension of TypeScript program?

TypeScript is another file format that uses the . TS file extension. These are text files used to make JavaScript applications and are in fact similar to JavaScript (.


1 Answers

The quick info for a type displayed with IntelliSense often leaves something to be desired; you generally get a single representation for any given type, which may turn out to be too terse or even too verbose for your purposes. There are a few suggestions to make it more flexible (e.g., microsoft/TypeScript#25784 and microsoft/TypeScript#28508) so that users could expand/collapse type definitions in their IDEs. But I don't know if they will get acted on in the near or even far future, so let's not wait around for that.


Here is a type alias I sometimes use to try to expand a type in the way you're talking about:

// expands object types one level deep type Expand<T> = T extends infer O ? { [K in keyof O]: O[K] } : never;  // expands object types recursively type ExpandRecursively<T> = T extends object   ? T extends infer O ? { [K in keyof O]: ExpandRecursively<O[K]> } : never   : T; 

Those use conditional type inference to "copy" a type T into a new type variable O and then an identity-like mapped type which iterates through the copied type's properties.

The conditional type inference is conceptually a no-op, but it's used to distribute union types and to force the compiler to evaluate the "true" branch of the conditional (if you redefine Expand<T> without it, sometimes the compiler will just output the mapped type {[K in keyof RelevantType]: RelevantType[K]}, which is not what you want to see).

The difference between Expand and ExpandRecursively is whether it should just spit out the property types as-is (Expand), or if it should expand the property types (ExpandRecursively). It helps in the recursive case not to try to drill down into primitive types, so that's why T extends object condition is included.


Okay, let's see what happens when we use it on your type. We don't need ExpandRecursively in your case, but we could use it... it gives the same result:

type ExpandedText = Expand<Text>; 

which, when we hover over it in the IDE (The TypeScript Playground and VSCode anyway), is displayed as:

/* type ExpandedText = {   name: string;   type: "text";   value: string;   title: string;   start: number;   extras: object;  } */ 

as you wanted. Okay, hope that helps; good luck!

Link to code

like image 198
jcalz Avatar answered Oct 05 '22 10:10

jcalz