Merge pull request #428 from Microsoft/tupleTypes

Adding support for tuple types (e.g. [number, string])
This commit is contained in:
Anders Hejlsberg 2014-09-15 11:12:43 -07:00
commit 11b9118cab
9 changed files with 324 additions and 43 deletions

View file

@ -102,6 +102,7 @@ module ts {
var globalBooleanType: ObjectType;
var globalRegExpType: ObjectType;
var tupleTypes: Map<TupleType> = {};
var stringLiteralTypes: Map<StringLiteralType> = {};
var emitExtends = false;
@ -649,15 +650,14 @@ module ts {
}
function isOptionalProperty(propertySymbol: Symbol): boolean {
if (propertySymbol.flags & SymbolFlags.Prototype) {
return false;
}
// class C {
// constructor(public x?) { }
// }
//
// x is an optional parameter, but it is a required property.
return (propertySymbol.valueDeclaration.flags & NodeFlags.QuestionMark) && propertySymbol.valueDeclaration.kind !== SyntaxKind.Parameter;
return propertySymbol.valueDeclaration &&
propertySymbol.valueDeclaration.flags & NodeFlags.QuestionMark &&
propertySymbol.valueDeclaration.kind !== SyntaxKind.Parameter;
}
function forEachSymbolTableInScope<T>(enclosingDeclaration: Node, callback: (symbolTable: SymbolTable) => T): T {
@ -995,6 +995,9 @@ module ts {
else if (type.flags & (TypeFlags.Class | TypeFlags.Interface | TypeFlags.Enum | TypeFlags.TypeParameter)) {
writer.writeSymbol(type.symbol, enclosingDeclaration, SymbolFlags.Type);
}
else if (type.flags & TypeFlags.Tuple) {
writeTupleType(<TupleType>type);
}
else if (type.flags & TypeFlags.Anonymous) {
writeAnonymousType(<ObjectType>type, allowFunctionOrConstructorTypeLiteral);
}
@ -1007,6 +1010,15 @@ module ts {
}
}
function writeTypeList(types: Type[]) {
for (var i = 0; i < types.length; i++) {
if (i > 0) {
writer.write(", ");
}
writeType(types[i], /*allowFunctionOrConstructorTypeLiteral*/ true);
}
}
function writeTypeReference(type: TypeReference) {
if (type.target === globalArrayType && !(flags & TypeFormatFlags.WriteArrayAsGenericType)) {
// If we are writing array element type the arrow style signatures are not allowed as
@ -1017,16 +1029,17 @@ module ts {
else {
writer.writeSymbol(type.target.symbol, enclosingDeclaration, SymbolFlags.Type);
writer.write("<");
for (var i = 0; i < type.typeArguments.length; i++) {
if (i > 0) {
writer.write(", ");
}
writeType(type.typeArguments[i], /*allowFunctionOrConstructorTypeLiteral*/ true);
}
writeTypeList(type.typeArguments);
writer.write(">");
}
}
function writeTupleType(type: TupleType) {
writer.write("[");
writeTypeList(type.elementTypes);
writer.write("]");
}
function writeAnonymousType(type: ObjectType, allowFunctionOrConstructorTypeLiteral: boolean) {
// Always use 'typeof T' for type of class, enum, and module objects
if (type.symbol && type.symbol.flags & (SymbolFlags.Class | SymbolFlags.Enum | SymbolFlags.ValueModule)) {
@ -1832,6 +1845,23 @@ module ts {
return [createSignature(undefined, classType.typeParameters, emptyArray, classType, 0, false, false)];
}
function createTupleTypeMemberSymbols(memberTypes: Type[]): SymbolTable {
var members: SymbolTable = {};
for (var i = 0; i < memberTypes.length; i++) {
var symbol = <TransientSymbol>createSymbol(SymbolFlags.Property | SymbolFlags.Transient, "" + i);
symbol.type = memberTypes[i];
members[i] = symbol;
}
return members;
}
function resolveTupleTypeMembers(type: TupleType) {
var arrayType = resolveObjectTypeMembers(createArrayType(getBestCommonType(type.elementTypes)));
var members = createTupleTypeMemberSymbols(type.elementTypes);
addInheritedMembers(members, arrayType.properties);
setObjectTypeMembers(type, members, arrayType.callSignatures, arrayType.constructSignatures, arrayType.stringIndexType, arrayType.numberIndexType);
}
function resolveAnonymousTypeMembers(type: ObjectType) {
var symbol = type.symbol;
if (symbol.flags & SymbolFlags.TypeLiteral) {
@ -1877,6 +1907,9 @@ module ts {
else if (type.flags & TypeFlags.Anonymous) {
resolveAnonymousTypeMembers(<ObjectType>type);
}
else if (type.flags & TypeFlags.Tuple) {
resolveTupleTypeMembers(<TupleType>type);
}
else {
resolveTypeReferenceMembers(<TypeReference>type);
}
@ -2241,7 +2274,7 @@ module ts {
if (type.flags & (TypeFlags.Class | TypeFlags.Interface) && type.flags & TypeFlags.Reference) {
var typeParameters = (<InterfaceType>type).typeParameters;
if (node.typeArguments && node.typeArguments.length === typeParameters.length) {
type = createTypeReference(<GenericType>type, map(node.typeArguments, t => getTypeFromTypeNode(t)));
type = createTypeReference(<GenericType>type, map(node.typeArguments, getTypeFromTypeNode));
}
else {
error(node, Diagnostics.Generic_type_0_requires_1_type_argument_s, typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType), typeParameters.length);
@ -2327,6 +2360,24 @@ module ts {
return links.resolvedType;
}
function createTupleType(elementTypes: Type[]) {
var id = getTypeListId(elementTypes);
var type = tupleTypes[id];
if (!type) {
type = tupleTypes[id] = <TupleType>createObjectType(TypeFlags.Tuple);
type.elementTypes = elementTypes;
}
return type;
}
function getTypeFromTupleTypeNode(node: TupleTypeNode): Type {
var links = getNodeLinks(node);
if (!links.resolvedType) {
links.resolvedType = createTupleType(map(node.elementTypes, getTypeFromTypeNode));
}
return links.resolvedType;
}
function getTypeFromTypeLiteralNode(node: TypeLiteralNode): Type {
var links = getNodeLinks(node);
if (!links.resolvedType) {
@ -2371,6 +2422,8 @@ module ts {
return getTypeFromTypeQueryNode(<TypeQueryNode>node);
case SyntaxKind.ArrayType:
return getTypeFromArrayTypeNode(<ArrayTypeNode>node);
case SyntaxKind.TupleType:
return getTypeFromTupleTypeNode(<TupleTypeNode>node);
case SyntaxKind.TypeLiteral:
return getTypeFromTypeLiteralNode(<TypeLiteralNode>node);
// This function assumes that an identifier or qualified name is a type expression
@ -2532,6 +2585,9 @@ module ts {
if (type.flags & TypeFlags.Reference) {
return createTypeReference((<TypeReference>type).target, instantiateList((<TypeReference>type).typeArguments, mapper, instantiateType));
}
if (type.flags & TypeFlags.Tuple) {
return createTupleType(instantiateList((<TupleType>type).elementTypes, mapper, instantiateType));
}
}
return type;
}
@ -3182,7 +3238,6 @@ module ts {
while (isArrayType(type)) {
type = (<GenericType>type).typeArguments[0];
}
return type;
}
@ -3331,9 +3386,9 @@ module ts {
inferFromTypes(sourceTypes[i], targetTypes[i]);
}
}
else if (source.flags & TypeFlags.ObjectType && (target.flags & TypeFlags.Reference || (target.flags & TypeFlags.Anonymous) &&
target.symbol && target.symbol.flags & (SymbolFlags.Method | SymbolFlags.TypeLiteral))) {
// If source is an object type, and target is a type reference, the type of a method, or a type literal, infer from members
else if (source.flags & TypeFlags.ObjectType && (target.flags & (TypeFlags.Reference | TypeFlags.Tuple) ||
(target.flags & TypeFlags.Anonymous) && target.symbol && target.symbol.flags & (SymbolFlags.Method | SymbolFlags.TypeLiteral))) {
// If source is an object type, and target is a type reference, a tuple type, the type of a method, or a type literal, infer from members
if (!isInProcess(source, target) && isWithinDepthLimit(source, sourceStack) && isWithinDepthLimit(target, targetStack)) {
if (depth === 0) {
sourceStack = [];
@ -3684,6 +3739,10 @@ module ts {
return undefined;
}
// In a variable, parameter or property declaration with a type annotation, the contextual type of an initializer
// expression is the type of the variable, parameter or property. In a parameter declaration of a contextually
// typed function expression, the contextual type of an initializer expression is the contextual type of the
// parameter.
function getContextualTypeForInitializerExpression(node: Expression): Type {
var declaration = <VariableDeclaration>node.parent;
if (node === declaration.initializer) {
@ -3715,6 +3774,7 @@ module ts {
return undefined;
}
// In a typed function call, an argument expression is contextually typed by the type of the corresponding parameter.
function getContextualTypeForArgument(node: Expression): Type {
var callExpression = <CallExpression>node.parent;
var argIndex = indexOf(callExpression.arguments, node);
@ -3729,11 +3789,14 @@ module ts {
var binaryExpression = <BinaryExpression>node.parent;
var operator = binaryExpression.operator;
if (operator >= SyntaxKind.FirstAssignment && operator <= SyntaxKind.LastAssignment) {
// In an assignment expression, the right operand is contextually typed by the type of the left operand.
if (node === binaryExpression.right) {
return checkExpression(binaryExpression.left);
}
}
else if (operator === SyntaxKind.BarBarToken) {
// When an || expression has a contextual type, the operands are contextually typed by that type. When an ||
// expression has no contextual type, the right operand is contextually typed by the type of the left operand.
var type = getContextualType(binaryExpression);
if (!type && node === binaryExpression.right) {
type = checkExpression(binaryExpression.left);
@ -3743,6 +3806,9 @@ module ts {
return undefined;
}
// In an object literal contextually typed by a type T, the contextual type of a property assignment is the type of
// the matching property in T, if one exists. Otherwise, it is the type of the numeric index signature in T, if one
// exists. Otherwise, it is the type of the string index signature in T, if one exists.
function getContextualTypeForPropertyExpression(node: Expression): Type {
var declaration = <PropertyDeclaration>node.parent;
var objectLiteral = <ObjectLiteral>declaration.parent;
@ -3758,17 +3824,31 @@ module ts {
return undefined;
}
// 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 = <ArrayLiteral>node.parent;
var type = getContextualType(arrayLiteral);
return type ? getIndexTypeOfType(type, IndexKind.Number) : undefined;
if (type) {
var index = indexOf(arrayLiteral.elements, node);
var prop = getPropertyOfType(type, "" + index);
if (prop) {
return getTypeOfSymbol(prop);
}
return getIndexTypeOfType(type, IndexKind.Number);
}
return undefined;
}
// In a contextually typed conditional expression, the true/false expressions are contextually typed by the same type.
function getContextualTypeForConditionalOperand(node: Expression): Type {
var conditional = <ConditionalExpression>node.parent;
return node === conditional.whenTrue || node === conditional.whenFalse ? getContextualType(conditional) : undefined;
}
// Return the contextual type for a given expression node. During overload resolution, a contextual type may temporarily
// be "pushed" onto a node using the contextualType property.
function getContextualType(node: Expression): Type {
if (node.contextualType) {
return node.contextualType;
@ -3820,17 +3900,26 @@ module ts {
}
function checkArrayLiteral(node: ArrayLiteral, contextualMapper?: TypeMapper): Type {
var contextualType = getContextualType(node);
var elements = node.elements;
var elementTypes: Type[] = [];
forEach(node.elements, element => {
if (element.kind !== SyntaxKind.OmittedExpression) {
var type = checkExpression(element, contextualMapper);
if (!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 contextualType = isInferentialContext(contextualMapper) ? undefined : getContextualType(node);
var contextualElementType = contextualType && getIndexTypeOfType(contextualType, IndexKind.Number);
var elementType = getBestCommonType(elementTypes, contextualElementType, true);
if (!elementType) elementType = elementTypes.length ? emptyObjectType : undefinedType;
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(uniqueElements(elementTypes), contextualElementType, true);
if (!elementType) {
elementType = elements.length ? emptyObjectType : undefinedType;
}
return createArrayType(elementType);
}
@ -3898,12 +3987,14 @@ module ts {
}
}
// If a symbol is a synthesized symbol with no value declaration, we assume it is a property. Example of this are the synthesized
// '.prototype' property as well as synthesized tuple index properties.
function getDeclarationKindFromSymbol(s: Symbol) {
return s.flags & SymbolFlags.Prototype ? SyntaxKind.Property : s.valueDeclaration.kind;
return s.valueDeclaration ? s.valueDeclaration.kind : SyntaxKind.Property;
}
function getDeclarationFlagsFromSymbol(s: Symbol) {
return s.flags & SymbolFlags.Prototype ? NodeFlags.Public | NodeFlags.Static : s.valueDeclaration.flags;
return s.valueDeclaration ? s.valueDeclaration.flags : s.flags & SymbolFlags.Prototype ? NodeFlags.Public | NodeFlags.Static : 0;
}
function checkPropertyAccess(node: PropertyAccess) {
@ -5171,7 +5262,11 @@ module ts {
}
function checkArrayType(node: ArrayTypeNode) {
getTypeFromArrayTypeNode(node);
checkSourceElement(node.elementType);
}
function checkTupleType(node: TupleTypeNode) {
forEach(node.elementTypes, checkSourceElement);
}
function isPrivateWithinAmbient(node: Node): boolean {
@ -6420,6 +6515,8 @@ module ts {
return checkTypeLiteral(<TypeLiteralNode>node);
case SyntaxKind.ArrayType:
return checkArrayType(<ArrayTypeNode>node);
case SyntaxKind.TupleType:
return checkTupleType(<TupleTypeNode>node);
case SyntaxKind.FunctionDeclaration:
return checkFunctionDeclaration(<FunctionDeclaration>node);
case SyntaxKind.Block:

View file

@ -19,8 +19,7 @@ module ts {
export function contains<T>(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<T>(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<T>(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<T, U>(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<T>(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++) {

View file

@ -84,6 +84,7 @@ module ts {
An_object_literal_cannot_have_property_and_accessor_with_the_same_name: { code: 1119, category: DiagnosticCategory.Error, key: "An object literal cannot have property and accessor with the same name." },
An_export_assignment_cannot_have_modifiers: { code: 1120, category: DiagnosticCategory.Error, key: "An export assignment cannot have modifiers." },
Octal_literals_are_not_allowed_in_strict_mode: { code: 1121, category: DiagnosticCategory.Error, key: "Octal literals are not allowed in strict mode." },
A_tuple_type_element_list_cannot_be_empty: { code: 1122, category: DiagnosticCategory.Error, key: "A tuple type element list cannot be empty." },
Variable_declaration_list_cannot_be_empty: { code: 1123, category: DiagnosticCategory.Error, key: "Variable declaration list cannot be empty." },
Digit_expected: { code: 1124, category: DiagnosticCategory.Error, key: "Digit expected." },
Hexadecimal_digit_expected: { code: 1125, category: DiagnosticCategory.Error, key: "Hexadecimal digit expected." },

View file

@ -327,6 +327,10 @@
"category": "Error",
"code": 1121
},
"A tuple type element list cannot be empty.": {
"category": "Error",
"code": 1122
},
"Variable declaration list cannot be empty.": {
"category": "Error",
"code": 1123

View file

@ -228,6 +228,8 @@ module ts {
return children((<TypeLiteralNode>node).members);
case SyntaxKind.ArrayType:
return child((<ArrayTypeNode>node).elementType);
case SyntaxKind.TupleType:
return children((<TupleTypeNode>node).elementTypes);
case SyntaxKind.ArrayLiteral:
return children((<ArrayLiteral>node).elements);
case SyntaxKind.ObjectLiteral:
@ -520,6 +522,7 @@ module ts {
Parameters, // Parameters in parameter list
TypeParameters, // Type parameters in type parameter list
TypeArguments, // Type arguments in type argument list
TupleElementTypes, // Element types in tuple element type list
Count // Number of parsing contexts
}
@ -547,6 +550,7 @@ module ts {
case ParsingContext.Parameters: return Diagnostics.Parameter_declaration_expected;
case ParsingContext.TypeParameters: return Diagnostics.Type_parameter_declaration_expected;
case ParsingContext.TypeArguments: return Diagnostics.Type_argument_expected;
case ParsingContext.TupleElementTypes: return Diagnostics.Type_expected;
}
};
@ -1015,6 +1019,7 @@ module ts {
case ParsingContext.Parameters:
return isParameter();
case ParsingContext.TypeArguments:
case ParsingContext.TupleElementTypes:
return isType();
}
@ -1050,6 +1055,7 @@ module ts {
// Tokens other than ')' are here for better error recovery
return token === SyntaxKind.CloseParenToken || token === SyntaxKind.SemicolonToken;
case ParsingContext.ArrayLiteralMembers:
case ParsingContext.TupleElementTypes:
return token === SyntaxKind.CloseBracketToken;
case ParsingContext.Parameters:
// Tokens other than ')' and ']' (the latter for index signatures) are here for better error recovery
@ -1570,6 +1576,17 @@ module ts {
return finishNode(node);
}
function parseTupleType(): TupleTypeNode {
var node = <TupleTypeNode>createNode(SyntaxKind.TupleType);
var startTokenPos = scanner.getTokenPos();
var startErrorCount = file.syntacticErrors.length;
node.elementTypes = parseBracketedList(ParsingContext.TupleElementTypes, parseType, SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken);
if (!node.elementTypes.length && file.syntacticErrors.length === startErrorCount) {
grammarErrorAtPos(startTokenPos, scanner.getStartPos() - startTokenPos, Diagnostics.A_tuple_type_element_list_cannot_be_empty);
}
return finishNode(node);
}
function parseFunctionType(signatureKind: SyntaxKind): TypeLiteralNode {
var node = <TypeLiteralNode>createNode(SyntaxKind.TypeLiteral);
var member = <SignatureDeclaration>createNode(signatureKind);
@ -1600,6 +1617,8 @@ module ts {
return parseTypeQuery();
case SyntaxKind.OpenBraceToken:
return parseTypeLiteral();
case SyntaxKind.OpenBracketToken:
return parseTupleType();
case SyntaxKind.OpenParenToken:
case SyntaxKind.LessThanToken:
return parseFunctionType(SyntaxKind.CallSignature);
@ -1623,6 +1642,7 @@ module ts {
case SyntaxKind.VoidKeyword:
case SyntaxKind.TypeOfKeyword:
case SyntaxKind.OpenBraceToken:
case SyntaxKind.OpenBracketToken:
case SyntaxKind.LessThanToken:
case SyntaxKind.NewKeyword:
return true;

View file

@ -149,6 +149,7 @@ module ts {
TypeQuery,
TypeLiteral,
ArrayType,
TupleType,
// Expression
ArrayLiteral,
ObjectLiteral,
@ -219,7 +220,7 @@ module ts {
FirstFutureReservedWord = ImplementsKeyword,
LastFutureReservedWord = YieldKeyword,
FirstTypeNode = TypeReference,
LastTypeNode = ArrayType,
LastTypeNode = TupleType,
FirstPunctuation = OpenBraceToken,
LastPunctuation = CaretEqualsToken
}
@ -320,6 +321,10 @@ module ts {
elementType: TypeNode;
}
export interface TupleTypeNode extends TypeNode {
elementTypes: NodeArray<TypeNode>;
}
export interface StringLiteralTypeNode extends TypeNode {
text: string;
}
@ -803,13 +808,14 @@ module ts {
Class = 0x00000400, // Class
Interface = 0x00000800, // Interface
Reference = 0x00001000, // Generic type reference
Anonymous = 0x00002000, // Anonymous
FromSignature = 0x00004000, // Created for signature assignment check
Tuple = 0x00002000, // Tuple
Anonymous = 0x00004000, // Anonymous
FromSignature = 0x00008000, // Created for signature assignment check
Intrinsic = Any | String | Number | Boolean | Void | Undefined | Null,
StringLike = String | StringLiteral,
NumberLike = Number | Enum,
ObjectType = Class | Interface | Reference | Anonymous
ObjectType = Class | Interface | Reference | Tuple | Anonymous
}
// Properties common to all types
@ -862,6 +868,11 @@ module ts {
openReferenceChecks: Map<boolean>; // Open type reference check cache
}
export interface TupleType extends ObjectType {
elementTypes: Type[]; // Element types
baseArrayType: TypeReference; // Array<T> where T is best common type of element types
}
// Resolved object type
export interface ResolvedObjectType extends ObjectType {
members: SymbolTable; // Properties by name

View file

@ -0,0 +1,87 @@
==== tests/cases/compiler/tupleTypes.ts (9 errors) ====
var v1: []; // Error
~~
!!! A tuple type element list cannot be empty.
var v2: [number];
var v3: [number, string];
var v4: [number, [string, string]];
var t: [number, string];
var t0 = t[0]; // number
var t0: number;
var t1 = t[1]; // string
var t1: string;
var t2 = t[2]; // {}
var t2: {};
t = []; // Error
~
!!! 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]':
!!! Property '1' is missing in type '[number]'.
t = [1, "hello"]; // Ok
t = ["hello", 1]; // Error
~
!!! Type '[string, number]' is not assignable to type '[number, string]':
!!! Types of property '0' are incompatible:
!!! Type 'string' is not assignable to type 'number'.
t = [1, "hello", 2]; // Ok
var tf: [string, (x: string) => number] = ["hello", x => x.length];
declare function ff<T, U>(a: T, b: [T, (x: T) => U]): U;
var ff1 = ff("hello", ["foo", x => x.length]);
var ff1: number;
function tuple2<T0, T1>(item0: T0, item1: T1): [T0, T1]{
return [item0, item1];
}
var tt = tuple2(1, "string");
var tt0 = tt[0];
var tt0: number;
var tt1 = tt[1];
var tt1: string;
var tt2 = tt[2];
var tt2: {};
tt = tuple2(1, undefined);
tt = [1, undefined];
tt = [undefined, undefined];
tt = []; // Error
~~
!!! Type '{}[]' is not assignable to type '[number, string]'.
var a: number[];
var a1: [number, string];
var a2: [number, number];
var a3: [number, {}];
a = a1; // Error
~
!!! Type '[number, string]' is not assignable to type 'number[]':
!!! Types of property 'pop' are incompatible:
!!! Type '() => {}' is not assignable to type '() => number':
!!! Type '{}' is not assignable to type 'number'.
a = a2;
a = a3; // Error
~
!!! Type '[number, {}]' is not assignable to type 'number[]':
!!! Types of property 'pop' are incompatible:
!!! Type '() => {}' is not assignable to type '() => number':
!!! Type '{}' is not assignable to type 'number'.
a1 = a2; // Error
~~
!!! Type '[number, number]' is not assignable to type '[number, string]':
!!! Types of property '1' are incompatible:
!!! Type 'number' is not assignable to type 'string'.
a1 = a3; // Error
~~
!!! Type '[number, {}]' is not assignable to type '[number, string]':
!!! Types of property '1' are incompatible:
!!! Type '{}' is not assignable to type 'string'.
a3 = a1;
a3 = a2;

View file

@ -1,4 +1,4 @@
==== tests/cases/compiler/typeName1.ts (16 errors) ====
==== tests/cases/compiler/typeName1.ts (17 errors) ====
interface I {
k;
}
@ -55,6 +55,8 @@
~~~
!!! Type 'number' is not assignable to type '{ z: I; x: boolean; y: (s: string) => boolean; w: { (): boolean; [x: string]: { x: any; y: any; }; [x: number]: { x: any; y: any; }; z: I; }; }[][]':
!!! Property 'length' is missing in type 'Number'.
~~~~
!!! Property 'z' of type 'I' is not assignable to string index type '{ x: any; y: any; }'.
var x13:{ new(): number; new(n:number):number; x: string; w: {y: number;}; (): {}; } = 3;
~~~
!!! Type 'number' is not assignable to type '{ (): {}; new (): number; new (n: number): number; x: string; w: { y: number; }; }':

View file

@ -0,0 +1,53 @@
var v1: []; // Error
var v2: [number];
var v3: [number, string];
var v4: [number, [string, string]];
var t: [number, string];
var t0 = t[0]; // number
var t0: number;
var t1 = t[1]; // string
var t1: string;
var t2 = t[2]; // {}
var t2: {};
t = []; // Error
t = [1]; // Error
t = [1, "hello"]; // Ok
t = ["hello", 1]; // Error
t = [1, "hello", 2]; // Ok
var tf: [string, (x: string) => number] = ["hello", x => x.length];
declare function ff<T, U>(a: T, b: [T, (x: T) => U]): U;
var ff1 = ff("hello", ["foo", x => x.length]);
var ff1: number;
function tuple2<T0, T1>(item0: T0, item1: T1): [T0, T1]{
return [item0, item1];
}
var tt = tuple2(1, "string");
var tt0 = tt[0];
var tt0: number;
var tt1 = tt[1];
var tt1: string;
var tt2 = tt[2];
var tt2: {};
tt = tuple2(1, undefined);
tt = [1, undefined];
tt = [undefined, undefined];
tt = []; // Error
var a: number[];
var a1: [number, string];
var a2: [number, number];
var a3: [number, {}];
a = a1; // Error
a = a2;
a = a3; // Error
a1 = a2; // Error
a1 = a3; // Error
a3 = a1;
a3 = a2;