diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 0a6cec7f6c..ee1d06112d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4639,7 +4639,7 @@ namespace ts { let type: Type | undefined; if (pattern.kind === SyntaxKind.ObjectBindingPattern) { if (declaration.dotDotDotToken) { - if (parentType.flags & TypeFlags.Unknown || !isValidSpreadType(parentType)) { + if (parentType.flags & TypeFlags.Unknown || !isValidSpreadType(parentType) || isGenericObjectType(parentType)) { error(declaration, Diagnostics.Rest_types_may_only_be_created_from_object_types); return errorType; } @@ -9842,6 +9842,10 @@ namespace ts { return symbol ? getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol) : undefined; } + function isNonGenericObjectType(type: Type) { + return !!(type.flags & TypeFlags.Object) && !isGenericMappedType(type); + } + /** * Since the source of spread types are object literals, which are not binary, * this function should be called in a left folding style, with left = previous result of getSpreadType @@ -9870,6 +9874,23 @@ namespace ts { return left; } + if (isGenericObjectType(left) || isGenericObjectType(right)) { + if (isEmptyObjectType(left)) { + return right; + } + // When the left type is an intersection, we may need to merge the last constituent of the + // intersection with the right type. For example when the left type is 'T & { a: string }' + // and the right type is '{ b: string }' we produce 'T & { a: string, b: string }'. + if (left.flags & TypeFlags.Intersection) { + const types = (left).types; + const lastLeft = types[types.length - 1]; + if (isNonGenericObjectType(lastLeft) && isNonGenericObjectType(right)) { + return getIntersectionType(concatenate(types.slice(0, types.length - 1), [getSpreadType(lastLeft, right, symbol, typeFlags, objectFlags)])); + } + } + return getIntersectionType([left, right]); + } + const members = createSymbolTable(); const skippedPrivateMembers = createUnderscoreEscapedMap(); let stringIndexInfo: IndexInfo | undefined; @@ -17700,9 +17721,8 @@ namespace ts { } function isValidSpreadType(type: Type): boolean { - return !!(type.flags & (TypeFlags.AnyOrUnknown | TypeFlags.NonPrimitive) || + return !!(type.flags & (TypeFlags.AnyOrUnknown | TypeFlags.NonPrimitive | TypeFlags.Object | TypeFlags.InstantiableNonPrimitive) || getFalsyFlags(type) & TypeFlags.DefinitelyFalsy && isValidSpreadType(removeDefinitelyFalsyTypes(type)) || - type.flags & TypeFlags.Object && !isGenericMappedType(type) || type.flags & TypeFlags.UnionOrIntersection && every((type).types, isValidSpreadType)); } diff --git a/tests/baselines/reference/objectSpread.js b/tests/baselines/reference/objectSpread.js index 1aef3a3bc9..b7d3e858c7 100644 --- a/tests/baselines/reference/objectSpread.js +++ b/tests/baselines/reference/objectSpread.js @@ -119,6 +119,41 @@ let a = 12; let shortCutted: { a: number, b: string } = { ...o, a } // non primitive let spreadNonPrimitive = { ...{}}; + +// generic spreads + +function f(t: T, u: U) { + return { ...t, ...u, id: 'id' }; +} + +let exclusive: { id: string, a: number, b: string, c: string, d: boolean } = + f({ a: 1, b: 'yes' }, { c: 'no', d: false }) +let overlap: { id: string, a: number, b: string } = + f({ a: 1 }, { a: 2, b: 'extra' }) +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' }) + +function genericSpread(t: T, u: U, v: T | U, w: T | { s: string }, obj: { x: number }) { + let x01 = { ...t }; + let x02 = { ...t, ...t }; + let x03 = { ...t, ...u }; + let x04 = { ...u, ...t }; + let x05 = { a: 5, b: 'hi', ...t }; + let x06 = { ...t, a: 5, b: 'hi' }; + let x07 = { a: 5, b: 'hi', ...t, c: true, ...obj }; + let x09 = { a: 5, ...t, b: 'hi', c: true, ...obj }; + let x10 = { a: 5, ...t, b: 'hi', ...u, ...obj }; + let x11 = { ...v }; + let x12 = { ...v, ...obj }; + let x13 = { ...w }; + let x14 = { ...w, ...obj }; + let x15 = { ...t, ...v }; + let x16 = { ...t, ...w }; + let x17 = { ...t, ...w, ...obj }; + let x18 = { ...t, ...v, ...w }; +} //// [objectSpread.js] @@ -214,3 +249,30 @@ var a = 12; var shortCutted = __assign({}, o, { a: a }); // non primitive var spreadNonPrimitive = __assign({}, {}); +// generic spreads +function f(t, u) { + return __assign({}, t, u, { id: 'id' }); +} +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' }); +function genericSpread(t, u, v, w, obj) { + var x01 = __assign({}, t); + var x02 = __assign({}, t, t); + var x03 = __assign({}, t, u); + var x04 = __assign({}, u, t); + var x05 = __assign({ a: 5, b: 'hi' }, t); + var x06 = __assign({}, t, { a: 5, b: 'hi' }); + var x07 = __assign({ a: 5, b: 'hi' }, t, { c: true }, obj); + var x09 = __assign({ a: 5 }, t, { b: 'hi', c: true }, obj); + var x10 = __assign({ a: 5 }, t, { b: 'hi' }, u, obj); + var x11 = __assign({}, v); + var x12 = __assign({}, v, obj); + var x13 = __assign({}, w); + var x14 = __assign({}, w, obj); + var x15 = __assign({}, t, v); + var x16 = __assign({}, t, w); + var x17 = __assign({}, t, w, obj); + var x18 = __assign({}, t, v, w); +} diff --git a/tests/baselines/reference/objectSpread.symbols b/tests/baselines/reference/objectSpread.symbols index 0bbcd4a9f4..e72772676e 100644 --- a/tests/baselines/reference/objectSpread.symbols +++ b/tests/baselines/reference/objectSpread.symbols @@ -452,3 +452,184 @@ let shortCutted: { a: number, b: string } = { ...o, a } let spreadNonPrimitive = { ...{}}; >spreadNonPrimitive : Symbol(spreadNonPrimitive, Decl(objectSpread.ts, 119, 3)) +// generic spreads + +function f(t: T, u: U) { +>f : Symbol(f, Decl(objectSpread.ts, 119, 42)) +>T : Symbol(T, Decl(objectSpread.ts, 123, 11)) +>U : Symbol(U, Decl(objectSpread.ts, 123, 13)) +>t : Symbol(t, Decl(objectSpread.ts, 123, 17)) +>T : Symbol(T, Decl(objectSpread.ts, 123, 11)) +>u : Symbol(u, Decl(objectSpread.ts, 123, 22)) +>U : Symbol(U, Decl(objectSpread.ts, 123, 13)) + + return { ...t, ...u, id: 'id' }; +>t : Symbol(t, Decl(objectSpread.ts, 123, 17)) +>u : Symbol(u, Decl(objectSpread.ts, 123, 22)) +>id : Symbol(id, Decl(objectSpread.ts, 124, 24)) +} + +let exclusive: { id: string, a: number, b: string, c: string, d: boolean } = +>exclusive : Symbol(exclusive, Decl(objectSpread.ts, 127, 3)) +>id : Symbol(id, Decl(objectSpread.ts, 127, 16)) +>a : Symbol(a, Decl(objectSpread.ts, 127, 28)) +>b : Symbol(b, Decl(objectSpread.ts, 127, 39)) +>c : Symbol(c, Decl(objectSpread.ts, 127, 50)) +>d : Symbol(d, Decl(objectSpread.ts, 127, 61)) + + f({ a: 1, b: 'yes' }, { c: 'no', d: false }) +>f : Symbol(f, Decl(objectSpread.ts, 119, 42)) +>a : Symbol(a, Decl(objectSpread.ts, 128, 7)) +>b : Symbol(b, Decl(objectSpread.ts, 128, 13)) +>c : Symbol(c, Decl(objectSpread.ts, 128, 27)) +>d : Symbol(d, Decl(objectSpread.ts, 128, 36)) + +let overlap: { id: string, a: number, b: string } = +>overlap : Symbol(overlap, Decl(objectSpread.ts, 129, 3)) +>id : Symbol(id, Decl(objectSpread.ts, 129, 14)) +>a : Symbol(a, Decl(objectSpread.ts, 129, 26)) +>b : Symbol(b, Decl(objectSpread.ts, 129, 37)) + + f({ a: 1 }, { a: 2, b: 'extra' }) +>f : Symbol(f, Decl(objectSpread.ts, 119, 42)) +>a : Symbol(a, Decl(objectSpread.ts, 130, 7)) +>a : Symbol(a, Decl(objectSpread.ts, 130, 17)) +>b : Symbol(b, Decl(objectSpread.ts, 130, 23)) + +let overlapConflict: { id:string, a: string } = +>overlapConflict : Symbol(overlapConflict, Decl(objectSpread.ts, 131, 3)) +>id : Symbol(id, Decl(objectSpread.ts, 131, 22)) +>a : Symbol(a, Decl(objectSpread.ts, 131, 33)) + + f({ a: 1 }, { a: 'mismatch' }) +>f : Symbol(f, Decl(objectSpread.ts, 119, 42)) +>a : Symbol(a, Decl(objectSpread.ts, 132, 7)) +>a : Symbol(a, Decl(objectSpread.ts, 132, 17)) + +let overwriteId: { id: string, a: number, c: number, d: string } = +>overwriteId : Symbol(overwriteId, Decl(objectSpread.ts, 133, 3)) +>id : Symbol(id, Decl(objectSpread.ts, 133, 18)) +>a : Symbol(a, Decl(objectSpread.ts, 133, 30)) +>c : Symbol(c, Decl(objectSpread.ts, 133, 41)) +>d : Symbol(d, Decl(objectSpread.ts, 133, 52)) + + f({ a: 1, id: true }, { c: 1, d: 'no' }) +>f : Symbol(f, Decl(objectSpread.ts, 119, 42)) +>a : Symbol(a, Decl(objectSpread.ts, 134, 7)) +>id : Symbol(id, Decl(objectSpread.ts, 134, 13)) +>c : Symbol(c, Decl(objectSpread.ts, 134, 27)) +>d : Symbol(d, Decl(objectSpread.ts, 134, 33)) + +function genericSpread(t: T, u: U, v: T | U, w: T | { s: string }, obj: { x: number }) { +>genericSpread : Symbol(genericSpread, Decl(objectSpread.ts, 134, 44)) +>T : Symbol(T, Decl(objectSpread.ts, 136, 23)) +>U : Symbol(U, Decl(objectSpread.ts, 136, 25)) +>t : Symbol(t, Decl(objectSpread.ts, 136, 29)) +>T : Symbol(T, Decl(objectSpread.ts, 136, 23)) +>u : Symbol(u, Decl(objectSpread.ts, 136, 34)) +>U : Symbol(U, Decl(objectSpread.ts, 136, 25)) +>v : Symbol(v, Decl(objectSpread.ts, 136, 40)) +>T : Symbol(T, Decl(objectSpread.ts, 136, 23)) +>U : Symbol(U, Decl(objectSpread.ts, 136, 25)) +>w : Symbol(w, Decl(objectSpread.ts, 136, 50)) +>T : Symbol(T, Decl(objectSpread.ts, 136, 23)) +>s : Symbol(s, Decl(objectSpread.ts, 136, 59)) +>obj : Symbol(obj, Decl(objectSpread.ts, 136, 72)) +>x : Symbol(x, Decl(objectSpread.ts, 136, 79)) + + let x01 = { ...t }; +>x01 : Symbol(x01, Decl(objectSpread.ts, 137, 7)) +>t : Symbol(t, Decl(objectSpread.ts, 136, 29)) + + let x02 = { ...t, ...t }; +>x02 : Symbol(x02, Decl(objectSpread.ts, 138, 7)) +>t : Symbol(t, Decl(objectSpread.ts, 136, 29)) +>t : Symbol(t, Decl(objectSpread.ts, 136, 29)) + + let x03 = { ...t, ...u }; +>x03 : Symbol(x03, Decl(objectSpread.ts, 139, 7)) +>t : Symbol(t, Decl(objectSpread.ts, 136, 29)) +>u : Symbol(u, Decl(objectSpread.ts, 136, 34)) + + let x04 = { ...u, ...t }; +>x04 : Symbol(x04, Decl(objectSpread.ts, 140, 7)) +>u : Symbol(u, Decl(objectSpread.ts, 136, 34)) +>t : Symbol(t, Decl(objectSpread.ts, 136, 29)) + + let x05 = { a: 5, b: 'hi', ...t }; +>x05 : Symbol(x05, Decl(objectSpread.ts, 141, 7)) +>a : Symbol(a, Decl(objectSpread.ts, 141, 15)) +>b : Symbol(b, Decl(objectSpread.ts, 141, 21)) +>t : Symbol(t, Decl(objectSpread.ts, 136, 29)) + + let x06 = { ...t, a: 5, b: 'hi' }; +>x06 : Symbol(x06, Decl(objectSpread.ts, 142, 7)) +>t : Symbol(t, Decl(objectSpread.ts, 136, 29)) +>a : Symbol(a, Decl(objectSpread.ts, 142, 21)) +>b : Symbol(b, Decl(objectSpread.ts, 142, 27)) + + let x07 = { a: 5, b: 'hi', ...t, c: true, ...obj }; +>x07 : Symbol(x07, Decl(objectSpread.ts, 143, 7)) +>a : Symbol(a, Decl(objectSpread.ts, 143, 15)) +>b : Symbol(b, Decl(objectSpread.ts, 143, 21)) +>t : Symbol(t, Decl(objectSpread.ts, 136, 29)) +>c : Symbol(c, Decl(objectSpread.ts, 143, 36)) +>obj : Symbol(obj, Decl(objectSpread.ts, 136, 72)) + + let x09 = { a: 5, ...t, b: 'hi', c: true, ...obj }; +>x09 : Symbol(x09, Decl(objectSpread.ts, 144, 7)) +>a : Symbol(a, Decl(objectSpread.ts, 144, 15)) +>t : Symbol(t, Decl(objectSpread.ts, 136, 29)) +>b : Symbol(b, Decl(objectSpread.ts, 144, 27)) +>c : Symbol(c, Decl(objectSpread.ts, 144, 36)) +>obj : Symbol(obj, Decl(objectSpread.ts, 136, 72)) + + let x10 = { a: 5, ...t, b: 'hi', ...u, ...obj }; +>x10 : Symbol(x10, Decl(objectSpread.ts, 145, 7)) +>a : Symbol(a, Decl(objectSpread.ts, 145, 15)) +>t : Symbol(t, Decl(objectSpread.ts, 136, 29)) +>b : Symbol(b, Decl(objectSpread.ts, 145, 27)) +>u : Symbol(u, Decl(objectSpread.ts, 136, 34)) +>obj : Symbol(obj, Decl(objectSpread.ts, 136, 72)) + + let x11 = { ...v }; +>x11 : Symbol(x11, Decl(objectSpread.ts, 146, 7)) +>v : Symbol(v, Decl(objectSpread.ts, 136, 40)) + + let x12 = { ...v, ...obj }; +>x12 : Symbol(x12, Decl(objectSpread.ts, 147, 7)) +>v : Symbol(v, Decl(objectSpread.ts, 136, 40)) +>obj : Symbol(obj, Decl(objectSpread.ts, 136, 72)) + + let x13 = { ...w }; +>x13 : Symbol(x13, Decl(objectSpread.ts, 148, 7)) +>w : Symbol(w, Decl(objectSpread.ts, 136, 50)) + + let x14 = { ...w, ...obj }; +>x14 : Symbol(x14, Decl(objectSpread.ts, 149, 7)) +>w : Symbol(w, Decl(objectSpread.ts, 136, 50)) +>obj : Symbol(obj, Decl(objectSpread.ts, 136, 72)) + + let x15 = { ...t, ...v }; +>x15 : Symbol(x15, Decl(objectSpread.ts, 150, 7)) +>t : Symbol(t, Decl(objectSpread.ts, 136, 29)) +>v : Symbol(v, Decl(objectSpread.ts, 136, 40)) + + let x16 = { ...t, ...w }; +>x16 : Symbol(x16, Decl(objectSpread.ts, 151, 7)) +>t : Symbol(t, Decl(objectSpread.ts, 136, 29)) +>w : Symbol(w, Decl(objectSpread.ts, 136, 50)) + + let x17 = { ...t, ...w, ...obj }; +>x17 : Symbol(x17, Decl(objectSpread.ts, 152, 7)) +>t : Symbol(t, Decl(objectSpread.ts, 136, 29)) +>w : Symbol(w, Decl(objectSpread.ts, 136, 50)) +>obj : Symbol(obj, Decl(objectSpread.ts, 136, 72)) + + let x18 = { ...t, ...v, ...w }; +>x18 : Symbol(x18, Decl(objectSpread.ts, 153, 7)) +>t : Symbol(t, Decl(objectSpread.ts, 136, 29)) +>v : Symbol(v, Decl(objectSpread.ts, 136, 40)) +>w : Symbol(w, Decl(objectSpread.ts, 136, 50)) +} + diff --git a/tests/baselines/reference/objectSpread.types b/tests/baselines/reference/objectSpread.types index fc60b0d88c..0ffd5dd20b 100644 --- a/tests/baselines/reference/objectSpread.types +++ b/tests/baselines/reference/objectSpread.types @@ -578,3 +578,229 @@ let spreadNonPrimitive = { ...{}}; >{} : object >{} : {} +// generic spreads + +function f(t: T, u: U) { +>f : (t: T, u: U) => T & U & { id: string; } +>t : T +>u : U + + return { ...t, ...u, id: 'id' }; +>{ ...t, ...u, id: 'id' } : T & U & { id: string; } +>t : T +>u : U +>id : string +>'id' : "id" +} + +let exclusive: { id: string, a: number, b: string, c: string, d: boolean } = +>exclusive : { id: string; a: number; b: string; c: string; d: boolean; } +>id : string +>a : number +>b : string +>c : string +>d : boolean + + f({ a: 1, b: 'yes' }, { c: 'no', d: false }) +>f({ a: 1, b: 'yes' }, { c: 'no', d: false }) : { a: number; b: string; } & { c: string; d: boolean; } & { id: string; } +>f : (t: T, u: U) => T & U & { id: string; } +>{ a: 1, b: 'yes' } : { a: number; b: string; } +>a : number +>1 : 1 +>b : string +>'yes' : "yes" +>{ c: 'no', d: false } : { c: string; d: false; } +>c : string +>'no' : "no" +>d : false +>false : false + +let overlap: { id: string, a: number, b: string } = +>overlap : { id: string; a: number; b: string; } +>id : string +>a : number +>b : string + + f({ a: 1 }, { a: 2, b: 'extra' }) +>f({ a: 1 }, { a: 2, b: 'extra' }) : { a: number; } & { a: number; b: string; } & { id: string; } +>f : (t: T, u: U) => T & U & { id: string; } +>{ a: 1 } : { a: number; } +>a : number +>1 : 1 +>{ a: 2, b: 'extra' } : { a: number; b: string; } +>a : number +>2 : 2 +>b : string +>'extra' : "extra" + +let overlapConflict: { id:string, a: string } = +>overlapConflict : { id: string; a: string; } +>id : string +>a : string + + f({ a: 1 }, { a: 'mismatch' }) +>f({ a: 1 }, { a: 'mismatch' }) : { a: number; } & { a: string; } & { id: string; } +>f : (t: T, u: U) => T & U & { id: string; } +>{ a: 1 } : { a: number; } +>a : number +>1 : 1 +>{ a: 'mismatch' } : { a: string; } +>a : string +>'mismatch' : "mismatch" + +let overwriteId: { id: string, a: number, c: number, d: string } = +>overwriteId : { id: string; a: number; c: number; d: string; } +>id : string +>a : number +>c : number +>d : string + + f({ a: 1, id: true }, { c: 1, d: 'no' }) +>f({ a: 1, id: true }, { c: 1, d: 'no' }) : { a: number; id: boolean; } & { c: number; d: string; } & { id: string; } +>f : (t: T, u: U) => T & U & { id: string; } +>{ a: 1, id: true } : { a: number; id: true; } +>a : number +>1 : 1 +>id : true +>true : true +>{ c: 1, d: 'no' } : { c: number; d: string; } +>c : number +>1 : 1 +>d : string +>'no' : "no" + +function genericSpread(t: T, u: U, v: T | U, w: T | { s: string }, obj: { x: number }) { +>genericSpread : (t: T, u: U, v: T | U, w: T | { s: string; }, obj: { x: number; }) => void +>t : T +>u : U +>v : T | U +>w : T | { s: string; } +>s : string +>obj : { x: number; } +>x : number + + let x01 = { ...t }; +>x01 : T +>{ ...t } : T +>t : T + + let x02 = { ...t, ...t }; +>x02 : T +>{ ...t, ...t } : T +>t : T +>t : T + + let x03 = { ...t, ...u }; +>x03 : T & U +>{ ...t, ...u } : T & U +>t : T +>u : U + + let x04 = { ...u, ...t }; +>x04 : U & T +>{ ...u, ...t } : U & T +>u : U +>t : T + + let x05 = { a: 5, b: 'hi', ...t }; +>x05 : { a: number; b: string; } & T +>{ a: 5, b: 'hi', ...t } : { a: number; b: string; } & T +>a : number +>5 : 5 +>b : string +>'hi' : "hi" +>t : T + + let x06 = { ...t, a: 5, b: 'hi' }; +>x06 : T & { a: number; b: string; } +>{ ...t, a: 5, b: 'hi' } : T & { a: number; b: string; } +>t : T +>a : number +>5 : 5 +>b : string +>'hi' : "hi" + + let x07 = { a: 5, b: 'hi', ...t, c: true, ...obj }; +>x07 : { a: number; b: string; } & T & { x: number; c: boolean; } +>{ a: 5, b: 'hi', ...t, c: true, ...obj } : { a: number; b: string; } & T & { x: number; c: boolean; } +>a : number +>5 : 5 +>b : string +>'hi' : "hi" +>t : T +>c : boolean +>true : true +>obj : { x: number; } + + let x09 = { a: 5, ...t, b: 'hi', c: true, ...obj }; +>x09 : { a: number; } & T & { x: number; b: string; c: boolean; } +>{ a: 5, ...t, b: 'hi', c: true, ...obj } : { a: number; } & T & { x: number; b: string; c: boolean; } +>a : number +>5 : 5 +>t : T +>b : string +>'hi' : "hi" +>c : boolean +>true : true +>obj : { x: number; } + + let x10 = { a: 5, ...t, b: 'hi', ...u, ...obj }; +>x10 : { a: number; } & T & { b: string; } & U & { x: number; } +>{ a: 5, ...t, b: 'hi', ...u, ...obj } : { a: number; } & T & { b: string; } & U & { x: number; } +>a : number +>5 : 5 +>t : T +>b : string +>'hi' : "hi" +>u : U +>obj : { x: number; } + + let x11 = { ...v }; +>x11 : T | U +>{ ...v } : T | U +>v : T | U + + let x12 = { ...v, ...obj }; +>x12 : (T & { x: number; }) | (U & { x: number; }) +>{ ...v, ...obj } : (T & { x: number; }) | (U & { x: number; }) +>v : T | U +>obj : { x: number; } + + let x13 = { ...w }; +>x13 : T | { s: string; } +>{ ...w } : T | { s: string; } +>w : T | { s: string; } + + let x14 = { ...w, ...obj }; +>x14 : (T & { x: number; }) | { x: number; s: string; } +>{ ...w, ...obj } : (T & { x: number; }) | { x: number; s: string; } +>w : T | { s: string; } +>obj : { x: number; } + + let x15 = { ...t, ...v }; +>x15 : T | (T & U) +>{ ...t, ...v } : T | (T & U) +>t : T +>v : T | U + + let x16 = { ...t, ...w }; +>x16 : T | (T & { s: string; }) +>{ ...t, ...w } : T | (T & { s: string; }) +>t : T +>w : T | { s: string; } + + let x17 = { ...t, ...w, ...obj }; +>x17 : (T & { x: number; }) | (T & { x: number; s: string; }) +>{ ...t, ...w, ...obj } : (T & { x: number; }) | (T & { x: number; s: string; }) +>t : T +>w : T | { s: string; } +>obj : { x: number; } + + let x18 = { ...t, ...v, ...w }; +>x18 : T | (T & U) | (T & { s: string; }) | (T & U & { s: string; }) +>{ ...t, ...v, ...w } : T | (T & U) | (T & { s: string; }) | (T & U & { s: string; }) +>t : T +>v : T | U +>w : T | { s: string; } +} + diff --git a/tests/baselines/reference/objectSpreadNegative.errors.txt b/tests/baselines/reference/objectSpreadNegative.errors.txt index 2f19564087..5c5e94c06f 100644 --- a/tests/baselines/reference/objectSpreadNegative.errors.txt +++ b/tests/baselines/reference/objectSpreadNegative.errors.txt @@ -16,11 +16,9 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(43,1): error TS2349 tests/cases/conformance/types/spread/objectSpreadNegative.ts(47,1): error TS2322: Type '12' is not assignable to type 'undefined'. tests/cases/conformance/types/spread/objectSpreadNegative.ts(53,9): error TS2339: Property 'm' does not exist on type '{ p: number; }'. 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 (17 errors) ==== +==== tests/cases/conformance/types/spread/objectSpreadNegative.ts (15 errors) ==== let o = { a: 1, b: 'no' } /// private propagates @@ -112,24 +110,4 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(65,14): error TS269 spreadObj.a; // error 'a' is not in {} ~ !!! error TS2339: Property 'a' does not exist on type '{}'. - - // generics - function f(t: T, u: U) { - return { ...t, ...u, id: 'id' }; - ~~~~ -!!! error TS2698: Spread types may only be created from object types. - } - function override(initial: U, override: U): U { - return { ...initial, ...override }; - ~~~~~~~~~~ -!!! error TS2698: Spread types may only be created from object types. - } - let exclusive: { id: string, a: number, b: string, c: string, d: boolean } = - f({ a: 1, b: 'yes' }, { c: 'no', d: false }) - let overlap: { id: string, a: number, b: string } = - f({ a: 1 }, { a: 2, b: 'extra' }) - 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' }) \ No newline at end of file diff --git a/tests/baselines/reference/objectSpreadNegative.js b/tests/baselines/reference/objectSpreadNegative.js index 35d8cdf983..23de5699ce 100644 --- a/tests/baselines/reference/objectSpreadNegative.js +++ b/tests/baselines/reference/objectSpreadNegative.js @@ -57,22 +57,6 @@ spreadC.m(); // error 'm' is not in '{ ... c }' let obj: object = { a: 123 }; let spreadObj = { ...obj }; spreadObj.a; // error 'a' is not in {} - -// generics -function f(t: T, u: U) { - return { ...t, ...u, id: 'id' }; -} -function override(initial: U, override: U): U { - return { ...initial, ...override }; -} -let exclusive: { id: string, a: number, b: string, c: string, d: boolean } = - f({ a: 1, b: 'yes' }, { c: 'no', d: false }) -let overlap: { id: string, a: number, b: string } = - f({ a: 1 }, { a: 2, b: 'extra' }) -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' }) //// [objectSpreadNegative.js] @@ -146,14 +130,3 @@ spreadC.m(); // error 'm' is not in '{ ... c }' var obj = { a: 123 }; var spreadObj = __assign({}, obj); spreadObj.a; // error 'a' is not in {} -// generics -function f(t, u) { - return __assign({}, t, u, { id: 'id' }); -} -function override(initial, override) { - return __assign({}, initial, override); -} -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' }); diff --git a/tests/baselines/reference/objectSpreadNegative.symbols b/tests/baselines/reference/objectSpreadNegative.symbols index 110d4557d2..4962630ceb 100644 --- a/tests/baselines/reference/objectSpreadNegative.symbols +++ b/tests/baselines/reference/objectSpreadNegative.symbols @@ -166,82 +166,3 @@ let spreadObj = { ...obj }; spreadObj.a; // error 'a' is not in {} >spreadObj : Symbol(spreadObj, Decl(objectSpreadNegative.ts, 56, 3)) -// generics -function f(t: T, u: U) { ->f : Symbol(f, Decl(objectSpreadNegative.ts, 57, 12)) ->T : Symbol(T, Decl(objectSpreadNegative.ts, 60, 11)) ->U : Symbol(U, Decl(objectSpreadNegative.ts, 60, 13)) ->t : Symbol(t, Decl(objectSpreadNegative.ts, 60, 17)) ->T : Symbol(T, Decl(objectSpreadNegative.ts, 60, 11)) ->u : Symbol(u, Decl(objectSpreadNegative.ts, 60, 22)) ->U : Symbol(U, Decl(objectSpreadNegative.ts, 60, 13)) - - return { ...t, ...u, id: 'id' }; ->t : Symbol(t, Decl(objectSpreadNegative.ts, 60, 17)) ->u : Symbol(u, Decl(objectSpreadNegative.ts, 60, 22)) ->id : Symbol(id, Decl(objectSpreadNegative.ts, 61, 24)) -} -function override(initial: U, override: U): U { ->override : Symbol(override, Decl(objectSpreadNegative.ts, 62, 1)) ->U : Symbol(U, Decl(objectSpreadNegative.ts, 63, 18)) ->initial : Symbol(initial, Decl(objectSpreadNegative.ts, 63, 21)) ->U : Symbol(U, Decl(objectSpreadNegative.ts, 63, 18)) ->override : Symbol(override, Decl(objectSpreadNegative.ts, 63, 32)) ->U : Symbol(U, Decl(objectSpreadNegative.ts, 63, 18)) ->U : Symbol(U, Decl(objectSpreadNegative.ts, 63, 18)) - - return { ...initial, ...override }; ->initial : Symbol(initial, Decl(objectSpreadNegative.ts, 63, 21)) ->override : Symbol(override, Decl(objectSpreadNegative.ts, 63, 32)) -} -let exclusive: { id: string, a: number, b: string, c: string, d: boolean } = ->exclusive : Symbol(exclusive, Decl(objectSpreadNegative.ts, 66, 3)) ->id : Symbol(id, Decl(objectSpreadNegative.ts, 66, 16)) ->a : Symbol(a, Decl(objectSpreadNegative.ts, 66, 28)) ->b : Symbol(b, Decl(objectSpreadNegative.ts, 66, 39)) ->c : Symbol(c, Decl(objectSpreadNegative.ts, 66, 50)) ->d : Symbol(d, Decl(objectSpreadNegative.ts, 66, 61)) - - f({ a: 1, b: 'yes' }, { c: 'no', d: false }) ->f : Symbol(f, Decl(objectSpreadNegative.ts, 57, 12)) ->a : Symbol(a, Decl(objectSpreadNegative.ts, 67, 7)) ->b : Symbol(b, Decl(objectSpreadNegative.ts, 67, 13)) ->c : Symbol(c, Decl(objectSpreadNegative.ts, 67, 27)) ->d : Symbol(d, Decl(objectSpreadNegative.ts, 67, 36)) - -let overlap: { id: string, a: number, b: string } = ->overlap : Symbol(overlap, Decl(objectSpreadNegative.ts, 68, 3)) ->id : Symbol(id, Decl(objectSpreadNegative.ts, 68, 14)) ->a : Symbol(a, Decl(objectSpreadNegative.ts, 68, 26)) ->b : Symbol(b, Decl(objectSpreadNegative.ts, 68, 37)) - - f({ a: 1 }, { a: 2, b: 'extra' }) ->f : Symbol(f, Decl(objectSpreadNegative.ts, 57, 12)) ->a : Symbol(a, Decl(objectSpreadNegative.ts, 69, 7)) ->a : Symbol(a, Decl(objectSpreadNegative.ts, 69, 17)) ->b : Symbol(b, Decl(objectSpreadNegative.ts, 69, 23)) - -let overlapConflict: { id:string, a: string } = ->overlapConflict : Symbol(overlapConflict, Decl(objectSpreadNegative.ts, 70, 3)) ->id : Symbol(id, Decl(objectSpreadNegative.ts, 70, 22)) ->a : Symbol(a, Decl(objectSpreadNegative.ts, 70, 33)) - - f({ a: 1 }, { a: 'mismatch' }) ->f : Symbol(f, Decl(objectSpreadNegative.ts, 57, 12)) ->a : Symbol(a, Decl(objectSpreadNegative.ts, 71, 7)) ->a : Symbol(a, Decl(objectSpreadNegative.ts, 71, 17)) - -let overwriteId: { id: string, a: number, c: number, d: string } = ->overwriteId : Symbol(overwriteId, Decl(objectSpreadNegative.ts, 72, 3)) ->id : Symbol(id, Decl(objectSpreadNegative.ts, 72, 18)) ->a : Symbol(a, Decl(objectSpreadNegative.ts, 72, 30)) ->c : Symbol(c, Decl(objectSpreadNegative.ts, 72, 41)) ->d : Symbol(d, Decl(objectSpreadNegative.ts, 72, 52)) - - f({ a: 1, id: true }, { c: 1, d: 'no' }) ->f : Symbol(f, Decl(objectSpreadNegative.ts, 57, 12)) ->a : Symbol(a, Decl(objectSpreadNegative.ts, 73, 7)) ->id : Symbol(id, Decl(objectSpreadNegative.ts, 73, 13)) ->c : Symbol(c, Decl(objectSpreadNegative.ts, 73, 27)) ->d : Symbol(d, Decl(objectSpreadNegative.ts, 73, 33)) - diff --git a/tests/baselines/reference/objectSpreadNegative.types b/tests/baselines/reference/objectSpreadNegative.types index 837670d58c..351522d896 100644 --- a/tests/baselines/reference/objectSpreadNegative.types +++ b/tests/baselines/reference/objectSpreadNegative.types @@ -226,102 +226,3 @@ spreadObj.a; // error 'a' is not in {} >spreadObj : {} >a : any -// generics -function f(t: T, u: U) { ->f : (t: T, u: U) => any ->t : T ->u : U - - return { ...t, ...u, id: 'id' }; ->{ ...t, ...u, id: 'id' } : any ->t : T ->u : U ->id : string ->'id' : "id" -} -function override(initial: U, override: U): U { ->override : (initial: U, override: U) => U ->initial : U ->override : U - - return { ...initial, ...override }; ->{ ...initial, ...override } : any ->initial : U ->override : U -} -let exclusive: { id: string, a: number, b: string, c: string, d: boolean } = ->exclusive : { id: string; a: number; b: string; c: string; d: boolean; } ->id : string ->a : number ->b : string ->c : string ->d : boolean - - f({ a: 1, b: 'yes' }, { c: 'no', d: false }) ->f({ a: 1, b: 'yes' }, { c: 'no', d: false }) : any ->f : (t: T, u: U) => any ->{ a: 1, b: 'yes' } : { a: number; b: string; } ->a : number ->1 : 1 ->b : string ->'yes' : "yes" ->{ c: 'no', d: false } : { c: string; d: false; } ->c : string ->'no' : "no" ->d : false ->false : false - -let overlap: { id: string, a: number, b: string } = ->overlap : { id: string; a: number; b: string; } ->id : string ->a : number ->b : string - - f({ a: 1 }, { a: 2, b: 'extra' }) ->f({ a: 1 }, { a: 2, b: 'extra' }) : any ->f : (t: T, u: U) => any ->{ a: 1 } : { a: number; } ->a : number ->1 : 1 ->{ a: 2, b: 'extra' } : { a: number; b: string; } ->a : number ->2 : 2 ->b : string ->'extra' : "extra" - -let overlapConflict: { id:string, a: string } = ->overlapConflict : { id: string; a: string; } ->id : string ->a : string - - f({ a: 1 }, { a: 'mismatch' }) ->f({ a: 1 }, { a: 'mismatch' }) : any ->f : (t: T, u: U) => any ->{ a: 1 } : { a: number; } ->a : number ->1 : 1 ->{ a: 'mismatch' } : { a: string; } ->a : string ->'mismatch' : "mismatch" - -let overwriteId: { id: string, a: number, c: number, d: string } = ->overwriteId : { id: string; a: number; c: number; d: string; } ->id : string ->a : number ->c : number ->d : string - - f({ a: 1, id: true }, { c: 1, d: 'no' }) ->f({ a: 1, id: true }, { c: 1, d: 'no' }) : any ->f : (t: T, u: U) => any ->{ a: 1, id: true } : { a: number; id: true; } ->a : number ->1 : 1 ->id : true ->true : true ->{ c: 1, d: 'no' } : { c: number; d: string; } ->c : number ->1 : 1 ->d : string ->'no' : "no" - diff --git a/tests/baselines/reference/spreadInvalidArgumentType.errors.txt b/tests/baselines/reference/spreadInvalidArgumentType.errors.txt index 4c1aa286aa..cb2b74b7b1 100644 --- a/tests/baselines/reference/spreadInvalidArgumentType.errors.txt +++ b/tests/baselines/reference/spreadInvalidArgumentType.errors.txt @@ -1,11 +1,5 @@ -tests/cases/compiler/spreadInvalidArgumentType.ts(30,16): error TS2698: Spread types may only be created from object types. -tests/cases/compiler/spreadInvalidArgumentType.ts(32,16): error TS2698: Spread types may only be created from object types. -tests/cases/compiler/spreadInvalidArgumentType.ts(33,16): error TS2698: Spread types may only be created from object types. tests/cases/compiler/spreadInvalidArgumentType.ts(34,16): error TS2698: Spread types may only be created from object types. -tests/cases/compiler/spreadInvalidArgumentType.ts(35,16): error TS2698: Spread types may only be created from object types. -tests/cases/compiler/spreadInvalidArgumentType.ts(38,16): error TS2698: Spread types may only be created from object types. tests/cases/compiler/spreadInvalidArgumentType.ts(39,16): error TS2698: Spread types may only be created from object types. -tests/cases/compiler/spreadInvalidArgumentType.ts(41,17): error TS2698: Spread types may only be created from object types. tests/cases/compiler/spreadInvalidArgumentType.ts(42,17): error TS2698: Spread types may only be created from object types. tests/cases/compiler/spreadInvalidArgumentType.ts(44,17): error TS2698: Spread types may only be created from object types. tests/cases/compiler/spreadInvalidArgumentType.ts(45,17): error TS2698: Spread types may only be created from object types. @@ -16,7 +10,7 @@ tests/cases/compiler/spreadInvalidArgumentType.ts(53,17): error TS2698: Spread t tests/cases/compiler/spreadInvalidArgumentType.ts(55,17): error TS2698: Spread types may only be created from object types. -==== tests/cases/compiler/spreadInvalidArgumentType.ts (16 errors) ==== +==== tests/cases/compiler/spreadInvalidArgumentType.ts (10 errors) ==== enum E { v1, v2 }; function f(p1: T, p2: T[]) { @@ -46,34 +40,22 @@ tests/cases/compiler/spreadInvalidArgumentType.ts(55,17): error TS2698: Spread t var e: E; - var o1 = { ...p1 }; // Error, generic type paramterre - ~~~~~ -!!! error TS2698: Spread types may only be created from object types. - var o2 = { ...p2 }; // OK - var o3 = { ...t }; // Error, generic type paramter - ~~~~ -!!! error TS2698: Spread types may only be created from object types. - var o4 = { ...i }; // Error, index access - ~~~~ -!!! error TS2698: Spread types may only be created from object types. + var o1 = { ...p1 }; // OK, generic type paramterre + var o2 = { ...p2 }; // OK + var o3 = { ...t }; // OK, generic type paramter + var o4 = { ...i }; // OK, index access var o5 = { ...k }; // Error, index ~~~~ !!! error TS2698: Spread types may only be created from object types. - var o6 = { ...mapped_generic }; // Error, generic mapped object type - ~~~~~~~~~~~~~~~~~ -!!! error TS2698: Spread types may only be created from object types. + var o6 = { ...mapped_generic }; // OK, generic mapped object type var o7 = { ...mapped }; // OK, non-generic mapped type - var o8 = { ...union_generic }; // Error, union with generic type parameter - ~~~~~~~~~~~~~~~~ -!!! error TS2698: Spread types may only be created from object types. + var o8 = { ...union_generic }; // OK, union with generic type parameter var o9 = { ...union_primitive }; // Error, union with generic type parameter ~~~~~~~~~~~~~~~~~~ !!! error TS2698: Spread types may only be created from object types. - var o10 = { ...intersection_generic }; // Error, intersection with generic type parameter - ~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2698: Spread types may only be created from object types. + var o10 = { ...intersection_generic }; // OK, intersection with generic type parameter var o11 = { ...intersection_primitive }; // Error, intersection with generic type parameter ~~~~~~~~~~~~~~~~~~~~~~~~~ !!! error TS2698: Spread types may only be created from object types. diff --git a/tests/baselines/reference/spreadInvalidArgumentType.js b/tests/baselines/reference/spreadInvalidArgumentType.js index 9a08fe4c36..b1cb2561ec 100644 --- a/tests/baselines/reference/spreadInvalidArgumentType.js +++ b/tests/baselines/reference/spreadInvalidArgumentType.js @@ -28,18 +28,18 @@ function f(p1: T, p2: T[]) { var e: E; - var o1 = { ...p1 }; // Error, generic type paramterre - var o2 = { ...p2 }; // OK - var o3 = { ...t }; // Error, generic type paramter - var o4 = { ...i }; // Error, index access + var o1 = { ...p1 }; // OK, generic type paramterre + var o2 = { ...p2 }; // OK + var o3 = { ...t }; // OK, generic type paramter + var o4 = { ...i }; // OK, index access var o5 = { ...k }; // Error, index - var o6 = { ...mapped_generic }; // Error, generic mapped object type + var o6 = { ...mapped_generic }; // OK, generic mapped object type var o7 = { ...mapped }; // OK, non-generic mapped type - var o8 = { ...union_generic }; // Error, union with generic type parameter + var o8 = { ...union_generic }; // OK, union with generic type parameter var o9 = { ...union_primitive }; // Error, union with generic type parameter - var o10 = { ...intersection_generic }; // Error, intersection with generic type parameter + var o10 = { ...intersection_generic }; // OK, intersection with generic type parameter var o11 = { ...intersection_primitive }; // Error, intersection with generic type parameter var o12 = { ...num }; // Error @@ -93,16 +93,16 @@ function f(p1, p2) { var n; var a; var e; - var o1 = __assign({}, p1); // Error, generic type paramterre + var o1 = __assign({}, p1); // OK, generic type paramterre var o2 = __assign({}, p2); // OK - var o3 = __assign({}, t); // Error, generic type paramter - var o4 = __assign({}, i); // Error, index access + var o3 = __assign({}, t); // OK, generic type paramter + var o4 = __assign({}, i); // OK, index access var o5 = __assign({}, k); // Error, index - var o6 = __assign({}, mapped_generic); // Error, generic mapped object type + var o6 = __assign({}, mapped_generic); // OK, generic mapped object type var o7 = __assign({}, mapped); // OK, non-generic mapped type - var o8 = __assign({}, union_generic); // Error, union with generic type parameter + var o8 = __assign({}, union_generic); // OK, union with generic type parameter var o9 = __assign({}, union_primitive); // Error, union with generic type parameter - var o10 = __assign({}, intersection_generic); // Error, intersection with generic type parameter + var o10 = __assign({}, intersection_generic); // OK, intersection with generic type parameter var o11 = __assign({}, intersection_primitive); // Error, intersection with generic type parameter var o12 = __assign({}, num); // Error var o13 = __assign({}, str); // Error diff --git a/tests/baselines/reference/spreadInvalidArgumentType.symbols b/tests/baselines/reference/spreadInvalidArgumentType.symbols index 3701440ffe..8c29a923d3 100644 --- a/tests/baselines/reference/spreadInvalidArgumentType.symbols +++ b/tests/baselines/reference/spreadInvalidArgumentType.symbols @@ -82,19 +82,19 @@ function f(p1: T, p2: T[]) { >e : Symbol(e, Decl(spreadInvalidArgumentType.ts, 27, 7)) >E : Symbol(E, Decl(spreadInvalidArgumentType.ts, 0, 0)) - var o1 = { ...p1 }; // Error, generic type paramterre + var o1 = { ...p1 }; // OK, generic type paramterre >o1 : Symbol(o1, Decl(spreadInvalidArgumentType.ts, 29, 7)) >p1 : Symbol(p1, Decl(spreadInvalidArgumentType.ts, 2, 36)) - var o2 = { ...p2 }; // OK + var o2 = { ...p2 }; // OK >o2 : Symbol(o2, Decl(spreadInvalidArgumentType.ts, 30, 7)) >p2 : Symbol(p2, Decl(spreadInvalidArgumentType.ts, 2, 42)) - var o3 = { ...t }; // Error, generic type paramter + var o3 = { ...t }; // OK, generic type paramter >o3 : Symbol(o3, Decl(spreadInvalidArgumentType.ts, 31, 7)) >t : Symbol(t, Decl(spreadInvalidArgumentType.ts, 3, 7)) - var o4 = { ...i }; // Error, index access + var o4 = { ...i }; // OK, index access >o4 : Symbol(o4, Decl(spreadInvalidArgumentType.ts, 32, 7)) >i : Symbol(i, Decl(spreadInvalidArgumentType.ts, 5, 7)) @@ -102,7 +102,7 @@ function f(p1: T, p2: T[]) { >o5 : Symbol(o5, Decl(spreadInvalidArgumentType.ts, 33, 7)) >k : Symbol(k, Decl(spreadInvalidArgumentType.ts, 6, 7)) - var o6 = { ...mapped_generic }; // Error, generic mapped object type + var o6 = { ...mapped_generic }; // OK, generic mapped object type >o6 : Symbol(o6, Decl(spreadInvalidArgumentType.ts, 34, 7)) >mapped_generic : Symbol(mapped_generic, Decl(spreadInvalidArgumentType.ts, 8, 7)) @@ -110,7 +110,7 @@ function f(p1: T, p2: T[]) { >o7 : Symbol(o7, Decl(spreadInvalidArgumentType.ts, 35, 7)) >mapped : Symbol(mapped, Decl(spreadInvalidArgumentType.ts, 9, 7)) - var o8 = { ...union_generic }; // Error, union with generic type parameter + var o8 = { ...union_generic }; // OK, union with generic type parameter >o8 : Symbol(o8, Decl(spreadInvalidArgumentType.ts, 37, 7)) >union_generic : Symbol(union_generic, Decl(spreadInvalidArgumentType.ts, 11, 7)) @@ -118,7 +118,7 @@ function f(p1: T, p2: T[]) { >o9 : Symbol(o9, Decl(spreadInvalidArgumentType.ts, 38, 7)) >union_primitive : Symbol(union_primitive, Decl(spreadInvalidArgumentType.ts, 12, 7)) - var o10 = { ...intersection_generic }; // Error, intersection with generic type parameter + var o10 = { ...intersection_generic }; // OK, intersection with generic type parameter >o10 : Symbol(o10, Decl(spreadInvalidArgumentType.ts, 40, 7)) >intersection_generic : Symbol(intersection_generic, Decl(spreadInvalidArgumentType.ts, 14, 7)) diff --git a/tests/baselines/reference/spreadInvalidArgumentType.types b/tests/baselines/reference/spreadInvalidArgumentType.types index 1acb22419a..6828d557d0 100644 --- a/tests/baselines/reference/spreadInvalidArgumentType.types +++ b/tests/baselines/reference/spreadInvalidArgumentType.types @@ -67,24 +67,24 @@ function f(p1: T, p2: T[]) { var e: E; >e : E - var o1 = { ...p1 }; // Error, generic type paramterre ->o1 : any ->{ ...p1 } : any + var o1 = { ...p1 }; // OK, generic type paramterre +>o1 : T +>{ ...p1 } : T >p1 : T - var o2 = { ...p2 }; // OK + var o2 = { ...p2 }; // OK >o2 : { [x: number]: T; length: number; toString(): string; toLocaleString(): string; pop(): T; push(...items: T[]): number; concat(...items: ConcatArray[]): T[]; concat(...items: (T | ConcatArray)[]): T[]; join(separator?: string): string; reverse(): T[]; shift(): T; slice(start?: number, end?: number): T[]; sort(compareFn?: (a: T, b: T) => number): T[]; splice(start: number, deleteCount?: number): T[]; splice(start: number, deleteCount: number, ...items: T[]): T[]; unshift(...items: T[]): number; indexOf(searchElement: T, fromIndex?: number): number; lastIndexOf(searchElement: T, fromIndex?: number): number; every(callbackfn: (value: T, index: number, array: T[]) => boolean, thisArg?: any): boolean; some(callbackfn: (value: T, index: number, array: T[]) => boolean, thisArg?: any): boolean; forEach(callbackfn: (value: T, index: number, array: T[]) => void, thisArg?: any): void; map(callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any): U[]; filter(callbackfn: (value: T, index: number, array: T[]) => value is S, thisArg?: any): S[]; filter(callbackfn: (value: T, index: number, array: T[]) => any, thisArg?: any): T[]; reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T): T; reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T, initialValue: T): T; reduce(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, initialValue: U): U; reduceRight(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T): T; reduceRight(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T, initialValue: T): T; reduceRight(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, initialValue: U): U; } >{ ...p2 } : { [n: number]: T; length: number; toString(): string; toLocaleString(): string; pop(): T; push(...items: T[]): number; concat(...items: ConcatArray[]): T[]; concat(...items: (T | ConcatArray)[]): T[]; join(separator?: string): string; reverse(): T[]; shift(): T; slice(start?: number, end?: number): T[]; sort(compareFn?: (a: T, b: T) => number): T[]; splice(start: number, deleteCount?: number): T[]; splice(start: number, deleteCount: number, ...items: T[]): T[]; unshift(...items: T[]): number; indexOf(searchElement: T, fromIndex?: number): number; lastIndexOf(searchElement: T, fromIndex?: number): number; every(callbackfn: (value: T, index: number, array: T[]) => boolean, thisArg?: any): boolean; some(callbackfn: (value: T, index: number, array: T[]) => boolean, thisArg?: any): boolean; forEach(callbackfn: (value: T, index: number, array: T[]) => void, thisArg?: any): void; map(callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any): U[]; filter(callbackfn: (value: T, index: number, array: T[]) => value is S, thisArg?: any): S[]; filter(callbackfn: (value: T, index: number, array: T[]) => any, thisArg?: any): T[]; reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T): T; reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T, initialValue: T): T; reduce(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, initialValue: U): U; reduceRight(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T): T; reduceRight(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T, initialValue: T): T; reduceRight(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, initialValue: U): U; } >p2 : T[] - var o3 = { ...t }; // Error, generic type paramter ->o3 : any ->{ ...t } : any + var o3 = { ...t }; // OK, generic type paramter +>o3 : T +>{ ...t } : T >t : T - var o4 = { ...i }; // Error, index access ->o4 : any ->{ ...i } : any + var o4 = { ...i }; // OK, index access +>o4 : T["b"] +>{ ...i } : T["b"] >i : T["b"] var o5 = { ...k }; // Error, index @@ -92,9 +92,9 @@ function f(p1: T, p2: T[]) { >{ ...k } : any >k : keyof T - var o6 = { ...mapped_generic }; // Error, generic mapped object type ->o6 : any ->{ ...mapped_generic } : any + var o6 = { ...mapped_generic }; // OK, generic mapped object type +>o6 : { [P in keyof T]: T[P]; } +>{ ...mapped_generic } : { [P in keyof T]: T[P]; } >mapped_generic : { [P in keyof T]: T[P]; } var o7 = { ...mapped }; // OK, non-generic mapped type @@ -102,9 +102,9 @@ function f(p1: T, p2: T[]) { >{ ...mapped } : { b: T["b"]; } >mapped : { b: T["b"]; } - var o8 = { ...union_generic }; // Error, union with generic type parameter ->o8 : any ->{ ...union_generic } : any + var o8 = { ...union_generic }; // OK, union with generic type parameter +>o8 : T | { a: number; } +>{ ...union_generic } : T | { a: number; } >union_generic : T | { a: number; } var o9 = { ...union_primitive }; // Error, union with generic type parameter @@ -112,9 +112,9 @@ function f(p1: T, p2: T[]) { >{ ...union_primitive } : any >union_primitive : number | { a: number; } - var o10 = { ...intersection_generic }; // Error, intersection with generic type parameter ->o10 : any ->{ ...intersection_generic } : any + var o10 = { ...intersection_generic }; // OK, intersection with generic type parameter +>o10 : T & { a: number; } +>{ ...intersection_generic } : T & { a: number; } >intersection_generic : T & { a: number; } var o11 = { ...intersection_primitive }; // Error, intersection with generic type parameter diff --git a/tests/cases/compiler/spreadInvalidArgumentType.ts b/tests/cases/compiler/spreadInvalidArgumentType.ts index f18e73b31e..d75d606cc7 100644 --- a/tests/cases/compiler/spreadInvalidArgumentType.ts +++ b/tests/cases/compiler/spreadInvalidArgumentType.ts @@ -27,18 +27,18 @@ function f(p1: T, p2: T[]) { var e: E; - var o1 = { ...p1 }; // Error, generic type paramterre - var o2 = { ...p2 }; // OK - var o3 = { ...t }; // Error, generic type paramter - var o4 = { ...i }; // Error, index access + var o1 = { ...p1 }; // OK, generic type paramterre + var o2 = { ...p2 }; // OK + var o3 = { ...t }; // OK, generic type paramter + var o4 = { ...i }; // OK, index access var o5 = { ...k }; // Error, index - var o6 = { ...mapped_generic }; // Error, generic mapped object type + var o6 = { ...mapped_generic }; // OK, generic mapped object type var o7 = { ...mapped }; // OK, non-generic mapped type - var o8 = { ...union_generic }; // Error, union with generic type parameter + var o8 = { ...union_generic }; // OK, union with generic type parameter var o9 = { ...union_primitive }; // Error, union with generic type parameter - var o10 = { ...intersection_generic }; // Error, intersection with generic type parameter + var o10 = { ...intersection_generic }; // OK, intersection with generic type parameter var o11 = { ...intersection_primitive }; // Error, intersection with generic type parameter var o12 = { ...num }; // Error diff --git a/tests/cases/conformance/types/spread/objectSpread.ts b/tests/cases/conformance/types/spread/objectSpread.ts index c7cf5e49ee..5917bdf6dc 100644 --- a/tests/cases/conformance/types/spread/objectSpread.ts +++ b/tests/cases/conformance/types/spread/objectSpread.ts @@ -120,3 +120,38 @@ let a = 12; let shortCutted: { a: number, b: string } = { ...o, a } // non primitive let spreadNonPrimitive = { ...{}}; + +// generic spreads + +function f(t: T, u: U) { + return { ...t, ...u, id: 'id' }; +} + +let exclusive: { id: string, a: number, b: string, c: string, d: boolean } = + f({ a: 1, b: 'yes' }, { c: 'no', d: false }) +let overlap: { id: string, a: number, b: string } = + f({ a: 1 }, { a: 2, b: 'extra' }) +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' }) + +function genericSpread(t: T, u: U, v: T | U, w: T | { s: string }, obj: { x: number }) { + let x01 = { ...t }; + let x02 = { ...t, ...t }; + let x03 = { ...t, ...u }; + let x04 = { ...u, ...t }; + let x05 = { a: 5, b: 'hi', ...t }; + let x06 = { ...t, a: 5, b: 'hi' }; + let x07 = { a: 5, b: 'hi', ...t, c: true, ...obj }; + let x09 = { a: 5, ...t, b: 'hi', c: true, ...obj }; + let x10 = { a: 5, ...t, b: 'hi', ...u, ...obj }; + let x11 = { ...v }; + let x12 = { ...v, ...obj }; + let x13 = { ...w }; + let x14 = { ...w, ...obj }; + let x15 = { ...t, ...v }; + let x16 = { ...t, ...w }; + let x17 = { ...t, ...w, ...obj }; + let x18 = { ...t, ...v, ...w }; +} diff --git a/tests/cases/conformance/types/spread/objectSpreadNegative.ts b/tests/cases/conformance/types/spread/objectSpreadNegative.ts index 789016762d..f31d62e2fa 100644 --- a/tests/cases/conformance/types/spread/objectSpreadNegative.ts +++ b/tests/cases/conformance/types/spread/objectSpreadNegative.ts @@ -57,19 +57,3 @@ spreadC.m(); // error 'm' is not in '{ ... c }' let obj: object = { a: 123 }; let spreadObj = { ...obj }; spreadObj.a; // error 'a' is not in {} - -// generics -function f(t: T, u: U) { - return { ...t, ...u, id: 'id' }; -} -function override(initial: U, override: U): U { - return { ...initial, ...override }; -} -let exclusive: { id: string, a: number, b: string, c: string, d: boolean } = - f({ a: 1, b: 'yes' }, { c: 'no', d: false }) -let overlap: { id: string, a: number, b: string } = - f({ a: 1 }, { a: 2, b: 'extra' }) -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' })