Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Normalize our lib files by compiler settings #4168

Closed
RyanCavanaugh opened this issue Aug 5, 2015 · 20 comments
Closed

Normalize our lib files by compiler settings #4168

RyanCavanaugh opened this issue Aug 5, 2015 · 20 comments
Labels
External Relates to another program, environment, or user action which we cannot control.

Comments

@RyanCavanaugh
Copy link
Member

Right now the compiler depends on a monolithic lib.d.ts file that is resolved according to the script target (ES5 or ES6). We have to build several different lib.d.ts files out of smaller parts.

We should refactor this so that the different aspects of the compiler settings can map to smaller sub-parts of the libraries.

Language target:

  • ES3
  • ES5
  • ES6
  • Latest

Host:

  • Browser with DOM
  • WebWorker
  • NodeJS
  • Windows Script Host 😷

Module system:

  • CommonJS
  • AMD
  • None

The idea is that we a function that takes a CompilerSettings and produces a list of filenames. These files might reference each other, e.g. lib.es5.d.ts would probably reference lib.es6.d.ts and just provide interface augmentations.

This provides several benefits:

  • It will be easier for us to edit these files because they are smaller
  • It will be easier for users to patch in only specific versions if they decide they need to fork certain things
  • It will be possible for users to have a custom version of one file while still getting bug fixes for the other files
  • Provides a more natural way to shim in specific things based on compiler settings without having a combinatorial explosion of concatenated lib.d.ts files
@RyanCavanaugh RyanCavanaugh added Suggestion An idea for TypeScript In Discussion Not yet reached consensus labels Aug 5, 2015
@weswigham
Copy link
Member

A really common practice right now is compiling for ES5, but still needing ES6 Promise types. The DefinitelyTyped es6-promise types get used in combination with the ES5 lib in this case right now, but it would be very nice if we could enable/disable lib.d.ts parts by feature, rather than by target spec (since the spec version target is just a collection of features, from a consumer of TS's point of view).

Breaking down the stdlib files into more parts could help work towards this considerably.

@mhegazy
Copy link
Contributor

mhegazy commented Aug 5, 2015

so what is the granularity, what needs to be in a flle by itself and what is not.. also what is draw back from just including all es6 types?

@weswigham
Copy link
Member

Including ES6 types would drop many extra types into your IDE/Editor experience which you don't actually have access to in your targeted environment, for one. Beyond that, many awkward things (interface redefinitions and the like) happen when you try to depend on a partial ES6 polyfill .d.ts file (like one included by a library you're using) alongside the full TS ES6 lib. (There's no simple way to tell the TS compiler "ES6 JS emit with ES5 types which-I'll-patch-to-partial-ES6-myself")

@mhegazy
Copy link
Contributor

mhegazy commented Aug 7, 2015

I agree with the principal, my question is about the details.. what is the granularity? is it down to methods (es6.array.is.d.ts) or containers (es6.array.d.ts, es6.object.d.ts), or areas (es6.core.d.ts, es6.typedarrays.d.ts, es6.promise.d.ts)?
a concreate list of files we want to generate would be ideal.

@weswigham
Copy link
Member

If we can get away with it, the highest level of granularity possible will allow the greatest amount of compiler consumer control later (and also combinatoric expansion in possible compiler configurations).

Generally speaking though, I'd say I'm partial to group by feature area (like how babel groups language features), since it's seemed like that's how they've gotten implemented in JS environments - one feature at a time. (Eg, the 'Set' API, the 'Map' API, the new 'Array' API, etc.)

@yortus
Copy link
Contributor

yortus commented Aug 11, 2015

If more granuar targetting is on the cards, then some consideration ought to be given to emit, not just lib files, for precisely the same motivations.

As @weswigham points out, JS environments implement and release features incrementally. Babel reflects this reality. With TypeScript one must choose the lowest common denominator for the target, even if the environment supports many but not all features of a higher target. Otherwise the emitted code will not run on the target. For example its still prudent to target ES5 for node projects, even though V8 now supports a great many ES6 features.

My suggestion would be to add a key to tsconfig.json, something like so:

{
    "compilerOptions": {
        "module": "commonjs",
        "target": "es5",
        "targets": {
            "builtins.map": "es6",
            "builtins.weakMap": "es6",
            "syntax.arrowFunctions": "es6",
            "syntax.generators": "es6",
            "syntax.templateStrings": "es6"
        }
    }
}

So a project can have a default target, and then override targets for particular features it uses. Note that 'features' cover far more than just lib.d.ts contents - they affect emit too. I know the emit part is straightforward to implement in the compiler because our fork does exactly this to support node.js (ES5) + native generators (ES6) compiling fine with tsc.

@LPGhatguy
Copy link
Contributor

I definitely agree with the proposal @yortus has included, and I filed an issue about it independently with issue #4389. This only solves the problem of weird inbetween JS targets, not DOM features, though. Maybe they could be solved with a similar idea?

@Arnavion
Copy link
Contributor

How would this work with something that crosses features like symbols, which would add members to other types that may or may not be there?

For example, the presence of "builtins.symbol" cannot naively result in interface Promise<T> { [Symbol.species](); } being included to the generated lib.d.ts, unless "builtins.promise" is also defined. So it seems the constituent .d.ts will need to be property-level granular (promise.symbol.d.ts), not feature-level (promise.d.ts, symbol.d.ts).

@weswigham
Copy link
Member

I imagine builtins.symbol would define symbols in isolation (the Symbol object, maybe covertly turn on the compiler flag to support them as indexers), then we could have separate extensions to builtins.promise which depend on builtins.symbol, like builtins.promise.symbolextensions, which define the additions to the promise interface which can come with symbols.

Symbols are a little interesting since a full implementation of them touches a lot of other objects... regexes, arrays, etc... but those well-known symbols aren't always present depending on the target('s implementation status), so being able to choose the ones you know will exist is a good thing.

@yortus
Copy link
Contributor

yortus commented Sep 8, 2015

I made a proposal for a possible solution over at #4692. There is a working implementation too.

@bpasero
Copy link
Member

bpasero commented Nov 18, 2015

I like this approach, but will I be able to define a new host? TypeScript should not hardcode the possible hosts my code can run in but provide a solution where I can provide my own host. To give an example: Electron is a host for JavaScript that adds API on top of plain JS and node.js. Specific versions of Electron might have different API. I want to express in my tsconfig.json that the host is "Electron: 0.34.x".

@mhegazy
Copy link
Contributor

mhegazy commented Nov 19, 2015

Specific versions of Electron might have different API. I want to express in my tsconfig.json that the host is "Electron: 0.34.x".

I do not think we can do a generic support for all hosts, the ones we know about are "core", i.e. some ES3/ES5/ES6 compliant engine (things like Object, JSON, Error, etc..), and "DOM" (regular and webworker, only latest, version would not possible here). for anything else, you need to pass a .d.ts for your host. so you should have electron.0.34.d.ts that you feed in to the compiler along with --noLib and things should just work.

@mhegazy
Copy link
Contributor

mhegazy commented Feb 22, 2016

subsumed by #6974

@mhegazy mhegazy closed this as completed Feb 22, 2016
@mhegazy mhegazy added the Duplicate An existing issue was already created label Feb 22, 2016
@remojansen
Copy link
Contributor

Hi guys,

I'm getting:

TypeScript error: Error TS2318: Cannot find global type 'Array'.

Only in one version of node (6.5.0 x86) with tsify. I'm not sure about what is causing the issue but I'm using:

"target": "es5",
"lib": ["es6", "dom"]

Any ideas? Full details available at tsify/issues/196.

Thanks!

@mhegazy
Copy link
Contributor

mhegazy commented Sep 8, 2016

do you happen to have --noResolve set?

@remojansen
Copy link
Contributor

I'm using noResolve false (default)

@RyanCavanaugh
Copy link
Member Author

This is likely a tsify bug. The gulp TS plugin had a similar issue

@remojansen
Copy link
Contributor

Thanks for helping me out @RyanCavanaugh @mhegazy it is now confirmed as a tsify bug.

@RyanCavanaugh RyanCavanaugh added External Relates to another program, environment, or user action which we cannot control. and removed Duplicate An existing issue was already created In Discussion Not yet reached consensus Suggestion An idea for TypeScript labels Sep 9, 2016
@RyanCavanaugh
Copy link
Member Author

Thanks!

@RyanCavanaugh RyanCavanaugh reopened this Sep 9, 2016
@RyanCavanaugh
Copy link
Member Author

Oops

@microsoft microsoft locked and limited conversation to collaborators Jun 19, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
External Relates to another program, environment, or user action which we cannot control.
Projects
None yet
Development

No branches or pull requests

8 participants