Allow string or numeric literal as property name of object binding

Require RHS of array destructuring to be an actual array type (i.e. assignable to any[])
Tighten test for tuple type (previously just required a "0" property)
This commit is contained in:
Anders Hejlsberg 2014-11-22 15:38:20 -08:00
parent 38a2640053
commit 6b96386337
5 changed files with 53 additions and 30 deletions

View File

@ -150,6 +150,8 @@ module ts {
var globalRegExpType: ObjectType;
var globalTemplateStringsArrayType: ObjectType;
var anyArrayType: Type;
var tupleTypes: Map<TupleType> = {};
var unionTypes: Map<UnionType> = {};
var stringLiteralTypes: Map<StringLiteralType> = {};
@ -1643,24 +1645,24 @@ module ts {
getIndexTypeOfType(parentType, IndexKind.String);
if (!type) {
error(name, Diagnostics.Type_0_has_no_property_1_and_no_string_index_signature, typeToString(parentType), declarationNameToString(name));
return unknownType;
}
return type;
}
else {
if (getPropertyOfType(parentType, "0")) {
var propName = "" + indexOf(pattern.elements, declaration);
var type = getTypeOfPropertyOfType(parentType, propName);
if (!type) {
error(declaration, Diagnostics.Type_0_has_no_property_1, typeToString(parentType), propName);
}
}
else {
var type = getIndexTypeOfType(parentType, IndexKind.Number);
if (!type) {
error(declaration, Diagnostics.Type_0_has_no_numeric_index_signature, typeToString(parentType));
}
}
if (!isTypeAssignableTo(parentType, anyArrayType)) {
error(pattern, Diagnostics.Type_0_is_not_an_array_type, typeToString(parentType));
return unknownType;
}
return type || unknownType;
if (isTupleType(parentType)) {
var propName = "" + indexOf(pattern.elements, declaration);
var type = getTypeOfPropertyOfType(parentType, propName);
if (!type) {
error(declaration, Diagnostics.Type_0_has_no_property_1, typeToString(parentType), propName);
return unknownType;
}
return type;
}
return getIndexTypeOfType(parentType, IndexKind.Number);
}
function getTypeForVariableDeclaration(declaration: VariableDeclaration | PropertyDeclaration): Type {
@ -1739,7 +1741,8 @@ module ts {
if (isBindingPattern(declaration.name)) {
return getTypeFromBindingPattern(<BindingPattern>declaration.name);
}
// Rest parameters default to type any[], other parameters default to type any type = declaration.flags & NodeFlags.Rest ? createArrayType(anyType) : anyType;
// Rest parameters default to type any[], other parameters default to type any
type = declaration.flags & NodeFlags.Rest ? anyArrayType : anyType;
// Report implicit any errors unless this is a private property within an ambient declaration
if (reportErrors && compilerOptions.noImplicitAny && !isPrivateWithinAmbient(declaration) && !(declaration.kind === SyntaxKind.Parameter && isPrivateWithinAmbient(declaration.parent))) {
reportImplicitAnyError(declaration, type);
@ -3976,6 +3979,10 @@ module ts {
return type.flags & TypeFlags.Reference && (<TypeReference>type).target === globalArrayType;
}
function isTupleType(type: Type): boolean {
return (type.flags & TypeFlags.Tuple) !== 0;
}
function getWidenedTypeOfObjectLiteral(type: Type): Type {
var properties = getPropertiesOfObjectType(type);
var members: SymbolTable = {};
@ -4914,7 +4921,7 @@ module ts {
// Return true if the given contextual type is a tuple-like type
function contextualTypeIsTupleType(type: Type): boolean {
return !!(type.flags & TypeFlags.Union ? forEach((<UnionType>type).types, t => getPropertyOfObjectType(t, "0")) : getPropertyOfObjectType(type, "0"));
return !!(type.flags & TypeFlags.Union ? forEach((<UnionType>type).types, t => isTupleType(t)) : isTupleType(type));
}
// Return true if the given contextual type provides an index signature of the given kind
@ -6379,12 +6386,11 @@ module ts {
}
function checkArrayLiteralAssignment(node: ArrayLiteral, sourceType: Type, contextualMapper?: TypeMapper): Type {
var isTupleType = getPropertyOfType(sourceType, "0");
var elements = node.elements;
for (var i = 0; i < elements.length; i++) {
var e = elements[i];
if (e.kind !== SyntaxKind.OmittedExpression) {
if (isTupleType) {
if (isTupleType(sourceType)) {
var propName = "" + i;
var type = getTypeOfPropertyOfType(sourceType, propName);
if (!type) {
@ -9290,12 +9296,12 @@ module ts {
globalNumberType = getGlobalType("Number");
globalBooleanType = getGlobalType("Boolean");
globalRegExpType = getGlobalType("RegExp");
// If we're in ES6 mode, load the TemplateStringsArray.
// Otherwise, default to 'unknown' for the purposes of type checking in LS scenarios.
globalTemplateStringsArrayType = compilerOptions.target >= ScriptTarget.ES6
? getGlobalType("TemplateStringsArray")
: unknownType;
anyArrayType = createArrayType(anyType);
}
initializeTypeChecker();

View File

@ -281,6 +281,7 @@ module ts {
Type_0_has_no_property_1_and_no_string_index_signature: { code: 2459, category: DiagnosticCategory.Error, key: "Type '{0}' has no property '{1}' and no string index signature." },
Type_0_has_no_property_1: { code: 2460, category: DiagnosticCategory.Error, key: "Type '{0}' has no property '{1}'." },
Type_0_has_no_numeric_index_signature: { code: 2461, category: DiagnosticCategory.Error, key: "Type '{0}' has no numeric index signature." },
Type_0_is_not_an_array_type: { code: 2462, category: DiagnosticCategory.Error, key: "Type '{0}' is not an array type." },
Import_declaration_0_is_using_private_name_1: { code: 4000, category: DiagnosticCategory.Error, key: "Import declaration '{0}' is using private name '{1}'." },
Type_parameter_0_of_exported_class_has_or_is_using_name_1_from_private_module_2: { code: 4001, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of exported class has or is using name '{1}' from private module '{2}'." },
Type_parameter_0_of_exported_class_has_or_is_using_private_name_1: { code: 4002, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of exported class has or is using private name '{1}'." },

View File

@ -1120,6 +1120,10 @@
"category": "Error",
"code": 2461
},
"Type '{0}' is not an array type.": {
"category": "Error",
"code": 2462
},
"Import declaration '{0}' is using private name '{1}'.": {
"category": "Error",

View File

@ -1534,11 +1534,22 @@ module ts {
function emitParameter(node: ParameterDeclaration) {
emitLeadingComments(node);
if (node.propertyName) {
emit(node.propertyName);
write(": ");
if (compilerOptions.target < ScriptTarget.ES6) {
if (isBindingPattern(node.name)) {
write("__" + indexOf((<FunctionLikeDeclaration>node.parent).parameters, node));
}
else {
emit(node.name);
}
}
else {
if (node.propertyName) {
emit(node.propertyName);
write(": ");
}
emit(node.name);
//emitOptional(" = ", node.initializer);
}
emit(node.name);
emitTrailingComments(node);
}

View File

@ -1250,11 +1250,11 @@ module ts {
return lookAhead(isClassMemberStart);
case ParsingContext.EnumMembers:
case ParsingContext.ObjectLiteralMembers:
case ParsingContext.ObjectBindingElements:
return isPropertyName();
case ParsingContext.BaseTypeReferences:
return isIdentifier() && ((token !== SyntaxKind.ExtendsKeyword && token !== SyntaxKind.ImplementsKeyword) || !lookAhead(() => (nextToken(), isIdentifier())));
case ParsingContext.VariableDeclarations:
case ParsingContext.ObjectBindingElements:
return isIdentifierOrPattern();
case ParsingContext.ArrayBindingElements:
return token === SyntaxKind.CommaToken || isIdentifierOrPattern();
@ -3477,13 +3477,14 @@ module ts {
var node = <BindingElement>createNode(kind);
node.flags = flags;
if (context === ParsingContext.ObjectBindingElements) {
var id = parseIdentifier();
if (parseOptional(SyntaxKind.ColonToken)) {
node.propertyName = id;
node.name = parseIdentifierOrPattern(kind, flags);
var id = parsePropertyName();
if (id.kind === SyntaxKind.Identifier && token !== SyntaxKind.ColonToken) {
node.name = id;
}
else {
node.name = id;
parseExpected(SyntaxKind.ColonToken);
node.propertyName = id;
node.name = parseIdentifierOrPattern(kind, flags);
}
}
else {