Skip to content

No excess property error for spread properties #26798

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 30, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11324,7 +11324,7 @@ namespace ts {
return hasExcessProperties(source, discriminant, /*discriminant*/ undefined, reportErrors);
}
for (const prop of getPropertiesOfObjectType(source)) {
if (!isKnownProperty(target, prop.escapedName, isComparingJsxAttributes)) {
if (!isPropertyFromSpread(prop, source.symbol) && !isKnownProperty(target, prop.escapedName, isComparingJsxAttributes)) {
if (reportErrors) {
// We know *exactly* where things went wrong when comparing the types.
// Use this property as the error node as this will be more helpful in
Expand Down Expand Up @@ -11368,6 +11368,10 @@ namespace ts {
return false;
}

function isPropertyFromSpread(prop: Symbol, container: Symbol) {
return prop.valueDeclaration && container.valueDeclaration && prop.valueDeclaration.parent !== container.valueDeclaration;
}

function eachTypeRelatedToSomeType(source: UnionOrIntersectionType, target: UnionOrIntersectionType): Ternary {
let result = Ternary.True;
const sourceTypes = source.types;
Expand Down
27 changes: 1 addition & 26 deletions tests/baselines/reference/objectSpreadNegative.errors.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,9 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(53,9): error TS2339
tests/cases/conformance/types/spread/objectSpreadNegative.ts(58,11): error TS2339: Property 'a' does not exist on type '{}'.
tests/cases/conformance/types/spread/objectSpreadNegative.ts(62,14): error TS2698: Spread types may only be created from object types.
tests/cases/conformance/types/spread/objectSpreadNegative.ts(65,14): error TS2698: Spread types may only be created from object types.
tests/cases/conformance/types/spread/objectSpreadNegative.ts(79,37): error TS2322: Type '{ a: string; b: string; extra: string; }' is not assignable to type 'A'.
Object literal may only specify known properties, and 'extra' does not exist in type 'A'.
tests/cases/conformance/types/spread/objectSpreadNegative.ts(82,7): error TS2322: Type '{ a: string; b: string; extra: string; }' is not assignable to type 'A'.
Object literal may only specify known properties, and 'extra' does not exist in type 'A'.
tests/cases/conformance/types/spread/objectSpreadNegative.ts(84,7): error TS2322: Type '{ a: string; b: string; extra: string; }' is not assignable to type 'A'.
Object literal may only specify known properties, and 'extra' does not exist in type 'A'.


==== tests/cases/conformance/types/spread/objectSpreadNegative.ts (20 errors) ====
==== tests/cases/conformance/types/spread/objectSpreadNegative.ts (17 errors) ====
let o = { a: 1, b: 'no' }

/// private propagates
Expand Down Expand Up @@ -138,23 +132,4 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(84,7): error TS2322
f({ a: 1 }, { a: 'mismatch' })
let overwriteId: { id: string, a: number, c: number, d: string } =
f({ a: 1, id: true }, { c: 1, d: 'no' })

// excess property checks
type A = { a: string, b: string };
type Extra = { a: string, b: string, extra: string };
const extra1: A = { a: "a", b: "b", extra: "extra" };
~~~~~~~~~~~~~~
!!! error TS2322: Type '{ a: string; b: string; extra: string; }' is not assignable to type 'A'.
!!! error TS2322: Object literal may only specify known properties, and 'extra' does not exist in type 'A'.
const extra2 = { a: "a", b: "b", extra: "extra" };
const a1: A = { ...extra1 }; // error spans should be here
const a2: A = { ...extra2 }; // not on the symbol declarations above
~~
!!! error TS2322: Type '{ a: string; b: string; extra: string; }' is not assignable to type 'A'.
!!! error TS2322: Object literal may only specify known properties, and 'extra' does not exist in type 'A'.
const extra3: Extra = { a: "a", b: "b", extra: "extra" };
const a3: A = { ...extra3 }; // same here
~~
!!! error TS2322: Type '{ a: string; b: string; extra: string; }' is not assignable to type 'A'.
!!! error TS2322: Object literal may only specify known properties, and 'extra' does not exist in type 'A'.

16 changes: 0 additions & 16 deletions tests/baselines/reference/objectSpreadNegative.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,16 +73,6 @@ let overlapConflict: { id:string, a: string } =
f({ a: 1 }, { a: 'mismatch' })
let overwriteId: { id: string, a: number, c: number, d: string } =
f({ a: 1, id: true }, { c: 1, d: 'no' })

// excess property checks
type A = { a: string, b: string };
type Extra = { a: string, b: string, extra: string };
const extra1: A = { a: "a", b: "b", extra: "extra" };
const extra2 = { a: "a", b: "b", extra: "extra" };
const a1: A = { ...extra1 }; // error spans should be here
const a2: A = { ...extra2 }; // not on the symbol declarations above
const extra3: Extra = { a: "a", b: "b", extra: "extra" };
const a3: A = { ...extra3 }; // same here


//// [objectSpreadNegative.js]
Expand Down Expand Up @@ -167,9 +157,3 @@ var exclusive = f({ a: 1, b: 'yes' }, { c: 'no', d: false });
var overlap = f({ a: 1 }, { a: 2, b: 'extra' });
var overlapConflict = f({ a: 1 }, { a: 'mismatch' });
var overwriteId = f({ a: 1, id: true }, { c: 1, d: 'no' });
var extra1 = { a: "a", b: "b", extra: "extra" };
var extra2 = { a: "a", b: "b", extra: "extra" };
var a1 = __assign({}, extra1); // error spans should be here
var a2 = __assign({}, extra2); // not on the symbol declarations above
var extra3 = { a: "a", b: "b", extra: "extra" };
var a3 = __assign({}, extra3); // same here
47 changes: 0 additions & 47 deletions tests/baselines/reference/objectSpreadNegative.symbols
Original file line number Diff line number Diff line change
Expand Up @@ -243,50 +243,3 @@ let overwriteId: { id: string, a: number, c: number, d: string } =
>c : Symbol(c, Decl(objectSpreadNegative.ts, 73, 27))
>d : Symbol(d, Decl(objectSpreadNegative.ts, 73, 33))

// excess property checks
type A = { a: string, b: string };
>A : Symbol(A, Decl(objectSpreadNegative.ts, 73, 44))
>a : Symbol(a, Decl(objectSpreadNegative.ts, 76, 10))
>b : Symbol(b, Decl(objectSpreadNegative.ts, 76, 21))

type Extra = { a: string, b: string, extra: string };
>Extra : Symbol(Extra, Decl(objectSpreadNegative.ts, 76, 34))
>a : Symbol(a, Decl(objectSpreadNegative.ts, 77, 14))
>b : Symbol(b, Decl(objectSpreadNegative.ts, 77, 25))
>extra : Symbol(extra, Decl(objectSpreadNegative.ts, 77, 36))

const extra1: A = { a: "a", b: "b", extra: "extra" };
>extra1 : Symbol(extra1, Decl(objectSpreadNegative.ts, 78, 5))
>A : Symbol(A, Decl(objectSpreadNegative.ts, 73, 44))
>a : Symbol(a, Decl(objectSpreadNegative.ts, 78, 19))
>b : Symbol(b, Decl(objectSpreadNegative.ts, 78, 27))
>extra : Symbol(extra, Decl(objectSpreadNegative.ts, 78, 35))

const extra2 = { a: "a", b: "b", extra: "extra" };
>extra2 : Symbol(extra2, Decl(objectSpreadNegative.ts, 79, 5))
>a : Symbol(a, Decl(objectSpreadNegative.ts, 79, 16))
>b : Symbol(b, Decl(objectSpreadNegative.ts, 79, 24))
>extra : Symbol(extra, Decl(objectSpreadNegative.ts, 79, 32))

const a1: A = { ...extra1 }; // error spans should be here
>a1 : Symbol(a1, Decl(objectSpreadNegative.ts, 80, 5))
>A : Symbol(A, Decl(objectSpreadNegative.ts, 73, 44))
>extra1 : Symbol(extra1, Decl(objectSpreadNegative.ts, 78, 5))

const a2: A = { ...extra2 }; // not on the symbol declarations above
>a2 : Symbol(a2, Decl(objectSpreadNegative.ts, 81, 5))
>A : Symbol(A, Decl(objectSpreadNegative.ts, 73, 44))
>extra2 : Symbol(extra2, Decl(objectSpreadNegative.ts, 79, 5))

const extra3: Extra = { a: "a", b: "b", extra: "extra" };
>extra3 : Symbol(extra3, Decl(objectSpreadNegative.ts, 82, 5))
>Extra : Symbol(Extra, Decl(objectSpreadNegative.ts, 76, 34))
>a : Symbol(a, Decl(objectSpreadNegative.ts, 82, 23))
>b : Symbol(b, Decl(objectSpreadNegative.ts, 82, 31))
>extra : Symbol(extra, Decl(objectSpreadNegative.ts, 82, 39))

const a3: A = { ...extra3 }; // same here
>a3 : Symbol(a3, Decl(objectSpreadNegative.ts, 83, 5))
>A : Symbol(A, Decl(objectSpreadNegative.ts, 73, 44))
>extra3 : Symbol(extra3, Decl(objectSpreadNegative.ts, 82, 5))

57 changes: 0 additions & 57 deletions tests/baselines/reference/objectSpreadNegative.types
Original file line number Diff line number Diff line change
Expand Up @@ -325,60 +325,3 @@ let overwriteId: { id: string, a: number, c: number, d: string } =
>d : string
>'no' : "no"

// excess property checks
type A = { a: string, b: string };
>A : A
>a : string
>b : string

type Extra = { a: string, b: string, extra: string };
>Extra : Extra
>a : string
>b : string
>extra : string

const extra1: A = { a: "a", b: "b", extra: "extra" };
>extra1 : A
>{ a: "a", b: "b", extra: "extra" } : { a: string; b: string; extra: string; }
>a : string
>"a" : "a"
>b : string
>"b" : "b"
>extra : string
>"extra" : "extra"

const extra2 = { a: "a", b: "b", extra: "extra" };
>extra2 : { a: string; b: string; extra: string; }
>{ a: "a", b: "b", extra: "extra" } : { a: string; b: string; extra: string; }
>a : string
>"a" : "a"
>b : string
>"b" : "b"
>extra : string
>"extra" : "extra"

const a1: A = { ...extra1 }; // error spans should be here
>a1 : A
>{ ...extra1 } : { a: string; b: string; }
>extra1 : A

const a2: A = { ...extra2 }; // not on the symbol declarations above
>a2 : A
>{ ...extra2 } : { a: string; b: string; extra: string; }
>extra2 : { a: string; b: string; extra: string; }

const extra3: Extra = { a: "a", b: "b", extra: "extra" };
>extra3 : Extra
>{ a: "a", b: "b", extra: "extra" } : { a: string; b: string; extra: string; }
>a : string
>"a" : "a"
>b : string
>"b" : "b"
>extra : string
>"extra" : "extra"

const a3: A = { ...extra3 }; // same here
>a3 : A
>{ ...extra3 } : { a: string; b: string; extra: string; }
>extra3 : Extra

20 changes: 20 additions & 0 deletions tests/baselines/reference/spreadExcessProperty.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//// [spreadExcessProperty.ts]
type A = { a: string, b: string };
const extra1 = { a: "a", b: "b", extra: "extra" };
const a1: A = { ...extra1 }; // spread should not give excess property errors


//// [spreadExcessProperty.js]
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var extra1 = { a: "a", b: "b", extra: "extra" };
var a1 = __assign({}, extra1); // spread should not give excess property errors
17 changes: 17 additions & 0 deletions tests/baselines/reference/spreadExcessProperty.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
=== tests/cases/conformance/types/spread/spreadExcessProperty.ts ===
type A = { a: string, b: string };
>A : Symbol(A, Decl(spreadExcessProperty.ts, 0, 0))
>a : Symbol(a, Decl(spreadExcessProperty.ts, 0, 10))
>b : Symbol(b, Decl(spreadExcessProperty.ts, 0, 21))

const extra1 = { a: "a", b: "b", extra: "extra" };
>extra1 : Symbol(extra1, Decl(spreadExcessProperty.ts, 1, 5))
>a : Symbol(a, Decl(spreadExcessProperty.ts, 1, 16))
>b : Symbol(b, Decl(spreadExcessProperty.ts, 1, 24))
>extra : Symbol(extra, Decl(spreadExcessProperty.ts, 1, 32))

const a1: A = { ...extra1 }; // spread should not give excess property errors
>a1 : Symbol(a1, Decl(spreadExcessProperty.ts, 2, 5))
>A : Symbol(A, Decl(spreadExcessProperty.ts, 0, 0))
>extra1 : Symbol(extra1, Decl(spreadExcessProperty.ts, 1, 5))

21 changes: 21 additions & 0 deletions tests/baselines/reference/spreadExcessProperty.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
=== tests/cases/conformance/types/spread/spreadExcessProperty.ts ===
type A = { a: string, b: string };
>A : A
>a : string
>b : string

const extra1 = { a: "a", b: "b", extra: "extra" };
>extra1 : { a: string; b: string; extra: string; }
>{ a: "a", b: "b", extra: "extra" } : { a: string; b: string; extra: string; }
>a : string
>"a" : "a"
>b : string
>"b" : "b"
>extra : string
>"extra" : "extra"

const a1: A = { ...extra1 }; // spread should not give excess property errors
>a1 : A
>{ ...extra1 } : { a: string; b: string; extra: string; }
>extra1 : { a: string; b: string; extra: string; }

10 changes: 0 additions & 10 deletions tests/cases/conformance/types/spread/objectSpreadNegative.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,3 @@ let overlapConflict: { id:string, a: string } =
f({ a: 1 }, { a: 'mismatch' })
let overwriteId: { id: string, a: number, c: number, d: string } =
f({ a: 1, id: true }, { c: 1, d: 'no' })

// excess property checks
type A = { a: string, b: string };
type Extra = { a: string, b: string, extra: string };
const extra1: A = { a: "a", b: "b", extra: "extra" };
const extra2 = { a: "a", b: "b", extra: "extra" };
const a1: A = { ...extra1 }; // error spans should be here
const a2: A = { ...extra2 }; // not on the symbol declarations above
const extra3: Extra = { a: "a", b: "b", extra: "extra" };
const a3: A = { ...extra3 }; // same here
3 changes: 3 additions & 0 deletions tests/cases/conformance/types/spread/spreadExcessProperty.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
type A = { a: string, b: string };
const extra1 = { a: "a", b: "b", extra: "extra" };
const a1: A = { ...extra1 }; // spread should not give excess property errors