@@ -2245,7 +2245,7 @@ namespace ts {
22452245 writeUnionOrIntersectionType(<UnionOrIntersectionType>type, nextFlags);
22462246 }
22472247 else if (type.flags & TypeFlags.Spread) {
2248- writeSpreadType(<SpreadType> type);
2248+ writeSpreadType(type as SpreadType );
22492249 }
22502250 else if (getObjectFlags(type) & ObjectFlags.Anonymous) {
22512251 writeAnonymousType(<ObjectType>type, nextFlags);
@@ -3028,26 +3028,31 @@ namespace ts {
30283028 return symbol && getSymbolLinks(symbol).type || getTypeForVariableLikeDeclaration(node, /*includeOptionality*/ false);
30293029 }
30303030
3031- function getTextOfPropertyName(name: PropertyName): string {
3032- switch (name.kind) {
3033- case SyntaxKind.Identifier:
3034- return (<Identifier>name).text;
3035- case SyntaxKind.StringLiteral:
3036- case SyntaxKind.NumericLiteral:
3037- return (<LiteralExpression>name).text;
3038- case SyntaxKind.ComputedPropertyName:
3039- if (isStringOrNumericLiteral((<ComputedPropertyName>name).expression.kind)) {
3040- return (<LiteralExpression>(<ComputedPropertyName>name).expression).text;
3041- }
3042- }
3043-
3044- return undefined;
3045- }
3046-
30473031 function isComputedNonLiteralName(name: PropertyName): boolean {
30483032 return name.kind === SyntaxKind.ComputedPropertyName && !isStringOrNumericLiteral((<ComputedPropertyName>name).expression.kind);
30493033 }
30503034
3035+ function getRestType(source: Type, properties: PropertyName[], symbol: Symbol): Type {
3036+ Debug.assert(!!(source.flags & TypeFlags.Object), "Rest types only support object types right now.");
3037+ const members = createMap<Symbol>();
3038+ const names = createMap<true>();
3039+ for (const name of properties) {
3040+ names[getTextOfPropertyName(name)] = true;
3041+ }
3042+ for (const prop of getPropertiesOfType(source)) {
3043+ const inNamesToRemove = prop.name in names;
3044+ const isPrivate = getDeclarationModifierFlagsFromSymbol(prop) & (ModifierFlags.Private | ModifierFlags.Protected);
3045+ const isMethod = prop.flags & SymbolFlags.Method;
3046+ const isSetOnlyAccessor = prop.flags & SymbolFlags.SetAccessor && !(prop.flags & SymbolFlags.GetAccessor);
3047+ if (!inNamesToRemove && !isPrivate && !isMethod && !isSetOnlyAccessor) {
3048+ members[prop.name] = prop;
3049+ }
3050+ }
3051+ const stringIndexInfo = getIndexInfoOfType(source, IndexKind.String);
3052+ const numberIndexInfo = getIndexInfoOfType(source, IndexKind.Number);
3053+ return createAnonymousType(symbol, members, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo);
3054+ }
3055+
30513056 /** Return the inferred type for a binding element */
30523057 function getTypeForBindingElement(declaration: BindingElement): Type {
30533058 const pattern = <BindingPattern>declaration.parent;
@@ -3068,26 +3073,41 @@ namespace ts {
30683073
30693074 let type: Type;
30703075 if (pattern.kind === SyntaxKind.ObjectBindingPattern) {
3071- // Use explicitly specified property name ({ p: xxx } form), or otherwise the implied name ({ p } form)
3072- const name = declaration.propertyName || <Identifier>declaration.name;
3073- if (isComputedNonLiteralName(name)) {
3074- // computed properties with non-literal names are treated as 'any'
3075- return anyType;
3076- }
3077- if (declaration.initializer) {
3078- getContextualType(declaration.initializer);
3076+ if (declaration.dotDotDotToken) {
3077+ if (!(parentType.flags & TypeFlags.Object)) {
3078+ error(declaration, Diagnostics.Rest_types_may_only_be_created_from_object_types);
3079+ return unknownType;
3080+ }
3081+ const literalMembers: PropertyName[] = [];
3082+ for (const element of pattern.elements) {
3083+ if (element.kind !== SyntaxKind.OmittedExpression && !(element as BindingElement).dotDotDotToken) {
3084+ literalMembers.push(element.propertyName || element.name as Identifier);
3085+ }
3086+ }
3087+ type = getRestType(parentType, literalMembers, declaration.symbol);
30793088 }
3089+ else {
3090+ // Use explicitly specified property name ({ p: xxx } form), or otherwise the implied name ({ p } form)
3091+ const name = declaration.propertyName || <Identifier>declaration.name;
3092+ if (isComputedNonLiteralName(name)) {
3093+ // computed properties with non-literal names are treated as 'any'
3094+ return anyType;
3095+ }
3096+ if (declaration.initializer) {
3097+ getContextualType(declaration.initializer);
3098+ }
30803099
3081- // Use type of the specified property, or otherwise, for a numeric name, the type of the numeric index signature,
3082- // or otherwise the type of the string index signature.
3083- const text = getTextOfPropertyName(name);
3100+ // Use type of the specified property, or otherwise, for a numeric name, the type of the numeric index signature,
3101+ // or otherwise the type of the string index signature.
3102+ const text = getTextOfPropertyName(name);
30843103
3085- type = getTypeOfPropertyOfType(parentType, text) ||
3086- isNumericLiteralName(text) && getIndexTypeOfType(parentType, IndexKind.Number) ||
3087- getIndexTypeOfType(parentType, IndexKind.String);
3088- if (!type) {
3089- error(name, Diagnostics.Type_0_has_no_property_1_and_no_string_index_signature, typeToString(parentType), declarationNameToString(name));
3090- return unknownType;
3104+ type = getTypeOfPropertyOfType(parentType, text) ||
3105+ isNumericLiteralName(text) && getIndexTypeOfType(parentType, IndexKind.Number) ||
3106+ getIndexTypeOfType(parentType, IndexKind.String);
3107+ if (!type) {
3108+ error(name, Diagnostics.Type_0_has_no_property_1_and_no_string_index_signature, typeToString(parentType), declarationNameToString(name));
3109+ return unknownType;
3110+ }
30913111 }
30923112 }
30933113 else {
@@ -3295,8 +3315,8 @@ namespace ts {
32953315 let hasComputedProperties = false;
32963316 forEach(pattern.elements, e => {
32973317 const name = e.propertyName || <Identifier>e.name;
3298- if (isComputedNonLiteralName(name)) {
3299- // do not include computed properties in the implied type
3318+ if (isComputedNonLiteralName(name) || e.dotDotDotToken ) {
3319+ // do not include computed properties or rests in the implied type
33003320 hasComputedProperties = true;
33013321 return;
33023322 }
@@ -14097,7 +14117,7 @@ namespace ts {
1409714117 error(name, Diagnostics.Type_0_has_no_property_1_and_no_string_index_signature, typeToString(objectLiteralType), declarationNameToString(name));
1409814118 }
1409914119 }
14100- else {
14120+ else if (property.kind !== SyntaxKind.SpreadElementExpression) {
1410114121 error(property, Diagnostics.Property_assignment_expected);
1410214122 }
1410314123 }
@@ -14143,7 +14163,7 @@ namespace ts {
1414314163 }
1414414164 else {
1414514165 if (elementIndex < elements.length - 1) {
14146- error(element, Diagnostics.A_rest_element_must_be_last_in_an_array_destructuring_pattern );
14166+ error(element, Diagnostics.A_rest_element_must_be_last_in_a_destructuring_pattern );
1414714167 }
1414814168 else {
1414914169 const restExpression = (<SpreadExpression>element).expression;
@@ -21058,7 +21078,7 @@ namespace ts {
2105821078 if (node.dotDotDotToken) {
2105921079 const elements = (<BindingPattern>node.parent).elements;
2106021080 if (node !== lastOrUndefined(elements)) {
21061- return grammarErrorOnNode(node, Diagnostics.A_rest_element_must_be_last_in_an_array_destructuring_pattern );
21081+ return grammarErrorOnNode(node, Diagnostics.A_rest_element_must_be_last_in_a_destructuring_pattern );
2106221082 }
2106321083
2106421084 if (node.name.kind === SyntaxKind.ArrayBindingPattern || node.name.kind === SyntaxKind.ObjectBindingPattern) {
0 commit comments