Inline a type definition in TypeScript

8k views Asked by At

I'm writing a type definition file (index.d.ts) for a jQuery library that doesn't come with a type definition.
The methods of that library repeatedly accept parameters of the same multi-type (string | number | []) so I defined it as a CustomType:

export type CustomType = string | number | [];

declare global {
    interface JQuery<TElement = HTMLElement> {
        setFoo(foo: CustomType): this;
        setBar(bar: CustomType): this;
    }
}

When I now want to call setFoo() on a jQuery object, the type hinting (of IntelliJ) shows that a parameter foo: CustomType is expected which doesn't help fellow devs without looking up what that type resembles.
Instead I'd love to see the type hinting to show foo: string | number | [].

For example, in C++ there is this concept of an inline function which basically tells the compiler to put the code of the inlined functions body right into the block where it's called rather than to call / jump to the function. Is there something similar in TypeScript?

How can I force TypeScript to inline this CustomType and make it show as foo: string | number | [] instead of foo: CustomType?

Ugly Solution

declare global {
    interface JQuery<TElement = HTMLElement> {
        setFoo(foo: string | number | []): this;
        setBar(bar: string | number | []): this;
    }
}

One solution would be to eliminate the CustomType and explicitly type parameters with their multi-types, but this becomes rather inconvenient with an increasing number of methods that use the same type as it doesn't benefit from reusability plus it looks ugly to me.

Imaginary Solution

export type CustomType = string | number | [];

declare global {
    interface JQuery<TElement = HTMLElement> {
        setFoo(foo: inline CustomType): this; // <-- note the 'inline' here
        setBar(bar: inline CustomType): this;
    }
}

This would be ideal and in my imagination behave like the 'Ugly Solution', but unfortunately isn't supported. So what would be the proper way to achieve this?

1

There are 1 answers

0
jcalz On BEST ANSWER

I think this is not currently possible.

There is an open GitHub issue, microsoft/TypeScript#25784, asking for the ability to "drill down" into the IntelliSense quick info, which, if implemented, may or may not expand unions into their constituents.

There's also microsoft/TypeScript#40780 which asks for an "alias" keyword that works similarly to what you're suggesting: basically a type macro that is eliminated by the time anyone consuming the code looks at it. This issue was closed as a duplicate of a draft pull request for what looks like a slightly different feature. So this line of research seemed to peter out fairly quickly.


So, workaround: create/declare a variable x of the type you'd like to inline away, and refer to this type as typeof x. At the call sites, IntelliSense should, I believe, resolve typeof x to the expanded type. I can't guarantee that this will always happen (the details of how the compiler decides to render type information are a bit murky to me) but it seems to do this in my testing. For example:

const __Custom: string | number | any[];

interface JQuery<TElement = HTMLElement> {
  setFoo(foo: typeof __Custom): this;
  setBar(bar: typeof __Custom): this;
}

And then later:

declare const $: JQuery;
$.setBar(""); // IntelliSense says 
// setBar(bar: string | number | any[]): JQuery<HTMLElement>

This may or may not work for you.

Playground link to code