fix(typings): repair broken type-checking for StringMap

Note that the previous type of StringMap was overly permissive and didn't catch errors.
Also we have to explicitly type empty objects, which is explained here:
https://github.com/Microsoft/TypeScript/issues/5089

Closes 
This commit is contained in:
Alex Eagle 2015-10-02 17:33:21 -07:00 committed by Alex Eagle
parent 7c4199cd1c
commit 208f3d4c65
16 changed files with 36 additions and 36 deletions

@ -113,9 +113,9 @@ export class CompileDirectiveMetadata {
lifecycleHooks?: LifecycleHooks[], lifecycleHooks?: LifecycleHooks[],
template?: CompileTemplateMetadata template?: CompileTemplateMetadata
} = {}): CompileDirectiveMetadata { } = {}): CompileDirectiveMetadata {
var hostListeners = {}; var hostListeners: {[key: string]: string} = {};
var hostProperties = {}; var hostProperties: {[key: string]: string} = {};
var hostAttributes = {}; var hostAttributes: {[key: string]: string} = {};
if (isPresent(host)) { if (isPresent(host)) {
StringMapWrapper.forEach(host, (value: string, key: string) => { StringMapWrapper.forEach(host, (value: string, key: string) => {
var matches = RegExpWrapper.firstMatch(HOST_REG_EXP, key); var matches = RegExpWrapper.firstMatch(HOST_REG_EXP, key);
@ -128,7 +128,7 @@ export class CompileDirectiveMetadata {
} }
}); });
} }
var inputsMap = {}; var inputsMap: {[key: string]: string} = {};
if (isPresent(inputs)) { if (isPresent(inputs)) {
inputs.forEach((bindConfig: string) => { inputs.forEach((bindConfig: string) => {
// canonical syntax: `dirProp: elProp` // canonical syntax: `dirProp: elProp`
@ -137,7 +137,7 @@ export class CompileDirectiveMetadata {
inputsMap[parts[0]] = parts[1]; inputsMap[parts[0]] = parts[1];
}); });
} }
var outputsMap = {}; var outputsMap: {[key: string]: string} = {};
if (isPresent(outputs)) { if (isPresent(outputs)) {
outputs.forEach((bindConfig: string) => { outputs.forEach((bindConfig: string) => {
// canonical syntax: `dirProp: elProp` // canonical syntax: `dirProp: elProp`

@ -23,7 +23,7 @@ export abstract class GenericBrowserDomAdapter extends DomAdapter {
} }
} }
} }
var transEndEventNames = { var transEndEventNames: {[key: string]: string} = {
WebkitTransition: 'webkitTransitionEnd', WebkitTransition: 'webkitTransitionEnd',
MozTransition: 'transitionend', MozTransition: 'transitionend',
OTransition: 'oTransitionEnd otransitionend', OTransition: 'oTransitionEnd otransitionend',

@ -17,7 +17,7 @@ import {
import {BaseException, WrappedException} from 'angular2/src/core/facade/exceptions'; import {BaseException, WrappedException} from 'angular2/src/core/facade/exceptions';
import {SelectorMatcher, CssSelector} from 'angular2/src/core/compiler/selector'; import {SelectorMatcher, CssSelector} from 'angular2/src/core/compiler/selector';
var _attrToPropMap = { var _attrToPropMap: {[key: string]: string} = {
'class': 'className', 'class': 'className',
'innerHtml': 'innerHTML', 'innerHtml': 'innerHTML',
'readonly': 'readOnly', 'readonly': 'readOnly',

@ -86,7 +86,7 @@ export class MapWrapper {
return result; return result;
} }
static toStringMap<T>(m: Map<string, T>): {[key: string]: T} { static toStringMap<T>(m: Map<string, T>): {[key: string]: T} {
var r = {}; var r: {[key: string]: T} = {};
m.forEach((v, k) => r[k] = v); m.forEach((v, k) => r[k] = v);
return r; return r;
} }
@ -135,7 +135,7 @@ export class StringMapWrapper {
} }
static merge<V>(m1: {[key: string]: V}, m2: {[key: string]: V}): {[key: string]: V} { static merge<V>(m1: {[key: string]: V}, m2: {[key: string]: V}): {[key: string]: V} {
var m = {}; var m: {[key: string]: V} = {};
for (var attr in m1) { for (var attr in m1) {
if (m1.hasOwnProperty(attr)) { if (m1.hasOwnProperty(attr)) {

@ -97,7 +97,7 @@ export class FormBuilder {
} }
_reduceControls(controlsConfig: any): {[key: string]: modelModule.AbstractControl} { _reduceControls(controlsConfig: any): {[key: string]: modelModule.AbstractControl} {
var controls = {}; var controls: {[key: string]: modelModule.AbstractControl} = {};
StringMapWrapper.forEach(controlsConfig, (controlConfig, controlName) => { StringMapWrapper.forEach(controlsConfig, (controlConfig, controlName) => {
controls[controlName] = this._createControl(controlConfig); controls[controlName] = this._createControl(controlConfig);
}); });

@ -29,14 +29,14 @@ export class Validators {
return function(control: modelModule.Control) { return function(control: modelModule.Control) {
var res = ListWrapper.reduce(validators, (res, validator) => { var res = ListWrapper.reduce(validators, (res, validator) => {
var errors = validator(control); var errors = validator(control);
return isPresent(errors) ? StringMapWrapper.merge(res, errors) : res; return isPresent(errors) ? StringMapWrapper.merge(<any>res, <any>errors) : res;
}, {}); }, {});
return StringMapWrapper.isEmpty(res) ? null : res; return StringMapWrapper.isEmpty(res) ? null : res;
}; };
} }
static group(group: modelModule.ControlGroup): {[key: string]: boolean} { static group(group: modelModule.ControlGroup): {[key: string]: any[]} {
var res = {}; var res: {[key: string]: any[]} = {};
StringMapWrapper.forEach(group.controls, (control, name) => { StringMapWrapper.forEach(group.controls, (control, name) => {
if (group.contains(name) && isPresent(control.errors)) { if (group.contains(name) && isPresent(control.errors)) {
Validators._mergeErrors(control, res); Validators._mergeErrors(control, res);
@ -45,8 +45,8 @@ export class Validators {
return StringMapWrapper.isEmpty(res) ? null : res; return StringMapWrapper.isEmpty(res) ? null : res;
} }
static array(array: modelModule.ControlArray): {[key: string]: boolean} { static array(array: modelModule.ControlArray): {[key: string]: any[]} {
var res = {}; var res: {[key: string]: any[]} = {};
array.controls.forEach((control) => { array.controls.forEach((control) => {
if (isPresent(control.errors)) { if (isPresent(control.errors)) {
Validators._mergeErrors(control, res); Validators._mergeErrors(control, res);

@ -46,8 +46,8 @@ export class DirectiveResolver {
propertyMetadata: {[key: string]: any[]}): DirectiveMetadata { propertyMetadata: {[key: string]: any[]}): DirectiveMetadata {
var inputs = []; var inputs = [];
var outputs = []; var outputs = [];
var host = {}; var host: {[key: string]: string} = {};
var queries = {}; var queries: {[key: string]: any} = {};
StringMapWrapper.forEach(propertyMetadata, (metadata: any[], propName: string) => { StringMapWrapper.forEach(propertyMetadata, (metadata: any[], propName: string) => {
metadata.forEach(a => { metadata.forEach(a => {

@ -55,9 +55,9 @@ export class ProtoViewFactory {
var result = this._cache.get(compiledTemplate.id); var result = this._cache.get(compiledTemplate.id);
if (isBlank(result)) { if (isBlank(result)) {
var templateData = compiledTemplate.getData(this._appId); var templateData = compiledTemplate.getData(this._appId);
result = var emptyMap: {[key: string]: PipeBinding} = {};
new AppProtoView(templateData.commands, ViewType.HOST, true, result = new AppProtoView(templateData.commands, ViewType.HOST, true,
templateData.changeDetectorFactory, null, new ProtoPipes(new Map())); templateData.changeDetectorFactory, null, new ProtoPipes(emptyMap));
this._cache.set(compiledTemplate.id, result); this._cache.set(compiledTemplate.id, result);
} }
return result; return result;

@ -81,7 +81,7 @@ var defaultLocale: string = 'en-US';
@Pipe({name: 'date'}) @Pipe({name: 'date'})
@Injectable() @Injectable()
export class DatePipe implements PipeTransform { export class DatePipe implements PipeTransform {
static _ALIASES = { static _ALIASES: {[key: string]: String} = {
'medium': 'yMMMdjms', 'medium': 'yMMMdjms',
'short': 'yMdjm', 'short': 'yMdjm',
'fullDate': 'yMMMMEEEEd', 'fullDate': 'yMMMMEEEEd',

@ -14,7 +14,7 @@ import * as cd from 'angular2/src/core/change_detection/pipes';
export class ProtoPipes { export class ProtoPipes {
static fromBindings(bindings: PipeBinding[]): ProtoPipes { static fromBindings(bindings: PipeBinding[]): ProtoPipes {
var config = {}; var config: {[key: string]: PipeBinding} = {};
bindings.forEach(b => config[b.name] = b); bindings.forEach(b => config[b.name] = b);
return new ProtoPipes(config); return new ProtoPipes(config);
} }

@ -251,7 +251,7 @@ export class NgZone {
var errorHandling; var errorHandling;
if (enableLongStackTrace) { if (enableLongStackTrace) {
errorHandling = StringMapWrapper.merge(Zone.longStackTraceZone, errorHandling = StringMapWrapper.merge(<any>Zone.longStackTraceZone,
{onError: function(e) { ngZone._onError(this, e); }}); {onError: function(e) { ngZone._onError(this, e); }});
} else { } else {
errorHandling = {onError: function(e) { ngZone._onError(this, e); }}; errorHandling = {onError: function(e) { ngZone._onError(this, e); }};

@ -44,7 +44,7 @@ export class Headers {
if (headers instanceof Headers) { if (headers instanceof Headers) {
this._headersMap = (<Headers>headers)._headersMap; this._headersMap = (<Headers>headers)._headersMap;
} else /*if (headers instanceof StringMap)*/ { } else /*if (headers instanceof StringMap)*/ {
this._headersMap = MapWrapper.createFromStringMap<string[]>(headers); this._headersMap = MapWrapper.createFromStringMap<string[]>(<{[key: string]: any}>headers);
MapWrapper.forEach(this._headersMap, (v, k) => { MapWrapper.forEach(this._headersMap, (v, k) => {
if (!isListLikeIterable(v)) { if (!isListLikeIterable(v)) {
var list = []; var list = [];

@ -155,7 +155,7 @@ export class RouteRegistry {
} }
var componentRecognizer = this._rules.get(parentComponent); var componentRecognizer = this._rules.get(parentComponent);
var auxInstructions = {}; var auxInstructions: {[key: string]: Instruction} = {};
var promises = instruction.auxUrls.map((auxSegment: Url) => { var promises = instruction.auxUrls.map((auxSegment: Url) => {
var match = componentRecognizer.recognizeAuxiliary(auxSegment); var match = componentRecognizer.recognizeAuxiliary(auxSegment);

@ -109,33 +109,33 @@ export function main() {
() => { expect(StringMapWrapper.equals({}, {})).toBe(true); }); () => { expect(StringMapWrapper.equals({}, {})).toBe(true); });
it('should return true when comparing the same map', () => { it('should return true when comparing the same map', () => {
var m1 = {'a': 1, 'b': 2, 'c': 3}; var m1: {[key: string]: number} = {'a': 1, 'b': 2, 'c': 3};
expect(StringMapWrapper.equals(m1, m1)).toBe(true); expect(StringMapWrapper.equals(m1, m1)).toBe(true);
}); });
it('should return true when comparing different maps with the same keys and values', () => { it('should return true when comparing different maps with the same keys and values', () => {
var m1 = {'a': 1, 'b': 2, 'c': 3}; var m1: {[key: string]: number} = {'a': 1, 'b': 2, 'c': 3};
var m2 = {'a': 1, 'b': 2, 'c': 3}; var m2: {[key: string]: number} = {'a': 1, 'b': 2, 'c': 3};
expect(StringMapWrapper.equals(m1, m2)).toBe(true); expect(StringMapWrapper.equals(m1, m2)).toBe(true);
}); });
it('should return false when comparing maps with different numbers of keys', () => { it('should return false when comparing maps with different numbers of keys', () => {
var m1 = {'a': 1, 'b': 2, 'c': 3}; var m1: {[key: string]: number} = {'a': 1, 'b': 2, 'c': 3};
var m2 = {'a': 1, 'b': 2, 'c': 3, 'd': 4}; var m2: {[key: string]: number} = {'a': 1, 'b': 2, 'c': 3, 'd': 4};
expect(StringMapWrapper.equals(m1, m2)).toBe(false); expect(StringMapWrapper.equals(m1, m2)).toBe(false);
expect(StringMapWrapper.equals(m2, m1)).toBe(false); expect(StringMapWrapper.equals(m2, m1)).toBe(false);
}); });
it('should return false when comparing maps with different keys', () => { it('should return false when comparing maps with different keys', () => {
var m1 = {'a': 1, 'b': 2, 'c': 3}; var m1: {[key: string]: number} = {'a': 1, 'b': 2, 'c': 3};
var m2 = {'a': 1, 'b': 2, 'CC': 3}; var m2: {[key: string]: number} = {'a': 1, 'b': 2, 'CC': 3};
expect(StringMapWrapper.equals(m1, m2)).toBe(false); expect(StringMapWrapper.equals(m1, m2)).toBe(false);
expect(StringMapWrapper.equals(m2, m1)).toBe(false); expect(StringMapWrapper.equals(m2, m1)).toBe(false);
}); });
it('should return false when comparing maps with different values', () => { it('should return false when comparing maps with different values', () => {
var m1 = {'a': 1, 'b': 2, 'c': 3}; var m1: {[key: string]: number} = {'a': 1, 'b': 2, 'c': 3};
var m2 = {'a': 1, 'b': 20, 'c': 3}; var m2: {[key: string]: number} = {'a': 1, 'b': 20, 'c': 3};
expect(StringMapWrapper.equals(m1, m2)).toBe(false); expect(StringMapWrapper.equals(m1, m2)).toBe(false);
expect(StringMapWrapper.equals(m2, m1)).toBe(false); expect(StringMapWrapper.equals(m2, m1)).toBe(false);
}); });

@ -187,7 +187,7 @@ export function main() {
} }
]; ];
browsers.forEach((browser) => { browsers.forEach((browser: {[key: string]: any}) => {
it(`should detect ${StringMapWrapper.get(browser, 'name')}`, () => { it(`should detect ${StringMapWrapper.get(browser, 'name')}`, () => {
var bd = new BrowserDetection(<string>StringMapWrapper.get(browser, 'ua')); var bd = new BrowserDetection(<string>StringMapWrapper.get(browser, 'ua'));
expect(bd.isFirefox).toBe(StringMapWrapper.get(browser, 'isFirefox')); expect(bd.isFirefox).toBe(StringMapWrapper.get(browser, 'isFirefox'));

@ -77,7 +77,7 @@ class MockMetric extends Metric {
} }
describe(): {[key: string]: string} { describe(): {[key: string]: string} {
var result = {}; var result: {[key: string]: string} = {};
result[this._id] = 'describe'; result[this._id] = 'describe';
return result; return result;
} }