Skip to content

es5.d.ts lib does not match the ECMAScript 5.1 Spec #16132

Closed
@ericdrobinson

Description

@ericdrobinson

Types in es5.d.ts Should Match the ECMAScript 5.1 Standard

As a TypeScript user, I expect that an environment configured with "lib": ["es5"] should only resolve types specified in the ECMAScript 5.1 Language Specifications. Any further type declarations necessary should be optionally imported or specified by the TypeScript user. Indeed, this appears to be the suggested usage, as pointed out by @mhegazy in #1995 (emphasis mine):

you can always augment your program with additional types that you know would exist on your target system. for instance, if you know you are always running on an engine that supports promises, just add declarations for Promise in your program. The idea is that the lib file reflects the baseline of engines supporting the target of the compilation (ES5 v.s. ES6)

However, including only the "es5" lib will also bring in the following non-ES5 types (and their support types):

Including these types breaks expectations in properly initialized environments and has the potential to lead to confusion, if not bugs.

Why Are These Types In es5.d.ts to Begin With?

In short: to support the DOM API declarations.

From what I've been able to glean from the history, the fact that the above type declarations exist in es5.d.ts is effectively a kludge to more simply support the constantly-evolving DOM API libraries. From the comments on #14053 (which brought Promise<T> into es5.d.ts):

Move the declaration of the Promise interface to es5.d.ts (and subsequently lib.d.ts). This allows for DOM APIs that return Promise to be typed accurately.

Indeed, supporting DOM APIs appears to explain much of the reason for including the previously listed types in es5.d.ts. Again, in #16077 we have the following comment:

The sole purpose of including Promise and Typed Arrays to prevent errors from lib.dom.d.ts where APIs e.g. Fetch and Web Audio use them.

[It should be noted that in the above case, the discussion revolves around whether or not to move the types further back in time (to ES3).]

Moving "Support" Types Out of es5.d.ts

So the types are defined in the ES libs to support the DOM APIs (which suffer from granularity issues). Here are some options for how they might be removed from the es5.d.ts file:

1. Create a Middleman Library

It appears that ES5 is used as the default ECMAScript library for TypeScript - at some point es5.d.ts was even called core.d.ts. But a core.d.ts could still exist: it could import es5.d.ts and then some extra "support" types (e.g. those outlined above). That file could then be specified in the lib.d.ts library source map (as well as others).

2. Specify Necessary Features Directly in the Library Source Map

Specific features that DOM APIs require might be included from their respective "future" libraries. An example for promises might look like:

    // ...
    { target: "lib.dom.d.ts", sources: ["header.d.ts", "dom.generated.d.ts"].concat("es2015.promise.d.ts") },
    // ...
    { target: "lib.d.ts", sources: ["header.d.ts", "es5.d.ts"].concat(hostsLibrarySources, "es2015.promise.d.ts") },
    // ...

provided Promise type interfaces were moved back into es2015.promise.d.ts (unless I'm missing something important).

3. Declare Necessary Interfaces Inline

Declare required, but possibly new/future types as empty interfaces inline in the libraries that require it. In at least one Node Type Declaration library I've encountered, they did just this:

interface MapConstructor { }
interface WeakMapConstructor { }
interface SetConstructor { }
interface WeakSetConstructor { }

What's more, this even seems to be a suggested approach (emphasis mine):

you can always augment your program with additional types that you know would exist on your target system. for instance, if you know you are always running on an engine that supports promises, just add declarations for Promise in your program. The idea is that the lib file reflects the baseline of engines supporting the target of the compilation (ES5 v.s. ES6)

Wrap-up: Being Explicit About Type Definition

Instituting a change like this would not only clean up the ECMAScript type declaration file(s), it would explicitly document why those types were included with certain libraries. Presently, a user trying to figure out why UInt8Array is a suggested type when they've only imported type declarations for ECMAScript 5 ("lib": ["es5"]) will find that it's confusingly included in the es5.d.ts file, sans any documentation for its mysterious inclusion.

Further, it would decouple DOM support from ECMAScript support, enabling users to more explicitly configure their environments without surprising side-effects.

Metadata

Metadata

Assignees

No one assigned

    Labels

    DiscussionIssues which may not have code impact

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions