Skip to content

[Feature Request] Future-proof always-aliasing/never-expanding of mapped/intersection/union/etc. types #35654

Closed

Description

Search Terms

Force TS to always alias type, optional property, never expand type

Suggestion

It would be nice to have a way to annotate a type alias and tell TS, "As much as possible, do not expand this type alias in emit". I don't know what syntax it should have. But maybe,

type interface PleaseDoNotExpand<T> = /*complex type*/;

In all aspects, the above is a type alias, except for the fact that its type will not expand in emit (as much as possible).

class and interface types have this behaviour. Their identifiers are used as much as possible in emit.

The "readability" of a particular emit is almost always subjective. So, giving developers some control over the emit can make code easier to understand.


Here's an example, where using a type alias in a union causes the type alias' identifier to not be used in emit,

type PleaseDoNotExpand<T> =
    | T
    | { x : T }
;

/*
Expected: const a: PleaseDoNotExpand<number>
Actual  : const a: PleaseDoNotExpand<number>
*/
declare const a: PleaseDoNotExpand<number>;


/*
Expected: const b: PleaseDoNotExpand<number>|undefined
Actual  : const b: number | {x: number;} | undefined
*/
declare const b: PleaseDoNotExpand<number>|undefined;

If PleaseDoNotExpand<> were a class or interface, we would have const b: PleaseDoNotExpand<number>|undefined

Use Cases

What do you want to use this for?

  • Better emit for .d.ts files
  • Better emit for tooltip hover
  • Better emit for error messages

Some type aliases are hundreds of lines long, after expansion. These type aliases usually have short, intuitive identifiers. But those identifiers tend to get lost when used in union types (and optional properties). See #35616 for more examples.

What shortcomings exist with current approaches?

There is no "general purpose" workaround for the current problem.

So far, I've thought of two workarounds. But they only work for very specific use cases.

Workaround 1: The type alias has statically known members

#34777

#34777 (comment)

The idea is to use an interface to extend the type alias. From that point, only the interface's identifier is used in emit. This has the most desirable behaviour. If it could be extended to work for all use cases, then I wouldn't have this feature request.

Workdaround 2: The type alias is being removed by unions/optional properties

#35616

#35616 (comment)

The idea is to create a new type alias that is a union of the original type and the new union elements. However, it does not always work and I don't know why. But this is better than always expanding.

Examples

//No idea about syntax
type interface PleaseDoNotExpand<T> =
    | T
    | { x : T }
;

/*
const a: PleaseDoNotExpand<number>
*/
declare const a: PleaseDoNotExpand<number>;


/*
const b: PleaseDoNotExpand<number>|undefined
*/
declare const b: PleaseDoNotExpand<number>|undefined;

/*
//It makes sense to lose the identifier at this point
const c: number
*/
declare const c: Extract<PleaseDoNotExpand<number>, number>;

/*
//It makes sense to lose the identifier at this point
const c: { x : number }
*/
declare const d: Exclude<PleaseDoNotExpand<number>, number>;

Checklist

My suggestion meets these guidelines:

  • This wouldn't be a breaking change in existing TypeScript/JavaScript code
  • This wouldn't change the runtime behavior of existing JavaScript code
  • This could be implemented without emitting different JS based on the types of the expressions
  • This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, etc.)
  • This feature would agree with the rest of TypeScript's Design Goals.

Related

#34556 asks to never alias a type. This asks to always alias a type.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

Labels

SuggestionAn idea for TypeScript

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions