No excess property error for spread properties (#26798)

That is, properties in an object literal type that came from a spread
assignment never cause an excess property error.
This commit is contained in:
Nathan Shively-Sanders 2018-08-30 16:16:58 -07:00 committed by GitHub
parent cd37e41d3d
commit b687caf3eb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 67 additions and 157 deletions

View file

@ -11328,7 +11328,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
@ -11372,6 +11372,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;

View file

@ -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
@ -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'.

View file

@ -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]
@ -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

View file

@ -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))

View file

@ -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

View file

@ -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

View file

@ -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))

View file

@ -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; }

View file

@ -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

View file

@ -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