Skip to content

Commit 2a70f4e

Browse files
committed
fix(typings): Don't expose typing dependencies to users.
This resolves Duplicate Identifier issues seen by many users, at the expense of more typings installation required in some cases. Removes the quickstart hack of placing all needed dependencies typings files in our distribution. Removes dependencies on nodejs from angular2/core. Fixes angular#5973 Fixes angular#5807 Fixes angular#6266 Angular now depends on es6-promise and es6-collections (and a handful of manual typings) rather than all of es6-shim. Fixes angular#5242 We previously had an undocumented breaking change, this is now documented in this commit. Fixes angular#6817 BREAKING CHANGE: Transitive typings are no longer included in the distribution. You may need to install typings in your project using http://github.com/typings/typings Users now must rely on getting typings from: - one of the peerDependencies, such as rxjs, which exposes typings via the moduleResolution=node mechanism. (see https://github.com/Microsoft/TypeScript/wiki/Typings-for-npm-packages) This happens automatically. - Using --target ES5 now requires manual installation of es6-promise and es6-collections typings. - Using some angular APIs may introduce a dependency on eg. nodejs or jasmine, and those typings need manual installation as well. Closes angular#6267
1 parent 2f31c4c commit 2a70f4e

File tree

9 files changed

+125
-96
lines changed

9 files changed

+125
-96
lines changed

gulpfile.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -981,15 +981,16 @@ gulp.task('!pre.test.typings.layoutNodeModule', ['build.js.cjs'], function() {
981981
.pipe(gulp.dest(path.join(tmpdir, 'node_modules')));
982982
});
983983
gulp.task('!pre.test.typings.copyTypingsSpec', function() {
984-
return gulp.src(['typing_spec/*.ts'], {base: 'typing_spec'}).pipe(gulp.dest(path.join(tmpdir)));
984+
return gulp.src(['typing_spec/*.ts'], {base: 'typing_spec'}).pipe(gulp.dest(tmpdir));
985985
});
986+
986987
gulp.task('test.typings',
987988
['!pre.test.typings.layoutNodeModule', '!pre.test.typings.copyTypingsSpec'], function() {
988989
var tsc = require('gulp-typescript');
989990

990-
return gulp.src([tmpdir + '/**'])
991+
return gulp.src([tmpdir + '/*.ts'])
991992
.pipe(tsc({
992-
target: 'ES5',
993+
target: 'ES6',
993994
module: 'commonjs',
994995
experimentalDecorators: true,
995996
noImplicitAny: true,

modules/angular2/manual_typings/globals-es6.d.ts

Lines changed: 0 additions & 36 deletions
This file was deleted.
Lines changed: 50 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,52 @@
11
/**
2-
* Declarations angular depends on for compilation to ES6.
3-
* This file is also used to propagate our transitive typings
4-
* to users.
2+
* Subset of es6-shim typings.
3+
* Angular should not require use of ES6 runtime but some API usages are already present.
4+
* See https://github.com/angular/angular/issues/5242
5+
* TODO(alexeagle): remove methods below which may not be present in targeted browser
56
*/
6-
/// <reference path="../typings/es6-shim/es6-shim.d.ts"/>
7-
/// <reference path="./globals-es6.d.ts"/>
7+
8+
declare type PromiseConstructor = typeof Promise;
9+
10+
interface String {
11+
/**
12+
* Returns true if the sequence of elements of searchString converted to a String is the
13+
* same as the corresponding elements of this object (converted to a String) starting at
14+
* position. Otherwise returns false.
15+
*/
16+
startsWith(searchString: string, position?: number): boolean;
17+
18+
/**
19+
* Returns true if the sequence of elements of searchString converted to a String is the
20+
* same as the corresponding elements of this object (converted to a String) starting at
21+
* endPosition – length(this). Otherwise returns false.
22+
*/
23+
endsWith(searchString: string, endPosition?: number): boolean;
24+
}
25+
interface Array<T> {
26+
/**
27+
* Returns the value of the first element in the array where predicate is true, and undefined
28+
* otherwise.
29+
* @param predicate find calls predicate once for each element of the array, in ascending
30+
* order, until it finds one where predicate returns true. If such an element is found, find
31+
* immediately returns that element value. Otherwise, find returns undefined.
32+
* @param thisArg If provided, it will be used as the this value for each invocation of
33+
* predicate. If it is not provided, undefined is used instead.
34+
*/
35+
find(predicate: (value: T, index: number, obj: Array<T>) => boolean, thisArg?: any): T;
36+
/**
37+
* Returns the this object after filling the section identified by start and end with value
38+
* @param value value to fill array section with
39+
* @param start index to start filling the array at. If start is negative, it is treated as
40+
* length+start where length is the length of the array.
41+
* @param end index to stop filling the array at. If end is negative, it is treated as
42+
* length+end.
43+
*/
44+
fill(value: T, start?: number, end?: number): T[];
45+
}
46+
interface NumberConstructor {
47+
/**
48+
* Returns true if the value passed is an integer, false otherwise.
49+
* @param number A numeric value.
50+
*/
51+
isInteger(number: number): boolean;
52+
}

modules/angular2/src/core/change_detection/parser/lexer.ts

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -248,15 +248,12 @@ class _Scanner {
248248
}
249249

250250
scanCharacter(start: number, code: number): Token {
251-
assert(this.peek == code);
252251
this.advance();
253252
return newCharacterToken(start, code);
254253
}
255254

256255

257256
scanOperator(start: number, str: string): Token {
258-
assert(this.peek == StringWrapper.charCodeAt(str, 0));
259-
assert(SetWrapper.has(OPERATORS, str));
260257
this.advance();
261258
return newOperatorToken(start, str);
262259
}
@@ -274,7 +271,6 @@ class _Scanner {
274271
*/
275272
scanComplexOperator(start: number, one: string, twoCode: number, two: string, threeCode?: number,
276273
three?: string): Token {
277-
assert(this.peek == StringWrapper.charCodeAt(one, 0));
278274
this.advance();
279275
var str: string = one;
280276
if (this.peek == twoCode) {
@@ -285,12 +281,10 @@ class _Scanner {
285281
this.advance();
286282
str += three;
287283
}
288-
assert(SetWrapper.has(OPERATORS, str));
289284
return newOperatorToken(start, str);
290285
}
291286

292287
scanIdentifier(): Token {
293-
assert(isIdentifierStart(this.peek));
294288
var start: number = this.index;
295289
this.advance();
296290
while (isIdentifierPart(this.peek)) this.advance();
@@ -303,7 +297,6 @@ class _Scanner {
303297
}
304298

305299
scanNumber(start: number): Token {
306-
assert(isDigit(this.peek));
307300
var simple: boolean = (this.index === start);
308301
this.advance(); // Skip initial digit.
309302
while (true) {
@@ -329,7 +322,6 @@ class _Scanner {
329322
}
330323

331324
scanString(): Token {
332-
assert(this.peek == $SQ || this.peek == $DQ);
333325
var start: number = this.index;
334326
var quote: number = this.peek;
335327
this.advance(); // Skip initial quote.

modules/angular2/src/core/zone/ng_zone.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import {ListWrapper, StringMapWrapper} from 'angular2/src/facade/collection';
2-
import {normalizeBlank, isPresent, global} from 'angular2/src/facade/lang';
2+
import {normalizeBlank, isPresent, global, ZoneLike} from 'angular2/src/facade/lang';
33
import {ObservableWrapper, EventEmitter} from 'angular2/src/facade/async';
44
import {wtfLeave, wtfCreateScope, WtfScopeFn} from '../profile/profile';
55

6-
export interface NgZoneZone extends Zone {
6+
export interface NgZoneZone extends ZoneLike {
77
/** @internal */
88
_innerZone: boolean;
99
}
@@ -348,8 +348,9 @@ export class NgZone {
348348
var errorHandling;
349349

350350
if (enableLongStackTrace) {
351-
errorHandling = StringMapWrapper.merge(
352-
Zone.longStackTraceZone, {onError: function(e) { ngZone._notifyOnError(this, e); }});
351+
errorHandling =
352+
StringMapWrapper.merge(global.Zone.longStackTraceZone,
353+
{onError: function(e) { ngZone._notifyOnError(this, e); }});
353354
} else {
354355
errorHandling = {onError: function(e) { ngZone._notifyOnError(this, e); }};
355356
}

modules/angular2/src/facade/async.ts

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,16 @@ import {toPromise} from 'rxjs/operator/toPromise';
1515
export {Observable} from 'rxjs/Observable';
1616
export {Subject} from 'rxjs/Subject';
1717

18-
export namespace NodeJS {
19-
export interface Timer {}
20-
}
21-
2218
export class TimerWrapper {
23-
static setTimeout(fn: (...args: any[]) => void, millis: number): NodeJS.Timer {
19+
static setTimeout(fn: (...args: any[]) => void, millis: number): number {
2420
return global.setTimeout(fn, millis);
2521
}
26-
static clearTimeout(id: NodeJS.Timer): void { global.clearTimeout(id); }
22+
static clearTimeout(id: number): void { global.clearTimeout(id); }
2723

28-
static setInterval(fn: (...args: any[]) => void, millis: number): NodeJS.Timer {
24+
static setInterval(fn: (...args: any[]) => void, millis: number): number {
2925
return global.setInterval(fn, millis);
3026
}
31-
static clearInterval(id: NodeJS.Timer): void { global.clearInterval(id); }
27+
static clearInterval(id: number): void { global.clearInterval(id); }
3228
}
3329

3430
export class ObservableWrapper {
@@ -161,4 +157,4 @@ export class EventEmitter<T> extends Subject<T> {
161157

162158
return super.subscribe(schedulerFn, errorFn, completeFn);
163159
}
164-
}
160+
}

modules/angular2/src/facade/lang.ts

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,36 @@
1+
// Zones are TC-39 standards-track so users could choose a different implementation
2+
// Rather than import {Zone} from 'zone.js' we define an interface
3+
// so that any library that structurally matches may be used with Angular 2.
4+
export interface ZoneLike {
5+
fork(locals?: any): ZoneLike;
6+
run(fn: any, applyTo?: any, applyWith?: any): any;
7+
}
8+
export interface ZoneLikeConstructor {
9+
longStackTraceZone: { [key: string]: any; };
10+
}
11+
12+
export interface BrowserNodeGlobal {
13+
Object: typeof Object;
14+
Array: typeof Array;
15+
Map: typeof Map;
16+
Set: typeof Set;
17+
Date: DateConstructor;
18+
RegExp: RegExpConstructor;
19+
JSON: typeof JSON;
20+
Math: any; // typeof Math;
21+
assert(condition: any): void;
22+
Reflect: any;
23+
zone: ZoneLike;
24+
Zone: ZoneLikeConstructor;
25+
getAngularTestability: Function;
26+
getAllAngularTestabilities: Function;
27+
frameworkStabilizers: Array<Function>;
28+
setTimeout: Function;
29+
clearTimeout: Function;
30+
setInterval: Function;
31+
clearInterval: Function;
32+
}
33+
134
// TODO(jteplitz602): Load WorkerGlobalScope from lib.webworker.d.ts file #3492
235
declare var WorkerGlobalScope;
336
var globalScope: BrowserNodeGlobal;
@@ -10,7 +43,7 @@ if (typeof window === 'undefined') {
1043
}
1144
} else {
1245
globalScope = <any>window;
13-
};
46+
}
1447

1548
export const IS_DART = false;
1649

@@ -430,4 +463,4 @@ export function evalExpression(sourceUrl: string, expr: string, declarations: st
430463

431464
export function isPrimitive(obj: any): boolean {
432465
return !isJsObject(obj);
433-
}
466+
}

tools/broccoli/trees/browser_tree.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,14 @@ module.exports = function makeBrowserTree(options, destinationPath) {
171171
patterns: [{match: /\$SCRIPTS\$/, replacement: jsReplace('SCRIPTS')}]
172172
});
173173

174+
let ambientTypings = [
175+
'angular2/typings/hammerjs/hammerjs.d.ts',
176+
'angular2/typings/node/node.d.ts',
177+
'angular2/manual_typings/globals.d.ts',
178+
'angular2/typings/es6-collections/es6-collections.d.ts',
179+
'angular2/typings/es6-promise/es6-promise.d.ts'
180+
];
181+
174182
// Use TypeScript to transpile the *.ts files to ES5
175183
var es5Tree = compileWithTypescript(es5ModulesTree, {
176184
declaration: false,
@@ -180,7 +188,7 @@ module.exports = function makeBrowserTree(options, destinationPath) {
180188
moduleResolution: 'classic',
181189
noEmitOnError: !noTypeChecks,
182190
rootDir: './',
183-
rootFilePaths: ['angular2/manual_typings/globals.d.ts'],
191+
rootFilePaths: ambientTypings,
184192
inlineSourceMap: sourceMaps,
185193
inlineSources: sourceMaps,
186194
target: 'es5'
@@ -311,7 +319,11 @@ module.exports = function makeBrowserTree(options, destinationPath) {
311319
experimentalDecorators: true,
312320
noEmitOnError: false,
313321
rootDir: './',
314-
rootFilePaths: ['angular2/manual_typings/globals-es6.d.ts'],
322+
rootFilePaths: [
323+
'angular2/typings/zone.js/zone.js.d.ts',
324+
'angular2/typings/hammerjs/hammerjs.d.ts',
325+
'angular2/typings/node/node.d.ts',
326+
],
315327
inlineSourceMap: sourceMaps,
316328
inlineSources: sourceMaps,
317329
target: 'es6'

tools/broccoli/trees/node_tree.ts

Lines changed: 12 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,16 @@ module.exports = function makeNodeTree(projects, destinationPath) {
3232
]
3333
});
3434

35+
let ambientTypings = [
36+
'angular2/typings/hammerjs/hammerjs.d.ts',
37+
'angular2/typings/node/node.d.ts',
38+
'angular2/manual_typings/globals.d.ts',
39+
'angular2/typings/es6-collections/es6-collections.d.ts',
40+
'angular2/typings/es6-promise/es6-promise.d.ts'
41+
];
42+
3543
// Compile the sources and generate the @internal .d.ts
36-
let compiledSrcTreeWithInternals =
37-
compileTree(srcTree, true, ['angular2/manual_typings/globals.d.ts']);
44+
let compiledSrcTreeWithInternals = compileTree(srcTree, true, ambientTypings);
3845

3946
var testTree = new Funnel('modules', {
4047
include: [
@@ -85,11 +92,10 @@ module.exports = function makeNodeTree(projects, destinationPath) {
8592

8693
testTree = mergeTrees([testTree, srcPrivateDeclarations]);
8794

88-
let compiledTestTree = compileTree(testTree, false, [
95+
let compiledTestTree = compileTree(testTree, false, ambientTypings.concat([
8996
'angular2/typings/jasmine/jasmine.d.ts',
9097
'angular2/typings/angular-protractor/angular-protractor.d.ts',
91-
'angular2/manual_typings/globals.d.ts'
92-
]);
98+
]));
9399

94100
// Merge the compiled sources and tests
95101
let compiledSrcTree =
@@ -112,12 +118,7 @@ module.exports = function makeNodeTree(projects, destinationPath) {
112118
var srcPkgJsons = extractPkgJsons(srcTree, BASE_PACKAGE_JSON);
113119
var testPkgJsons = extractPkgJsons(testTree, BASE_PACKAGE_JSON);
114120

115-
var typingsTree = new Funnel(
116-
'modules',
117-
{include: ['angular2/typings/**/*.d.ts', 'angular2/manual_typings/*.d.ts'], destDir: '/'});
118-
119-
var nodeTree =
120-
mergeTrees([compiledTree, srcDocs, testDocs, srcPkgJsons, testPkgJsons, typingsTree]);
121+
var nodeTree = mergeTrees([compiledTree, srcDocs, testDocs, srcPkgJsons, testPkgJsons]);
121122

122123
// Transform all tests to make them runnable in node
123124
nodeTree = replace(nodeTree, {
@@ -139,22 +140,6 @@ module.exports = function makeNodeTree(projects, destinationPath) {
139140
nodeTree = replace(
140141
nodeTree, {files: ['**/*.js'], patterns: [{match: /^/, replacement: () => `'use strict';`}]});
141142

142-
// Add a line to the end of our top-level .d.ts file.
143-
// This HACK for transitive typings is a workaround for
144-
// https://github.com/Microsoft/TypeScript/issues/5097
145-
//
146-
// This allows users to get our top-level dependencies like zone.d.ts
147-
// to appear when they compile against angular2.
148-
//
149-
// This carries the risk that the user brings their own copy of that file
150-
// (or any other symbols exported here) and they will get a compiler error
151-
// because of the duplicate definitions.
152-
// TODO(alexeagle): remove this when typescript releases a fix
153-
nodeTree = replace(nodeTree, {
154-
files: ['angular2/core.d.ts'],
155-
patterns: [{match: /$/, replacement: 'import "./manual_typings/globals-es6.d.ts";\r\n'}]
156-
});
157-
158143
return destCopy(nodeTree, destinationPath);
159144
};
160145

0 commit comments

Comments
 (0)