Force TypeScript to show final state of variable on hover

Viewed 279

In my project it happens in multiple occasion that TypeScript show to me an uninterpreted type.


Example :

In the following code, hovering over Foo will give to me the following result :

playground

interface FooParent {
    fish: {
        catfish: string;
    }[];
}

type Foo = {
    test: FooParent['fish'][0];
};

enter image description here


If I want to know about the type of FooParent['fish'][0], I have to interpret it myself.

I saw that it is possible to trick TypeScript using the infer keywork :

playground


interface FooParent {
    fish: {
        catfish: string;
    }[];
}

type Foo = {
    test: FooParent['fish'][0] extends infer U ? { [P in keyof U]: U[P] } : never;
};

enter image description here


But it's unpredictable (Playground).


Do you know of any method allowing TypeScript to show to you the final type of the variable you are hovering on in a simple and reliable way ?

1 Answers

Depending on your Typescript knowledge, the solution itself could be a bit intense; I provided some comments to walk you through. But the usage is rather simple and reliable - very analogous to your initial working example: YourType extends ForceType<infer U> ? U : _whatever_ .

interface FooParent {
    fish: {
        catfish: string;
        foo: {
            bar: () => void
        },
        loop: FooParent
    }[];
}

type Foo = {
    test: 
        // FooParent,
        // FooParent extends ForceType<infer U> ? U : never,
        // FooParent['fish'],
        // FooParent['fish'] extends ForceType<infer U> ? U : never,
        // FooParent['fish'][0],
        FooParent['fish'][0] extends ForceType<infer U> ? U : never,
        // FooParent['fish'][0]['catfish'],
        // FooParent['fish'][0]['catfish'] extends ForceType<infer U> ? U : never
    
};

type Index = number | string | symbol
type ForceType<T, Path extends Index[] = Index[]> = Path extends [infer _] ?
 T extends Record<Index, any> ? ForceObject<T, Path>
    : T extends ReadonlyArray<any> ? ForceArray<T, Path>
        : never // neither object nor array; never could only happen if Path was specified explicitly
            : T // closes the first condition - Path is empty we reached a leaf

type ForceObject<T, Path extends Index[]> = Path extends [infer H, ...infer Rest] ?
        Rest extends Index[] ?
            H extends keyof T ? ForceType<T[H], Rest> // traverse and recurse
                : never : never : never // never could only happen if Path was specified explicitly

type ForceArray<T extends ReadonlyArray<any>, Path extends Index[]> = Path extends [number, ...infer Rest] ?
   Rest extends Index[] ? ForceType<T[number], Rest> // traverse and recurse
    : never : never // never could only happen if Path was specified explicitly

PLAYGROUND

The below image was taken with CMD pressed. Showing the original code and calculated type.

working example from TS playground

I think ultimately the issue should be addressed on IDE level, as it is mostly a DX challenge. It seems Monaco Editor / VSCode are pretty close to actually address it, but in most cases hovering over a type definition with CMD pressed displays just duplicated information.

Fortunately, in this case a problem with types can be solved with even more types.

Btw. a very nice question - well researched, documented and challenging. Thank you.

Related