Issue 1:
This proposal is based on a working implementation at:

https://github.com/yortus/TypeScript/tree/granular-targeting

To try it out, clone it or install it with npm install yortus-typescript

Problem Scenario

The TypeScript compiler accepts a single target option of either ES3, ES5 or ES6. However, most realistic target environments support a mixture or ES5 and ES6, and even ES7, often known in advance (e.g. when targeting Node.js, and/or using polyfills).

Using TypeScript with target environments with mixed ES5/5/7 support presents some challenges, many of which have been discussed in other issues. E.g.:

(#4389) Support compile targets between ES5 and ES6

(#4168) Normalize our lib files by compiler settings

(#3215) New APIs added to lib.d.ts may break client codes. Allow duplicated members in interfaces? Make lib.d.ts overridable?

(#3005) Using ES6 type default library when targetting ES5 output

(#2695) for-of does not work with DOM collections when target is ES6

(somewhat related: (#2481) Create DOM-Level specific dom-version.d.ts)

In summary:

The default lib either includes all ES6 types and properties, or none of them.

Specifying --noLib and/or manually maintaining lib.b.ts files brings other problems:

separate core typings are a burden to maintain.

problems of missing symbols and clashing symbols.

burden of manually tracking fixes and additions made in the default libs.

Targeting ES5 as the 'lowest common denominator' means some language features known to be supported cannot be used (eg generators in Node.js).

Targeting ES6 (e.g. to take advantage of Node.js' support for many ES6 features) leads to further complications:

CommonJS modules won't compile, even though that's the only module system Node supports. (fixed by #4811)

The compiler emits ES6 even for features that are known not to be supported, which would fail at runtime.

Adding babel.js to the build pipeline adds complexity.

Workarounds

To achieve mixed ES5/ES6 core typings:

specify --target ES5 and selectively add ES6 typings in separately maintained files (eg from DefinitelyTyped).

specify --target ES6 and be careful to avoid referencing unsupported ES6 features (the compiler won't issue any errors).

specify --noLib and manually maintain custom core typings in your own project.

To use ES6 features supported by the target platform

specify --target ES5 and (a) accept that things will be down-level emitted, and (b) don't use features with no down-level emit yet (ie generators).

specify --target ES6 and (a) convert everything from CommonJS to ES6 modules (fixed by #4811), (b) add babel.js to the build pipeline, and (c) configure babel.js to do either pass-through or down-level emit on a feature-by-feature basis.

Proposed Solution

This proposal consists of two parts:

1. Support for conditional compilation using #if and #endif directives, so that a single default lib can offer fine-grained typings tailored to a mixed ES3/5/6/7 target environment.

The conditional compilation part is detailed in a separate proposal (#4691) with its own working implementation.

1. A mechanism allowing the default lib to offer fine-grained typings tailored to a mixed ES3/5/6/7 target environment.

This is really an internal compiler detail, so the mechanism is open to debate. It just has to match the granularity supported by the new compiler options below.

The working implementation uses #if...#endif conditional compilation proposed in #4691. But this is overkill for this use case and seems unlikely to be considered.

Several other mechanisms have been discussed (summarized here).

2. Support for additional compiler options allowing the target environment to be described on a feature-by-feature basis.

Under this proposal, the target option remains, but is now interpreted as the 'baseline' target, determining which features the target supports by default. For instance, ES6 symbols and generators are supported by default if target is set to ES6 or higher.

The additional compiler options have the form targetHasXYZ, where XYZ designates a feature. These options are used to override the target for a particular language feature. They instruct the compiler that the target environment explicitly does or does not support a particular feature, regardless of what the target option otherwise imples.

The working implementation currently supports the following additional compiler options (all boolean):

targetHasArrowFunctions: specify whether the target supports ES6 () => {...} syntax

targetHasBlockScoping: specify whether the target supports ES6 let and const

targetHasForOf: specify whether the target supports ES6 for..of syntax

targetHasGenerators: specify whether the target supports ES6 generators

targetHasIterables: specify whether the target supports ES6 iterables and iterators

targetHasModules: specify whether the target supports ES6 modules

targetHasPromises: specify whether the target supports ES6 promises

targetHasSymbols: specify whether the target supports ES6 symbols

These options work both on the command line and in tsconfig.json files.

Example tsconfig.json Files and their Behaviour

A.

{
"target": "es6",
"targetHasModules": false,
"targetHasBlockScoping": false,
"module": "commonjs"
}

Emits ES6 JavaScript, except with CommonJS module syntax, and with let/const down-leveled to var. This might match a Node.js environment.

B.

{
"target": "es5",
"targetHasSymbols": true
}

Emits ES5 JavaScript, except with Symbol references emitted as-is, and with full type support for well-known symbols from the default lib.

C.

{
"target": "es5",
"targetHasPromises": true
}

Emits ES5 JavaScript, except with full type support for ES6 promises from the default lib. This would work in an ES5 environment with a native or polyfilled Promise object.

Backward Compatibility, Design Impact, Performance, etc

There is no impact on existing TypeScript projects. The additional options and preprocessor directives only modify the compiler's behaviour if they are explicitly used.

The preprocessor directives #if and #endif add new language syntax. No existing language features are affected.

There is negligable impact on compiler performance.

Only one default lib is needed (lib.es6.d.ts). It contains many conditionally compiled sections (ie with #if and #endif)

Remaining Work and Questions

Support compiler options for more target features, e.g.:

template strings

classes

Map/Set/WeakMap/WeakSet

binary and octal literals

destructuring

default, rest, and optional parameters

How granular could/should targets be? Feature support is naturally hierarchical. E.g. block scoping may be separated into (a) let, (b) const and (c) block-level function declaration. This is true of most features and their realistic implementations (the Kangax ES6 compatibility table has a three-level hierarchy down the left side).

Issue 2:
I have the below overloaded function declaration for a function in my class

private _forEachBindingContext(bindingContext: IContext, fn: (bindingContext: IContext) => void);
private _forEachBindingContext(bindingContextArray: Array<IContext>, fn: (bindingContext:IContext) => void);
private _forEachBindingContext(context, fn: (bindingContext: IContext) => void): void {
// Function here
}

In previous versions of TypeScript to 1.1 it would generate a definition file with the line

private _forEachBindingContext(bindingContext, fn);

I could use this definition file in my other projects and it would work fine. After upgrading to 1.1 the same code now generates the following in the definition file

private _forEachBindingContext(bindingContext, fn);
private _forEachBindingContext(bindingContextArray, fn);

If I try using this definition file in other projects I get the following error:

Duplicate overload signature for '_forEachBindingContext'.

Changing this method to public solves the issue since it generates types on the definitions of public functions. I would expect that I could use either public or private and not encounter this issue.