diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c91489b3d88..6a2fab1312b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3758,19 +3758,17 @@ module ts { return undefined; } - // In an array literal contextually typed by a type T, the contextual type of an element expression is the corresponding - // tuple element type in T, if one exists and T is a tuple type. Otherwise, it is the type of the numeric index signature - // in T, if one exists. + // In an array literal contextually typed by a type T, the contextual type of an element expression at index N is + // the type of the property with the numeric name N in T, if one exists. Otherwise, it is the type of the numeric + // index signature in T, if one exists. function getContextualTypeForElementExpression(node: Expression): Type { var arrayLiteral = node.parent; var type = getContextualType(arrayLiteral); if (type) { - if (type.flags & TypeFlags.Tuple) { - var index = indexOf(arrayLiteral.elements, node); - var prop = getPropertyOfType(type, "" + index); - if (prop) { - return getTypeOfSymbol(prop); - } + var index = indexOf(arrayLiteral.elements, node); + var prop = getPropertyOfType(type, "" + index); + if (prop) { + return getTypeOfSymbol(prop); } return getIndexTypeOfType(type, IndexKind.Number); } @@ -3837,21 +3835,24 @@ module ts { function checkArrayLiteral(node: ArrayLiteral, contextualMapper?: TypeMapper): Type { var contextualType = getContextualType(node); - var isTupleLiteral = contextualType && (contextualType.flags & TypeFlags.Tuple) !== 0; + var elements = node.elements; var elementTypes: Type[] = []; - forEach(node.elements, element => { - var type = element.kind !== SyntaxKind.OmittedExpression ? checkExpression(element, contextualMapper) : undefinedType; - if (isTupleLiteral || !contains(elementTypes, type)) { - elementTypes.push(type); + var isTupleLiteral: boolean = false; + for (var i = 0; i < elements.length; i++) { + if (contextualType && getPropertyOfType(contextualType, "" + i)) { + isTupleLiteral = true; } - }); + var element = elements[i]; + var type = element.kind !== SyntaxKind.OmittedExpression ? checkExpression(element, contextualMapper) : undefinedType; + elementTypes.push(type); + } if (isTupleLiteral) { return createTupleType(elementTypes); } var contextualElementType = contextualType && !isInferentialContext(contextualMapper) ? getIndexTypeOfType(contextualType, IndexKind.Number) : undefined; - var elementType = getBestCommonType(elementTypes, contextualElementType, true); + var elementType = getBestCommonType(uniqueElements(elementTypes), contextualElementType, true); if (!elementType) { - elementType = elementTypes.length ? emptyObjectType : undefinedType; + elementType = elements.length ? emptyObjectType : undefinedType; } return createArrayType(elementType); } diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 8f6ac1ddfc8..221b6016ce5 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -19,8 +19,7 @@ module ts { export function contains(array: T[], value: T): boolean { if (array) { - var len = array.length; - for (var i = 0; i < len; i++) { + for (var i = 0, len = array.length; i < len; i++) { if (array[i] === value) { return true; } @@ -31,8 +30,7 @@ module ts { export function indexOf(array: T[], value: T): number { if (array) { - var len = array.length; - for (var i = 0; i < len; i++) { + for (var i = 0, len = array.length; i < len; i++) { if (array[i] === value) { return i; } @@ -42,9 +40,8 @@ module ts { } export function filter(array: T[], f: (x: T) => boolean): T[] { - var result: T[]; if (array) { - result = []; + var result: T[] = []; for (var i = 0, len = array.length; i < len; i++) { var item = array[i]; if (f(item)) { @@ -56,11 +53,9 @@ module ts { } export function map(array: T[], f: (x: T) => U): U[] { - var result: U[]; if (array) { - result = []; - var len = array.length; - for (var i = 0; i < len; i++) { + var result: U[] = []; + for (var i = 0, len = array.length; i < len; i++) { result.push(f(array[i])); } } @@ -73,6 +68,17 @@ module ts { return array1.concat(array2); } + export function uniqueElements(array: T[]): T[] { + if (array) { + var result: T[] = []; + for (var i = 0, len = array.length; i < len; i++) { + var item = array[i]; + if (!contains(result, item)) result.push(item); + } + } + return result; + } + export function sum(array: any[], prop: string): number { var result = 0; for (var i = 0; i < array.length; i++) { diff --git a/tests/baselines/reference/tupleTypes.errors.txt b/tests/baselines/reference/tupleTypes.errors.txt index 44cb22daf0f..1e1ebd07292 100644 --- a/tests/baselines/reference/tupleTypes.errors.txt +++ b/tests/baselines/reference/tupleTypes.errors.txt @@ -16,8 +16,8 @@ t = []; // Error ~ -!!! Type '[]' is not assignable to type '[number, string]': -!!! Property '0' is missing in type '[]'. +!!! Type '{}[]' is not assignable to type '[number, string]': +!!! Property '0' is missing in type '{}[]'. t = [1]; // Error ~ !!! Type '[number]' is not assignable to type '[number, string]': @@ -53,7 +53,7 @@ tt = [undefined, undefined]; tt = []; // Error ~~ -!!! Type '[]' is not assignable to type '[number, string]'. +!!! Type '{}[]' is not assignable to type '[number, string]'. var a: number[]; var a1: [number, string];