Skip to content

Commit

Permalink
Merge pull request #12564 from Microsoft/rest-of-untyped-binding-patt…
Browse files Browse the repository at this point in the history
…ern-is-any

Rest of untyped binding pattern is { [s: string]: any }
  • Loading branch information
sandersn authored Dec 1, 2016
2 parents 09f158d + 7722631 commit fc1f6e3
Show file tree
Hide file tree
Showing 8 changed files with 58 additions and 5 deletions.
14 changes: 10 additions & 4 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3319,14 +3319,19 @@ namespace ts {
// Return the type implied by an object binding pattern
function getTypeFromObjectBindingPattern(pattern: ObjectBindingPattern, includePatternInType: boolean, reportErrors: boolean): Type {
const members = createMap<Symbol>();
let stringIndexInfo: IndexInfo;
let hasComputedProperties = false;
forEach(pattern.elements, e => {
const name = e.propertyName || <Identifier>e.name;
if (isComputedNonLiteralName(name) || e.dotDotDotToken) {
// do not include computed properties or rests in the implied type
if (isComputedNonLiteralName(name)) {
// do not include computed properties in the implied type
hasComputedProperties = true;
return;
}
if (e.dotDotDotToken) {
stringIndexInfo = createIndexInfo(anyType, /*isReadonly*/ false);
return;
}

const text = getTextOfPropertyName(name);
const flags = SymbolFlags.Property | SymbolFlags.Transient | (e.initializer ? SymbolFlags.Optional : 0);
Expand All @@ -3335,7 +3340,7 @@ namespace ts {
symbol.bindingElement = e;
members[symbol.name] = symbol;
});
const result = createAnonymousType(undefined, members, emptyArray, emptyArray, undefined, undefined);
const result = createAnonymousType(undefined, members, emptyArray, emptyArray, stringIndexInfo, undefined);
if (includePatternInType) {
result.pattern = pattern;
}
Expand Down Expand Up @@ -11447,7 +11452,8 @@ namespace ts {
if (impliedProp) {
prop.flags |= impliedProp.flags & SymbolFlags.Optional;
}
else if (!compilerOptions.suppressExcessPropertyErrors) {

else if (!compilerOptions.suppressExcessPropertyErrors && !getIndexInfoOfType(contextualType, IndexKind.String)) {
error(memberDecl.name, Diagnostics.Object_literal_may_only_specify_known_properties_and_0_does_not_exist_in_type_1,
symbolToString(member), typeToString(contextualType));
}
Expand Down
6 changes: 6 additions & 0 deletions tests/baselines/reference/objectRest.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ let computed = 'b';
let computed2 = 'a';
var { [computed]: stillNotGreat, [computed2]: soSo, ...o } = o;
({ [computed]: stillNotGreat, [computed2]: soSo, ...o } = o);

var noContextualType = ({ aNumber = 12, ...notEmptyObject }) => aNumber + notEmptyObject['anythingGoes'];


//// [objectRest.js]
Expand Down Expand Up @@ -76,4 +78,8 @@ let computed = 'b';
let computed2 = 'a';
var _g = computed, stillNotGreat = o[_g], _h = computed2, soSo = o[_h], o = __rest(o, [typeof _g === "symbol" ? _g : _g + "", typeof _h === "symbol" ? _h : _h + ""]);
(_j = computed, stillNotGreat = o[_j], _k = computed2, soSo = o[_k], o = __rest(o, [typeof _j === "symbol" ? _j : _j + "", typeof _k === "symbol" ? _k : _k + ""]));
var noContextualType = (_a) => {
var { aNumber = 12 } = _a, notEmptyObject = __rest(_a, ["aNumber"]);
return aNumber + notEmptyObject['anythingGoes'];
};
var _d, _f, _j, _k;
7 changes: 7 additions & 0 deletions tests/baselines/reference/objectRest.symbols
Original file line number Diff line number Diff line change
Expand Up @@ -169,3 +169,10 @@ var { [computed]: stillNotGreat, [computed2]: soSo, ...o } = o;
>o : Symbol(o, Decl(objectRest.ts, 0, 3), Decl(objectRest.ts, 35, 51))
>o : Symbol(o, Decl(objectRest.ts, 0, 3), Decl(objectRest.ts, 35, 51))

var noContextualType = ({ aNumber = 12, ...notEmptyObject }) => aNumber + notEmptyObject['anythingGoes'];
>noContextualType : Symbol(noContextualType, Decl(objectRest.ts, 38, 3))
>aNumber : Symbol(aNumber, Decl(objectRest.ts, 38, 25))
>notEmptyObject : Symbol(notEmptyObject, Decl(objectRest.ts, 38, 39))
>aNumber : Symbol(aNumber, Decl(objectRest.ts, 38, 25))
>notEmptyObject : Symbol(notEmptyObject, Decl(objectRest.ts, 38, 39))

12 changes: 12 additions & 0 deletions tests/baselines/reference/objectRest.types
Original file line number Diff line number Diff line change
Expand Up @@ -195,3 +195,15 @@ var { [computed]: stillNotGreat, [computed2]: soSo, ...o } = o;
>o : { a: number; b: string; }
>o : { a: number; b: string; }

var noContextualType = ({ aNumber = 12, ...notEmptyObject }) => aNumber + notEmptyObject['anythingGoes'];
>noContextualType : ({aNumber, ...notEmptyObject}: { [x: string]: any; aNumber?: number; }) => any
>({ aNumber = 12, ...notEmptyObject }) => aNumber + notEmptyObject['anythingGoes'] : ({aNumber, ...notEmptyObject}: { [x: string]: any; aNumber?: number; }) => any
>aNumber : number
>12 : 12
>notEmptyObject : { [x: string]: any; }
>aNumber + notEmptyObject['anythingGoes'] : any
>aNumber : number
>notEmptyObject['anythingGoes'] : any
>notEmptyObject : { [x: string]: any; }
>'anythingGoes' : "anythingGoes"

13 changes: 12 additions & 1 deletion tests/baselines/reference/objectRestNegative.errors.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@ tests/cases/conformance/types/rest/objectRestNegative.ts(6,10): error TS2322: Ty
Types of property 'a' are incompatible.
Type 'number' is not assignable to type 'string'.
tests/cases/conformance/types/rest/objectRestNegative.ts(9,31): error TS2462: A rest element must be last in a destructuring pattern
tests/cases/conformance/types/rest/objectRestNegative.ts(11,30): error TS7008: Member 'x' implicitly has an 'any' type.
tests/cases/conformance/types/rest/objectRestNegative.ts(11,33): error TS7008: Member 'y' implicitly has an 'any' type.
tests/cases/conformance/types/rest/objectRestNegative.ts(12,17): error TS2700: Rest types may only be created from object types.
tests/cases/conformance/types/rest/objectRestNegative.ts(17,9): error TS2701: The target of an object rest assignment must be a variable or a property access.
tests/cases/conformance/types/rest/objectRestNegative.ts(19,90): error TS2339: Property 'anythingGoes' does not exist on type '{ [x: string]: any; }'.


==== tests/cases/conformance/types/rest/objectRestNegative.ts (5 errors) ====
==== tests/cases/conformance/types/rest/objectRestNegative.ts (8 errors) ====
let o = { a: 1, b: 'no' };
var { ...mustBeLast, a } = o;
~~~~~~~~~~
Expand All @@ -27,6 +30,10 @@ tests/cases/conformance/types/rest/objectRestNegative.ts(17,9): error TS2701: Th
!!! error TS2462: A rest element must be last in a destructuring pattern
}
function generic<T extends { x, y }>(t: T) {
~~
!!! error TS7008: Member 'x' implicitly has an 'any' type.
~
!!! error TS7008: Member 'y' implicitly has an 'any' type.
let { x, ...rest } = t;
~~~~
!!! error TS2700: Rest types may only be created from object types.
Expand All @@ -37,4 +44,8 @@ tests/cases/conformance/types/rest/objectRestNegative.ts(17,9): error TS2701: Th
({a, ...rest.b + rest.b} = o);
~~~~~~~~~~~~~~~
!!! error TS2701: The target of an object rest assignment must be a variable or a property access.

var noContextualType = ({ aNumber = 12, ...notEmptyObject }) => aNumber + notEmptyObject.anythingGoes;
~~~~~~~~~~~~
!!! error TS2339: Property 'anythingGoes' does not exist on type '{ [x: string]: any; }'.

6 changes: 6 additions & 0 deletions tests/baselines/reference/objectRestNegative.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ function generic<T extends { x, y }>(t: T) {

let rest: { b: string }
({a, ...rest.b + rest.b} = o);

var noContextualType = ({ aNumber = 12, ...notEmptyObject }) => aNumber + notEmptyObject.anythingGoes;


//// [objectRestNegative.js]
Expand All @@ -42,3 +44,7 @@ function generic(t) {
}
var rest;
(a = o.a, o, rest.b + rest.b = __rest(o, ["a"]));
var noContextualType = function (_a) {
var _b = _a.aNumber, aNumber = _b === void 0 ? 12 : _b, notEmptyObject = __rest(_a, ["aNumber"]);
return aNumber + notEmptyObject.anythingGoes;
};
2 changes: 2 additions & 0 deletions tests/cases/conformance/types/rest/objectRest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,5 @@ let computed = 'b';
let computed2 = 'a';
var { [computed]: stillNotGreat, [computed2]: soSo, ...o } = o;
({ [computed]: stillNotGreat, [computed2]: soSo, ...o } = o);

var noContextualType = ({ aNumber = 12, ...notEmptyObject }) => aNumber + notEmptyObject['anythingGoes'];
3 changes: 3 additions & 0 deletions tests/cases/conformance/types/rest/objectRestNegative.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// @noImplicitAny: true
let o = { a: 1, b: 'no' };
var { ...mustBeLast, a } = o;

Expand All @@ -15,3 +16,5 @@ function generic<T extends { x, y }>(t: T) {

let rest: { b: string }
({a, ...rest.b + rest.b} = o);

var noContextualType = ({ aNumber = 12, ...notEmptyObject }) => aNumber + notEmptyObject.anythingGoes;

0 comments on commit fc1f6e3

Please sign in to comment.