From 60f1d4573d8166fc369887ca4b96bf04d2d5b782 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Wed, 13 Sep 2017 14:04:14 -0700 Subject: [PATCH 01/10] Allow booleans in spread types Special-case types produced by `bool && expr` with the type `false | T`. This spreads `Partial` instead of `false | T`. --- src/compiler/checker.ts | 44 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 5c6a8b59119..287311e6433 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7832,12 +7832,25 @@ namespace ts { return left; } if (left.flags & TypeFlags.Union) { - return mapType(left, t => getSpreadType(t, right)); + // if the union is `false | T` make all the properties of T optional + const wl = getPartialTypeFromFalseUnion(left as UnionType); + if (wl) { + left = wl; + } + else { + return mapType(left, t => getSpreadType(t, right)); + } } if (right.flags & TypeFlags.Union) { - return mapType(right, t => getSpreadType(left, t)); + const wr = getPartialTypeFromFalseUnion(right as UnionType); + if (wr) { + right = wr; + } + else { + return mapType(right, t => getSpreadType(left, t)); + } } - if (right.flags & TypeFlags.NonPrimitive) { + if (right.flags & (TypeFlags.NonPrimitive | TypeFlags.BooleanLike)) { return emptyObjectType; } @@ -7908,6 +7921,29 @@ namespace ts { return prop.flags & SymbolFlags.Method && find(prop.declarations, decl => isClassLike(decl.parent)); } + function getPartialTypeFromFalseUnion(type: UnionType): Type | undefined { + if (type.types.length === 2) { + const i = type.types.indexOf(falseType); + if (i > -1) { + const members = createSymbolTable(); + const other = type.types[i === 0 ? 1 : 0]; + for (const prop of getPropertiesOfType(other)) { + if (prop.flags & SymbolFlags.Optional) { + members.set(prop.escapedName, prop); + } + else { + const result = createSymbol(prop.flags | SymbolFlags.Optional, prop.escapedName); + result.type = getUnionType([getTypeOfSymbol(prop), undefinedType]); + result.declarations = prop.declarations; + result.syntheticOrigin = prop; + members.set(prop.escapedName, result); + } + } + return createAnonymousType(undefined, members, emptyArray, emptyArray, getIndexInfoOfType(other, IndexKind.String), getIndexInfoOfType(other, IndexKind.Number)); + } + } + } + function createLiteralType(flags: TypeFlags, value: string | number, symbol: Symbol) { const type = createType(flags); type.symbol = symbol; @@ -13749,7 +13785,7 @@ namespace ts { } function isValidSpreadType(type: Type): boolean { - return !!(type.flags & (TypeFlags.Any | TypeFlags.Null | TypeFlags.Undefined | TypeFlags.NonPrimitive) || + return !!(type.flags & (TypeFlags.Any | TypeFlags.Nullable | TypeFlags.NonPrimitive | TypeFlags.BooleanLike) || type.flags & TypeFlags.Object && !isGenericMappedType(type) || type.flags & TypeFlags.UnionOrIntersection && !forEach((type).types, t => !isValidSpreadType(t))); } From 9cddd1aca2de5eec903b2cbdb5d812ab68e2ef94 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Wed, 13 Sep 2017 14:06:15 -0700 Subject: [PATCH 02/10] Update spread tests for booleans in spread types --- tests/baselines/reference/objectSpread.js | 65 +++--- .../baselines/reference/objectSpread.symbols | 201 ++++++++++-------- tests/baselines/reference/objectSpread.types | 80 ++++--- .../reference/objectSpreadNegative.errors.txt | 26 +-- .../reference/objectSpreadNegative.js | 6 - .../conformance/types/spread/objectSpread.ts | 38 ++-- .../types/spread/objectSpreadNegative.ts | 3 - 7 files changed, 236 insertions(+), 183 deletions(-) diff --git a/tests/baselines/reference/objectSpread.js b/tests/baselines/reference/objectSpread.js index e05837c32d5..11b904a4806 100644 --- a/tests/baselines/reference/objectSpread.js +++ b/tests/baselines/reference/objectSpread.js @@ -38,6 +38,13 @@ getter.a = 12; // functions result in { } let spreadFunc = { ...(function () { }) }; +// boolean && T results in Partial +function conditionalSpread(b: boolean) : { x?: number | undefined, y?: number | undefined } { + return { ...b && { x: 1, y: 2 } }; +} +// other booleans result in { } +let spreadBool = { ... true } + // any results in any let anything: any; let spreadAny = { ...anything }; @@ -60,21 +67,23 @@ let changeTypeBoth: { a: string, b: number } = { ...o, ...swap }; // optional -let definiteBoolean: { sn: boolean }; -let definiteString: { sn: string }; -let optionalString: { sn?: string }; -let optionalNumber: { sn?: number }; -let optionalUnionStops: { sn: string | number | boolean } = { ...definiteBoolean, ...definiteString, ...optionalNumber }; -let optionalUnionDuplicates: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...optionalString, ...optionalNumber }; -let allOptional: { sn?: string | number } = { ...optionalString, ...optionalNumber }; +function container( + definiteBoolean: { sn: boolean }, + definiteString: { sn: string }, + optionalString: { sn?: string }, + optionalNumber: { sn?: number }) { + let optionalUnionStops: { sn: string | number | boolean } = { ...definiteBoolean, ...definiteString, ...optionalNumber }; + let optionalUnionDuplicates: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...optionalString, ...optionalNumber }; + let allOptional: { sn?: string | number } = { ...optionalString, ...optionalNumber }; -// computed property -let computedFirst: { a: number, b: string, "before everything": number } = - { ['before everything']: 12, ...o, b: 'yes' } -let computedMiddle: { a: number, b: string, c: boolean, "in the middle": number } = - { ...o, ['in the middle']: 13, b: 'maybe?', ...o2 } -let computedAfter: { a: number, b: string, "at the end": number } = - { ...o, b: 'yeah', ['at the end']: 14 } + // computed property + let computedFirst: { a: number, b: string, "before everything": number } = + { ['before everything']: 12, ...o, b: 'yes' } + let computedMiddle: { a: number, b: string, c: boolean, "in the middle": number } = + { ...o, ['in the middle']: 13, b: 'maybe?', ...o2 } + let computedAfter: { a: number, b: string, "at the end": number } = + { ...o, b: 'yeah', ['at the end']: 14 } +} // shortcut syntax let a = 12; let shortCutted: { a: number, b: string } = { ...o, a } @@ -114,6 +123,12 @@ var getter = __assign({}, op, { c: 7 }); getter.a = 12; // functions result in { } var spreadFunc = __assign({}, (function () { })); +// boolean && T results in Partial +function conditionalSpread(b) { + return __assign({}, b && { x: 1, y: 2 }); +} +// other booleans result in { } +var spreadBool = __assign({}, true); // any results in any var anything; var spreadAny = __assign({}, anything); @@ -135,20 +150,18 @@ var changeTypeAfter = __assign({}, o, { a: 'wrong type?' }); var changeTypeBefore = __assign({ a: 'wrong type?' }, o); var changeTypeBoth = __assign({}, o, swap); // optional -var definiteBoolean; -var definiteString; -var optionalString; -var optionalNumber; -var optionalUnionStops = __assign({}, definiteBoolean, definiteString, optionalNumber); -var optionalUnionDuplicates = __assign({}, definiteBoolean, definiteString, optionalString, optionalNumber); -var allOptional = __assign({}, optionalString, optionalNumber); -// computed property -var computedFirst = __assign((_a = {}, _a['before everything'] = 12, _a), o, { b: 'yes' }); -var computedMiddle = __assign({}, o, (_b = {}, _b['in the middle'] = 13, _b.b = 'maybe?', _b), o2); -var computedAfter = __assign({}, o, (_c = { b: 'yeah' }, _c['at the end'] = 14, _c)); +function container(definiteBoolean, definiteString, optionalString, optionalNumber) { + var optionalUnionStops = __assign({}, definiteBoolean, definiteString, optionalNumber); + var optionalUnionDuplicates = __assign({}, definiteBoolean, definiteString, optionalString, optionalNumber); + var allOptional = __assign({}, optionalString, optionalNumber); + // computed property + var computedFirst = __assign((_a = {}, _a['before everything'] = 12, _a), o, { b: 'yes' }); + var computedMiddle = __assign({}, o, (_b = {}, _b['in the middle'] = 13, _b.b = 'maybe?', _b), o2); + var computedAfter = __assign({}, o, (_c = { b: 'yeah' }, _c['at the end'] = 14, _c)); + var _a, _b, _c; +} // shortcut syntax var a = 12; var shortCutted = __assign({}, o, { a: a }); // non primitive var spreadNonPrimitive = __assign({}, {}); -var _a, _b, _c; diff --git a/tests/baselines/reference/objectSpread.symbols b/tests/baselines/reference/objectSpread.symbols index 1ec2520e166..0c5e8a4c5a8 100644 --- a/tests/baselines/reference/objectSpread.symbols +++ b/tests/baselines/reference/objectSpread.symbols @@ -169,154 +169,173 @@ getter.a = 12; let spreadFunc = { ...(function () { }) }; >spreadFunc : Symbol(spreadFunc, Decl(objectSpread.ts, 37, 3)) +// boolean && T results in Partial +function conditionalSpread(b: boolean) : { x?: number | undefined, y?: number | undefined } { +>conditionalSpread : Symbol(conditionalSpread, Decl(objectSpread.ts, 37, 42)) +>b : Symbol(b, Decl(objectSpread.ts, 40, 27)) +>x : Symbol(x, Decl(objectSpread.ts, 40, 42)) +>y : Symbol(y, Decl(objectSpread.ts, 40, 66)) + + return { ...b && { x: 1, y: 2 } }; +>b : Symbol(b, Decl(objectSpread.ts, 40, 27)) +>x : Symbol(x, Decl(objectSpread.ts, 41, 22)) +>y : Symbol(y, Decl(objectSpread.ts, 41, 28)) +} +// other booleans result in { } +let spreadBool = { ... true } +>spreadBool : Symbol(spreadBool, Decl(objectSpread.ts, 44, 3)) + // any results in any let anything: any; ->anything : Symbol(anything, Decl(objectSpread.ts, 40, 3)) +>anything : Symbol(anything, Decl(objectSpread.ts, 47, 3)) let spreadAny = { ...anything }; ->spreadAny : Symbol(spreadAny, Decl(objectSpread.ts, 41, 3)) ->anything : Symbol(anything, Decl(objectSpread.ts, 40, 3)) +>spreadAny : Symbol(spreadAny, Decl(objectSpread.ts, 48, 3)) +>anything : Symbol(anything, Decl(objectSpread.ts, 47, 3)) // methods are not enumerable class C { p = 1; m() { } } ->C : Symbol(C, Decl(objectSpread.ts, 41, 32)) ->p : Symbol(C.p, Decl(objectSpread.ts, 44, 9)) ->m : Symbol(C.m, Decl(objectSpread.ts, 44, 16)) +>C : Symbol(C, Decl(objectSpread.ts, 48, 32)) +>p : Symbol(C.p, Decl(objectSpread.ts, 51, 9)) +>m : Symbol(C.m, Decl(objectSpread.ts, 51, 16)) let c: C = new C() ->c : Symbol(c, Decl(objectSpread.ts, 45, 3)) ->C : Symbol(C, Decl(objectSpread.ts, 41, 32)) ->C : Symbol(C, Decl(objectSpread.ts, 41, 32)) +>c : Symbol(c, Decl(objectSpread.ts, 52, 3)) +>C : Symbol(C, Decl(objectSpread.ts, 48, 32)) +>C : Symbol(C, Decl(objectSpread.ts, 48, 32)) let spreadC: { p: number } = { ...c } ->spreadC : Symbol(spreadC, Decl(objectSpread.ts, 46, 3)) ->p : Symbol(p, Decl(objectSpread.ts, 46, 14)) ->c : Symbol(c, Decl(objectSpread.ts, 45, 3)) +>spreadC : Symbol(spreadC, Decl(objectSpread.ts, 53, 3)) +>p : Symbol(p, Decl(objectSpread.ts, 53, 14)) +>c : Symbol(c, Decl(objectSpread.ts, 52, 3)) // own methods are enumerable let cplus: { p: number, plus(): void } = { ...c, plus() { return this.p + 1; } }; ->cplus : Symbol(cplus, Decl(objectSpread.ts, 49, 3)) ->p : Symbol(p, Decl(objectSpread.ts, 49, 12)) ->plus : Symbol(plus, Decl(objectSpread.ts, 49, 23)) ->c : Symbol(c, Decl(objectSpread.ts, 45, 3)) ->plus : Symbol(plus, Decl(objectSpread.ts, 49, 48)) +>cplus : Symbol(cplus, Decl(objectSpread.ts, 56, 3)) +>p : Symbol(p, Decl(objectSpread.ts, 56, 12)) +>plus : Symbol(plus, Decl(objectSpread.ts, 56, 23)) +>c : Symbol(c, Decl(objectSpread.ts, 52, 3)) +>plus : Symbol(plus, Decl(objectSpread.ts, 56, 48)) cplus.plus(); ->cplus.plus : Symbol(plus, Decl(objectSpread.ts, 49, 23)) ->cplus : Symbol(cplus, Decl(objectSpread.ts, 49, 3)) ->plus : Symbol(plus, Decl(objectSpread.ts, 49, 23)) +>cplus.plus : Symbol(plus, Decl(objectSpread.ts, 56, 23)) +>cplus : Symbol(cplus, Decl(objectSpread.ts, 56, 3)) +>plus : Symbol(plus, Decl(objectSpread.ts, 56, 23)) // new field's type conflicting with existing field is OK let changeTypeAfter: { a: string, b: string } = ->changeTypeAfter : Symbol(changeTypeAfter, Decl(objectSpread.ts, 53, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 53, 22)) ->b : Symbol(b, Decl(objectSpread.ts, 53, 33)) +>changeTypeAfter : Symbol(changeTypeAfter, Decl(objectSpread.ts, 60, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 60, 22)) +>b : Symbol(b, Decl(objectSpread.ts, 60, 33)) { ...o, a: 'wrong type?' } >o : Symbol(o, Decl(objectSpread.ts, 0, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 54, 11)) +>a : Symbol(a, Decl(objectSpread.ts, 61, 11)) let changeTypeBefore: { a: number, b: string } = ->changeTypeBefore : Symbol(changeTypeBefore, Decl(objectSpread.ts, 55, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 55, 23)) ->b : Symbol(b, Decl(objectSpread.ts, 55, 34)) +>changeTypeBefore : Symbol(changeTypeBefore, Decl(objectSpread.ts, 62, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 62, 23)) +>b : Symbol(b, Decl(objectSpread.ts, 62, 34)) { a: 'wrong type?', ...o }; ->a : Symbol(a, Decl(objectSpread.ts, 56, 5)) +>a : Symbol(a, Decl(objectSpread.ts, 63, 5)) >o : Symbol(o, Decl(objectSpread.ts, 0, 3)) let changeTypeBoth: { a: string, b: number } = ->changeTypeBoth : Symbol(changeTypeBoth, Decl(objectSpread.ts, 57, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 57, 21)) ->b : Symbol(b, Decl(objectSpread.ts, 57, 32)) +>changeTypeBoth : Symbol(changeTypeBoth, Decl(objectSpread.ts, 64, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 64, 21)) +>b : Symbol(b, Decl(objectSpread.ts, 64, 32)) { ...o, ...swap }; >o : Symbol(o, Decl(objectSpread.ts, 0, 3)) >swap : Symbol(swap, Decl(objectSpread.ts, 2, 3)) // optional -let definiteBoolean: { sn: boolean }; ->definiteBoolean : Symbol(definiteBoolean, Decl(objectSpread.ts, 61, 3)) ->sn : Symbol(sn, Decl(objectSpread.ts, 61, 22)) +function container( +>container : Symbol(container, Decl(objectSpread.ts, 65, 22)) -let definiteString: { sn: string }; ->definiteString : Symbol(definiteString, Decl(objectSpread.ts, 62, 3)) ->sn : Symbol(sn, Decl(objectSpread.ts, 62, 21)) + definiteBoolean: { sn: boolean }, +>definiteBoolean : Symbol(definiteBoolean, Decl(objectSpread.ts, 68, 19)) +>sn : Symbol(sn, Decl(objectSpread.ts, 69, 22)) -let optionalString: { sn?: string }; ->optionalString : Symbol(optionalString, Decl(objectSpread.ts, 63, 3)) ->sn : Symbol(sn, Decl(objectSpread.ts, 63, 21)) + definiteString: { sn: string }, +>definiteString : Symbol(definiteString, Decl(objectSpread.ts, 69, 37)) +>sn : Symbol(sn, Decl(objectSpread.ts, 70, 21)) -let optionalNumber: { sn?: number }; ->optionalNumber : Symbol(optionalNumber, Decl(objectSpread.ts, 64, 3)) ->sn : Symbol(sn, Decl(objectSpread.ts, 64, 21)) + optionalString: { sn?: string }, +>optionalString : Symbol(optionalString, Decl(objectSpread.ts, 70, 35)) +>sn : Symbol(sn, Decl(objectSpread.ts, 71, 21)) -let optionalUnionStops: { sn: string | number | boolean } = { ...definiteBoolean, ...definiteString, ...optionalNumber }; ->optionalUnionStops : Symbol(optionalUnionStops, Decl(objectSpread.ts, 65, 3)) ->sn : Symbol(sn, Decl(objectSpread.ts, 65, 25)) ->definiteBoolean : Symbol(definiteBoolean, Decl(objectSpread.ts, 61, 3)) ->definiteString : Symbol(definiteString, Decl(objectSpread.ts, 62, 3)) ->optionalNumber : Symbol(optionalNumber, Decl(objectSpread.ts, 64, 3)) + optionalNumber: { sn?: number }) { +>optionalNumber : Symbol(optionalNumber, Decl(objectSpread.ts, 71, 36)) +>sn : Symbol(sn, Decl(objectSpread.ts, 72, 21)) -let optionalUnionDuplicates: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...optionalString, ...optionalNumber }; ->optionalUnionDuplicates : Symbol(optionalUnionDuplicates, Decl(objectSpread.ts, 66, 3)) ->sn : Symbol(sn, Decl(objectSpread.ts, 66, 30)) ->definiteBoolean : Symbol(definiteBoolean, Decl(objectSpread.ts, 61, 3)) ->definiteString : Symbol(definiteString, Decl(objectSpread.ts, 62, 3)) ->optionalString : Symbol(optionalString, Decl(objectSpread.ts, 63, 3)) ->optionalNumber : Symbol(optionalNumber, Decl(objectSpread.ts, 64, 3)) + let optionalUnionStops: { sn: string | number | boolean } = { ...definiteBoolean, ...definiteString, ...optionalNumber }; +>optionalUnionStops : Symbol(optionalUnionStops, Decl(objectSpread.ts, 73, 7)) +>sn : Symbol(sn, Decl(objectSpread.ts, 73, 29)) +>definiteBoolean : Symbol(definiteBoolean, Decl(objectSpread.ts, 68, 19)) +>definiteString : Symbol(definiteString, Decl(objectSpread.ts, 69, 37)) +>optionalNumber : Symbol(optionalNumber, Decl(objectSpread.ts, 71, 36)) -let allOptional: { sn?: string | number } = { ...optionalString, ...optionalNumber }; ->allOptional : Symbol(allOptional, Decl(objectSpread.ts, 67, 3)) ->sn : Symbol(sn, Decl(objectSpread.ts, 67, 18)) ->optionalString : Symbol(optionalString, Decl(objectSpread.ts, 63, 3)) ->optionalNumber : Symbol(optionalNumber, Decl(objectSpread.ts, 64, 3)) + let optionalUnionDuplicates: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...optionalString, ...optionalNumber }; +>optionalUnionDuplicates : Symbol(optionalUnionDuplicates, Decl(objectSpread.ts, 74, 7)) +>sn : Symbol(sn, Decl(objectSpread.ts, 74, 34)) +>definiteBoolean : Symbol(definiteBoolean, Decl(objectSpread.ts, 68, 19)) +>definiteString : Symbol(definiteString, Decl(objectSpread.ts, 69, 37)) +>optionalString : Symbol(optionalString, Decl(objectSpread.ts, 70, 35)) +>optionalNumber : Symbol(optionalNumber, Decl(objectSpread.ts, 71, 36)) -// computed property -let computedFirst: { a: number, b: string, "before everything": number } = ->computedFirst : Symbol(computedFirst, Decl(objectSpread.ts, 70, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 70, 20)) ->b : Symbol(b, Decl(objectSpread.ts, 70, 31)) + let allOptional: { sn?: string | number } = { ...optionalString, ...optionalNumber }; +>allOptional : Symbol(allOptional, Decl(objectSpread.ts, 75, 7)) +>sn : Symbol(sn, Decl(objectSpread.ts, 75, 22)) +>optionalString : Symbol(optionalString, Decl(objectSpread.ts, 70, 35)) +>optionalNumber : Symbol(optionalNumber, Decl(objectSpread.ts, 71, 36)) - { ['before everything']: 12, ...o, b: 'yes' } ->'before everything' : Symbol(['before everything'], Decl(objectSpread.ts, 71, 5)) + // computed property + let computedFirst: { a: number, b: string, "before everything": number } = +>computedFirst : Symbol(computedFirst, Decl(objectSpread.ts, 78, 7)) +>a : Symbol(a, Decl(objectSpread.ts, 78, 24)) +>b : Symbol(b, Decl(objectSpread.ts, 78, 35)) + + { ['before everything']: 12, ...o, b: 'yes' } +>'before everything' : Symbol(['before everything'], Decl(objectSpread.ts, 79, 9)) >o : Symbol(o, Decl(objectSpread.ts, 0, 3)) ->b : Symbol(b, Decl(objectSpread.ts, 71, 38)) +>b : Symbol(b, Decl(objectSpread.ts, 79, 42)) -let computedMiddle: { a: number, b: string, c: boolean, "in the middle": number } = ->computedMiddle : Symbol(computedMiddle, Decl(objectSpread.ts, 72, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 72, 21)) ->b : Symbol(b, Decl(objectSpread.ts, 72, 32)) ->c : Symbol(c, Decl(objectSpread.ts, 72, 43)) + let computedMiddle: { a: number, b: string, c: boolean, "in the middle": number } = +>computedMiddle : Symbol(computedMiddle, Decl(objectSpread.ts, 80, 7)) +>a : Symbol(a, Decl(objectSpread.ts, 80, 25)) +>b : Symbol(b, Decl(objectSpread.ts, 80, 36)) +>c : Symbol(c, Decl(objectSpread.ts, 80, 47)) - { ...o, ['in the middle']: 13, b: 'maybe?', ...o2 } + { ...o, ['in the middle']: 13, b: 'maybe?', ...o2 } >o : Symbol(o, Decl(objectSpread.ts, 0, 3)) ->'in the middle' : Symbol(['in the middle'], Decl(objectSpread.ts, 73, 11)) ->b : Symbol(b, Decl(objectSpread.ts, 73, 34)) +>'in the middle' : Symbol(['in the middle'], Decl(objectSpread.ts, 81, 15)) +>b : Symbol(b, Decl(objectSpread.ts, 81, 38)) >o2 : Symbol(o2, Decl(objectSpread.ts, 1, 3)) -let computedAfter: { a: number, b: string, "at the end": number } = ->computedAfter : Symbol(computedAfter, Decl(objectSpread.ts, 74, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 74, 20)) ->b : Symbol(b, Decl(objectSpread.ts, 74, 31)) + let computedAfter: { a: number, b: string, "at the end": number } = +>computedAfter : Symbol(computedAfter, Decl(objectSpread.ts, 82, 7)) +>a : Symbol(a, Decl(objectSpread.ts, 82, 24)) +>b : Symbol(b, Decl(objectSpread.ts, 82, 35)) - { ...o, b: 'yeah', ['at the end']: 14 } + { ...o, b: 'yeah', ['at the end']: 14 } >o : Symbol(o, Decl(objectSpread.ts, 0, 3)) ->b : Symbol(b, Decl(objectSpread.ts, 75, 11)) ->'at the end' : Symbol(['at the end'], Decl(objectSpread.ts, 75, 22)) - +>b : Symbol(b, Decl(objectSpread.ts, 83, 15)) +>'at the end' : Symbol(['at the end'], Decl(objectSpread.ts, 83, 26)) +} // shortcut syntax let a = 12; ->a : Symbol(a, Decl(objectSpread.ts, 77, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 86, 3)) let shortCutted: { a: number, b: string } = { ...o, a } ->shortCutted : Symbol(shortCutted, Decl(objectSpread.ts, 78, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 78, 18)) ->b : Symbol(b, Decl(objectSpread.ts, 78, 29)) +>shortCutted : Symbol(shortCutted, Decl(objectSpread.ts, 87, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 87, 18)) +>b : Symbol(b, Decl(objectSpread.ts, 87, 29)) >o : Symbol(o, Decl(objectSpread.ts, 0, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 78, 51)) +>a : Symbol(a, Decl(objectSpread.ts, 87, 51)) // non primitive let spreadNonPrimitive = { ...{}}; ->spreadNonPrimitive : Symbol(spreadNonPrimitive, Decl(objectSpread.ts, 80, 3)) +>spreadNonPrimitive : Symbol(spreadNonPrimitive, Decl(objectSpread.ts, 89, 3)) diff --git a/tests/baselines/reference/objectSpread.types b/tests/baselines/reference/objectSpread.types index 7bac35119ed..d696ed9ac7c 100644 --- a/tests/baselines/reference/objectSpread.types +++ b/tests/baselines/reference/objectSpread.types @@ -230,6 +230,29 @@ let spreadFunc = { ...(function () { }) }; >(function () { }) : () => void >function () { } : () => void +// boolean && T results in Partial +function conditionalSpread(b: boolean) : { x?: number | undefined, y?: number | undefined } { +>conditionalSpread : (b: boolean) => { x?: number | undefined; y?: number | undefined; } +>b : boolean +>x : number | undefined +>y : number | undefined + + return { ...b && { x: 1, y: 2 } }; +>{ ...b && { x: 1, y: 2 } } : { x?: number | undefined; y?: number | undefined; } +>b && { x: 1, y: 2 } : false | { x: number; y: number; } +>b : boolean +>{ x: 1, y: 2 } : { x: number; y: number; } +>x : number +>1 : 1 +>y : number +>2 : 2 +} +// other booleans result in { } +let spreadBool = { ... true } +>spreadBool : {} +>{ ... true } : {} +>true : true + // any results in any let anything: any; >anything : any @@ -312,53 +335,56 @@ let changeTypeBoth: { a: string, b: number } = >swap : { a: string; b: number; } // optional -let definiteBoolean: { sn: boolean }; +function container( +>container : (definiteBoolean: { sn: boolean; }, definiteString: { sn: string; }, optionalString: { sn?: string | undefined; }, optionalNumber: { sn?: number | undefined; }) => void + + definiteBoolean: { sn: boolean }, >definiteBoolean : { sn: boolean; } >sn : boolean -let definiteString: { sn: string }; + definiteString: { sn: string }, >definiteString : { sn: string; } >sn : string -let optionalString: { sn?: string }; ->optionalString : { sn?: string; } ->sn : string + optionalString: { sn?: string }, +>optionalString : { sn?: string | undefined; } +>sn : string | undefined -let optionalNumber: { sn?: number }; ->optionalNumber : { sn?: number; } ->sn : number + optionalNumber: { sn?: number }) { +>optionalNumber : { sn?: number | undefined; } +>sn : number | undefined -let optionalUnionStops: { sn: string | number | boolean } = { ...definiteBoolean, ...definiteString, ...optionalNumber }; + let optionalUnionStops: { sn: string | number | boolean } = { ...definiteBoolean, ...definiteString, ...optionalNumber }; >optionalUnionStops : { sn: string | number | boolean; } >sn : string | number | boolean >{ ...definiteBoolean, ...definiteString, ...optionalNumber } : { sn: string | number; } >definiteBoolean : { sn: boolean; } >definiteString : { sn: string; } ->optionalNumber : { sn?: number; } +>optionalNumber : { sn?: number | undefined; } -let optionalUnionDuplicates: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...optionalString, ...optionalNumber }; + let optionalUnionDuplicates: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...optionalString, ...optionalNumber }; >optionalUnionDuplicates : { sn: string | number; } >sn : string | number >{ ...definiteBoolean, ...definiteString, ...optionalString, ...optionalNumber } : { sn: string | number; } >definiteBoolean : { sn: boolean; } >definiteString : { sn: string; } ->optionalString : { sn?: string; } ->optionalNumber : { sn?: number; } +>optionalString : { sn?: string | undefined; } +>optionalNumber : { sn?: number | undefined; } -let allOptional: { sn?: string | number } = { ...optionalString, ...optionalNumber }; ->allOptional : { sn?: string | number; } ->sn : string | number ->{ ...optionalString, ...optionalNumber } : { sn?: string | number; } ->optionalString : { sn?: string; } ->optionalNumber : { sn?: number; } + let allOptional: { sn?: string | number } = { ...optionalString, ...optionalNumber }; +>allOptional : { sn?: string | number | undefined; } +>sn : string | number | undefined +>{ ...optionalString, ...optionalNumber } : { sn?: string | number | undefined; } +>optionalString : { sn?: string | undefined; } +>optionalNumber : { sn?: number | undefined; } -// computed property -let computedFirst: { a: number, b: string, "before everything": number } = + // computed property + let computedFirst: { a: number, b: string, "before everything": number } = >computedFirst : { a: number; b: string; "before everything": number; } >a : number >b : string - { ['before everything']: 12, ...o, b: 'yes' } + { ['before everything']: 12, ...o, b: 'yes' } >{ ['before everything']: 12, ...o, b: 'yes' } : { b: string; a: number; ['before everything']: number; } >'before everything' : "before everything" >12 : 12 @@ -366,13 +392,13 @@ let computedFirst: { a: number, b: string, "before everything": number } = >b : string >'yes' : "yes" -let computedMiddle: { a: number, b: string, c: boolean, "in the middle": number } = + let computedMiddle: { a: number, b: string, c: boolean, "in the middle": number } = >computedMiddle : { a: number; b: string; c: boolean; "in the middle": number; } >a : number >b : string >c : boolean - { ...o, ['in the middle']: 13, b: 'maybe?', ...o2 } + { ...o, ['in the middle']: 13, b: 'maybe?', ...o2 } >{ ...o, ['in the middle']: 13, b: 'maybe?', ...o2 } : { b: string; c: boolean; ['in the middle']: number; a: number; } >o : { a: number; b: string; } >'in the middle' : "in the middle" @@ -381,19 +407,19 @@ let computedMiddle: { a: number, b: string, c: boolean, "in the middle": number >'maybe?' : "maybe?" >o2 : { b: string; c: boolean; } -let computedAfter: { a: number, b: string, "at the end": number } = + let computedAfter: { a: number, b: string, "at the end": number } = >computedAfter : { a: number; b: string; "at the end": number; } >a : number >b : string - { ...o, b: 'yeah', ['at the end']: 14 } + { ...o, b: 'yeah', ['at the end']: 14 } >{ ...o, b: 'yeah', ['at the end']: 14 } : { b: string; ['at the end']: number; a: number; } >o : { a: number; b: string; } >b : string >'yeah' : "yeah" >'at the end' : "at the end" >14 : 14 - +} // shortcut syntax let a = 12; >a : number diff --git a/tests/baselines/reference/objectSpreadNegative.errors.txt b/tests/baselines/reference/objectSpreadNegative.errors.txt index a9381a0dcb1..14eba9d6f2a 100644 --- a/tests/baselines/reference/objectSpreadNegative.errors.txt +++ b/tests/baselines/reference/objectSpreadNegative.errors.txt @@ -9,23 +9,22 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(28,36): error TS230 tests/cases/conformance/types/spread/objectSpreadNegative.ts(28,53): error TS2300: Duplicate identifier 'b'. tests/cases/conformance/types/spread/objectSpreadNegative.ts(32,19): error TS2698: Spread types may only be created from object types. tests/cases/conformance/types/spread/objectSpreadNegative.ts(33,19): error TS2698: Spread types may only be created from object types. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(35,20): error TS2698: Spread types may only be created from object types. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(37,19): error TS2698: Spread types may only be created from object types. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(42,1): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type '{}' has no compatible call signatures. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(46,12): error TS2339: Property 'b' does not exist on type '{}'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(52,9): error TS2339: Property 'm' does not exist on type '{ p: number; }'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(57,11): error TS2339: Property 'a' does not exist on type '{}'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(34,19): error TS2698: Spread types may only be created from object types. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(39,1): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type '{}' has no compatible call signatures. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(43,12): error TS2339: Property 'b' does not exist on type '{}'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(49,9): error TS2339: Property 'm' does not exist on type '{ p: number; }'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(54,11): error TS2339: Property 'a' does not exist on type '{}'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(58,14): error TS2698: Spread types may only be created from object types. tests/cases/conformance/types/spread/objectSpreadNegative.ts(61,14): error TS2698: Spread types may only be created from object types. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(64,14): error TS2698: Spread types may only be created from object types. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(78,37): error TS2322: Type '{ a: string; b: string; extra: string; }' is not assignable to type 'A'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(75,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(81,7): error TS2322: Type '{ a: string; b: string; extra: string; }' is not assignable to type 'A'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(78,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(83,7): error TS2322: Type '{ a: string; b: string; extra: string; }' is not assignable to type 'A'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(80,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 (19 errors) ==== +==== tests/cases/conformance/types/spread/objectSpreadNegative.ts (18 errors) ==== let o = { a: 1, b: 'no' } /// private propagates @@ -78,11 +77,6 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(83,7): error TS2322 let spreadSum = { ...1 + 1 }; ~~~~~~~~ !!! error TS2698: Spread types may only be created from object types. - spreadSum.toFixed(); // error, no methods from number - let spreadBool = { ...false }; - ~~~~~~~~ -!!! error TS2698: Spread types may only be created from object types. - spreadBool.valueOf(); // error, what were you thinking? let spreadStr = { ...'foo' }; ~~~~~~~~ !!! error TS2698: Spread types may only be created from object types. diff --git a/tests/baselines/reference/objectSpreadNegative.js b/tests/baselines/reference/objectSpreadNegative.js index aab8ffc4e91..6e82a19acbc 100644 --- a/tests/baselines/reference/objectSpreadNegative.js +++ b/tests/baselines/reference/objectSpreadNegative.js @@ -32,9 +32,6 @@ let duplicatedSpread = { ...o, ...o } // primitives are not allowed let spreadNum = { ...12 }; let spreadSum = { ...1 + 1 }; -spreadSum.toFixed(); // error, no methods from number -let spreadBool = { ...false }; -spreadBool.valueOf(); // error, what were you thinking? let spreadStr = { ...'foo' }; spreadStr.length; // error, no 'length' spreadStr.charAt(1); // error, no methods either @@ -124,9 +121,6 @@ var duplicatedSpread = __assign({}, o, o); // primitives are not allowed var spreadNum = __assign({}, 12); var spreadSum = __assign({}, 1 + 1); -spreadSum.toFixed(); // error, no methods from number -var spreadBool = __assign({}, false); -spreadBool.valueOf(); // error, what were you thinking? var spreadStr = __assign({}, 'foo'); spreadStr.length; // error, no 'length' spreadStr.charAt(1); // error, no methods either diff --git a/tests/cases/conformance/types/spread/objectSpread.ts b/tests/cases/conformance/types/spread/objectSpread.ts index 59b93bdd9e4..378c5558fc5 100644 --- a/tests/cases/conformance/types/spread/objectSpread.ts +++ b/tests/cases/conformance/types/spread/objectSpread.ts @@ -1,3 +1,4 @@ +// @strictNullChecks: true // @target: es5 let o = { a: 1, b: 'no' } let o2 = { b: 'yes', c: true } @@ -38,6 +39,13 @@ getter.a = 12; // functions result in { } let spreadFunc = { ...(function () { }) }; +// boolean && T results in Partial +function conditionalSpread(b: boolean) : { x?: number | undefined, y?: number | undefined } { + return { ...b && { x: 1, y: 2 } }; +} +// other booleans result in { } +let spreadBool = { ... true } + // any results in any let anything: any; let spreadAny = { ...anything }; @@ -60,21 +68,23 @@ let changeTypeBoth: { a: string, b: number } = { ...o, ...swap }; // optional -let definiteBoolean: { sn: boolean }; -let definiteString: { sn: string }; -let optionalString: { sn?: string }; -let optionalNumber: { sn?: number }; -let optionalUnionStops: { sn: string | number | boolean } = { ...definiteBoolean, ...definiteString, ...optionalNumber }; -let optionalUnionDuplicates: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...optionalString, ...optionalNumber }; -let allOptional: { sn?: string | number } = { ...optionalString, ...optionalNumber }; +function container( + definiteBoolean: { sn: boolean }, + definiteString: { sn: string }, + optionalString: { sn?: string }, + optionalNumber: { sn?: number }) { + let optionalUnionStops: { sn: string | number | boolean } = { ...definiteBoolean, ...definiteString, ...optionalNumber }; + let optionalUnionDuplicates: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...optionalString, ...optionalNumber }; + let allOptional: { sn?: string | number } = { ...optionalString, ...optionalNumber }; -// computed property -let computedFirst: { a: number, b: string, "before everything": number } = - { ['before everything']: 12, ...o, b: 'yes' } -let computedMiddle: { a: number, b: string, c: boolean, "in the middle": number } = - { ...o, ['in the middle']: 13, b: 'maybe?', ...o2 } -let computedAfter: { a: number, b: string, "at the end": number } = - { ...o, b: 'yeah', ['at the end']: 14 } + // computed property + let computedFirst: { a: number, b: string, "before everything": number } = + { ['before everything']: 12, ...o, b: 'yes' } + let computedMiddle: { a: number, b: string, c: boolean, "in the middle": number } = + { ...o, ['in the middle']: 13, b: 'maybe?', ...o2 } + let computedAfter: { a: number, b: string, "at the end": number } = + { ...o, b: 'yeah', ['at the end']: 14 } +} // shortcut syntax let a = 12; let shortCutted: { a: number, b: string } = { ...o, a } diff --git a/tests/cases/conformance/types/spread/objectSpreadNegative.ts b/tests/cases/conformance/types/spread/objectSpreadNegative.ts index fced7706c96..beb9ff265b4 100644 --- a/tests/cases/conformance/types/spread/objectSpreadNegative.ts +++ b/tests/cases/conformance/types/spread/objectSpreadNegative.ts @@ -32,9 +32,6 @@ let duplicatedSpread = { ...o, ...o } // primitives are not allowed let spreadNum = { ...12 }; let spreadSum = { ...1 + 1 }; -spreadSum.toFixed(); // error, no methods from number -let spreadBool = { ...false }; -spreadBool.valueOf(); // error, what were you thinking? let spreadStr = { ...'foo' }; spreadStr.length; // error, no 'length' spreadStr.charAt(1); // error, no methods either From d951c14052b077cef3b8d1d6ef83c89f766c6d47 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Wed, 13 Sep 2017 14:56:15 -0700 Subject: [PATCH 03/10] Allow all possibly falsy types in spreads And update tests to reflect that --- src/compiler/checker.ts | 10 +- tests/baselines/reference/objectSpread.js | 34 ++- .../baselines/reference/objectSpread.symbols | 230 +++++++++++------- tests/baselines/reference/objectSpread.types | 86 ++++++- .../reference/objectSpreadNegative.errors.txt | 17 +- .../objectSpreadNegativeParse.errors.txt | 5 +- .../conformance/types/spread/objectSpread.ts | 20 +- 7 files changed, 296 insertions(+), 106 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 287311e6433..ff796879071 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7850,7 +7850,7 @@ namespace ts { return mapType(right, t => getSpreadType(left, t)); } } - if (right.flags & (TypeFlags.NonPrimitive | TypeFlags.BooleanLike)) { + if (right.flags & (TypeFlags.NonPrimitive | TypeFlags.BooleanLike | TypeFlags.NumberLike | TypeFlags.StringLike)) { return emptyObjectType; } @@ -7923,7 +7923,11 @@ namespace ts { function getPartialTypeFromFalseUnion(type: UnionType): Type | undefined { if (type.types.length === 2) { - const i = type.types.indexOf(falseType); + // getFalsyFlagsOfTypes + // getTypeFacts + const i = Math.max(type.types.indexOf(falseType), + type.types.indexOf(zeroType), + type.types.indexOf(emptyStringType)); if (i > -1) { const members = createSymbolTable(); const other = type.types[i === 0 ? 1 : 0]; @@ -13785,7 +13789,7 @@ namespace ts { } function isValidSpreadType(type: Type): boolean { - return !!(type.flags & (TypeFlags.Any | TypeFlags.Nullable | TypeFlags.NonPrimitive | TypeFlags.BooleanLike) || + return !!(type.flags & (TypeFlags.Any | TypeFlags.PossiblyFalsy | TypeFlags.NonPrimitive) || type.flags & TypeFlags.Object && !isGenericMappedType(type) || type.flags & TypeFlags.UnionOrIntersection && !forEach((type).types, t => !isValidSpreadType(t))); } diff --git a/tests/baselines/reference/objectSpread.js b/tests/baselines/reference/objectSpread.js index 11b904a4806..7eab2da265f 100644 --- a/tests/baselines/reference/objectSpread.js +++ b/tests/baselines/reference/objectSpread.js @@ -39,9 +39,27 @@ getter.a = 12; let spreadFunc = { ...(function () { }) }; // boolean && T results in Partial -function conditionalSpread(b: boolean) : { x?: number | undefined, y?: number | undefined } { +function conditionalSpreadBoolean(b: boolean) : { x?: number | undefined, y?: number | undefined } { return { ...b && { x: 1, y: 2 } }; } +function conditionalSpreadNumber(nt: number): { x?: number | undefined, y: number } { + let o = { x: 12, y: 13 } + o = { + ...o, + ...nt && { x: nt } + } + let o2 = { ...nt && { x: nt }} + return o; +} +function conditionalSpreadString(st: string): { x?: string | undefined, y: number } { + let o = { x: 'hi', y: 13 } + o = { + ...o, + ...st && { x: st } + } + let o2 = { ...st && { x: st }} + return o; +} // other booleans result in { } let spreadBool = { ... true } @@ -124,9 +142,21 @@ getter.a = 12; // functions result in { } var spreadFunc = __assign({}, (function () { })); // boolean && T results in Partial -function conditionalSpread(b) { +function conditionalSpreadBoolean(b) { return __assign({}, b && { x: 1, y: 2 }); } +function conditionalSpreadNumber(nt) { + var o = { x: 12, y: 13 }; + o = __assign({}, o, nt && { x: nt }); + var o2 = __assign({}, nt && { x: nt }); + return o; +} +function conditionalSpreadString(st) { + var o = { x: 'hi', y: 13 }; + o = __assign({}, o, st && { x: st }); + var o2 = __assign({}, st && { x: st }); + return o; +} // other booleans result in { } var spreadBool = __assign({}, true); // any results in any diff --git a/tests/baselines/reference/objectSpread.symbols b/tests/baselines/reference/objectSpread.symbols index 0c5e8a4c5a8..9f257870a0b 100644 --- a/tests/baselines/reference/objectSpread.symbols +++ b/tests/baselines/reference/objectSpread.symbols @@ -170,81 +170,143 @@ let spreadFunc = { ...(function () { }) }; >spreadFunc : Symbol(spreadFunc, Decl(objectSpread.ts, 37, 3)) // boolean && T results in Partial -function conditionalSpread(b: boolean) : { x?: number | undefined, y?: number | undefined } { ->conditionalSpread : Symbol(conditionalSpread, Decl(objectSpread.ts, 37, 42)) ->b : Symbol(b, Decl(objectSpread.ts, 40, 27)) ->x : Symbol(x, Decl(objectSpread.ts, 40, 42)) ->y : Symbol(y, Decl(objectSpread.ts, 40, 66)) +function conditionalSpreadBoolean(b: boolean) : { x?: number | undefined, y?: number | undefined } { +>conditionalSpreadBoolean : Symbol(conditionalSpreadBoolean, Decl(objectSpread.ts, 37, 42)) +>b : Symbol(b, Decl(objectSpread.ts, 40, 34)) +>x : Symbol(x, Decl(objectSpread.ts, 40, 49)) +>y : Symbol(y, Decl(objectSpread.ts, 40, 73)) return { ...b && { x: 1, y: 2 } }; ->b : Symbol(b, Decl(objectSpread.ts, 40, 27)) +>b : Symbol(b, Decl(objectSpread.ts, 40, 34)) >x : Symbol(x, Decl(objectSpread.ts, 41, 22)) >y : Symbol(y, Decl(objectSpread.ts, 41, 28)) } +function conditionalSpreadNumber(nt: number): { x?: number | undefined, y: number } { +>conditionalSpreadNumber : Symbol(conditionalSpreadNumber, Decl(objectSpread.ts, 42, 1)) +>nt : Symbol(nt, Decl(objectSpread.ts, 43, 33)) +>x : Symbol(x, Decl(objectSpread.ts, 43, 47)) +>y : Symbol(y, Decl(objectSpread.ts, 43, 71)) + + let o = { x: 12, y: 13 } +>o : Symbol(o, Decl(objectSpread.ts, 44, 7)) +>x : Symbol(x, Decl(objectSpread.ts, 44, 13)) +>y : Symbol(y, Decl(objectSpread.ts, 44, 20)) + + o = { +>o : Symbol(o, Decl(objectSpread.ts, 44, 7)) + + ...o, +>o : Symbol(o, Decl(objectSpread.ts, 44, 7)) + + ...nt && { x: nt } +>nt : Symbol(nt, Decl(objectSpread.ts, 43, 33)) +>x : Symbol(x, Decl(objectSpread.ts, 47, 18)) +>nt : Symbol(nt, Decl(objectSpread.ts, 43, 33)) + } + let o2 = { ...nt && { x: nt }} +>o2 : Symbol(o2, Decl(objectSpread.ts, 49, 7)) +>nt : Symbol(nt, Decl(objectSpread.ts, 43, 33)) +>x : Symbol(x, Decl(objectSpread.ts, 49, 25)) +>nt : Symbol(nt, Decl(objectSpread.ts, 43, 33)) + + return o; +>o : Symbol(o, Decl(objectSpread.ts, 44, 7)) +} +function conditionalSpreadString(st: string): { x?: string | undefined, y: number } { +>conditionalSpreadString : Symbol(conditionalSpreadString, Decl(objectSpread.ts, 51, 1)) +>st : Symbol(st, Decl(objectSpread.ts, 52, 33)) +>x : Symbol(x, Decl(objectSpread.ts, 52, 47)) +>y : Symbol(y, Decl(objectSpread.ts, 52, 71)) + + let o = { x: 'hi', y: 13 } +>o : Symbol(o, Decl(objectSpread.ts, 53, 7)) +>x : Symbol(x, Decl(objectSpread.ts, 53, 13)) +>y : Symbol(y, Decl(objectSpread.ts, 53, 22)) + + o = { +>o : Symbol(o, Decl(objectSpread.ts, 53, 7)) + + ...o, +>o : Symbol(o, Decl(objectSpread.ts, 53, 7)) + + ...st && { x: st } +>st : Symbol(st, Decl(objectSpread.ts, 52, 33)) +>x : Symbol(x, Decl(objectSpread.ts, 56, 18)) +>st : Symbol(st, Decl(objectSpread.ts, 52, 33)) + } + let o2 = { ...st && { x: st }} +>o2 : Symbol(o2, Decl(objectSpread.ts, 58, 7)) +>st : Symbol(st, Decl(objectSpread.ts, 52, 33)) +>x : Symbol(x, Decl(objectSpread.ts, 58, 25)) +>st : Symbol(st, Decl(objectSpread.ts, 52, 33)) + + return o; +>o : Symbol(o, Decl(objectSpread.ts, 53, 7)) +} // other booleans result in { } let spreadBool = { ... true } ->spreadBool : Symbol(spreadBool, Decl(objectSpread.ts, 44, 3)) +>spreadBool : Symbol(spreadBool, Decl(objectSpread.ts, 62, 3)) // any results in any let anything: any; ->anything : Symbol(anything, Decl(objectSpread.ts, 47, 3)) +>anything : Symbol(anything, Decl(objectSpread.ts, 65, 3)) let spreadAny = { ...anything }; ->spreadAny : Symbol(spreadAny, Decl(objectSpread.ts, 48, 3)) ->anything : Symbol(anything, Decl(objectSpread.ts, 47, 3)) +>spreadAny : Symbol(spreadAny, Decl(objectSpread.ts, 66, 3)) +>anything : Symbol(anything, Decl(objectSpread.ts, 65, 3)) // methods are not enumerable class C { p = 1; m() { } } ->C : Symbol(C, Decl(objectSpread.ts, 48, 32)) ->p : Symbol(C.p, Decl(objectSpread.ts, 51, 9)) ->m : Symbol(C.m, Decl(objectSpread.ts, 51, 16)) +>C : Symbol(C, Decl(objectSpread.ts, 66, 32)) +>p : Symbol(C.p, Decl(objectSpread.ts, 69, 9)) +>m : Symbol(C.m, Decl(objectSpread.ts, 69, 16)) let c: C = new C() ->c : Symbol(c, Decl(objectSpread.ts, 52, 3)) ->C : Symbol(C, Decl(objectSpread.ts, 48, 32)) ->C : Symbol(C, Decl(objectSpread.ts, 48, 32)) +>c : Symbol(c, Decl(objectSpread.ts, 70, 3)) +>C : Symbol(C, Decl(objectSpread.ts, 66, 32)) +>C : Symbol(C, Decl(objectSpread.ts, 66, 32)) let spreadC: { p: number } = { ...c } ->spreadC : Symbol(spreadC, Decl(objectSpread.ts, 53, 3)) ->p : Symbol(p, Decl(objectSpread.ts, 53, 14)) ->c : Symbol(c, Decl(objectSpread.ts, 52, 3)) +>spreadC : Symbol(spreadC, Decl(objectSpread.ts, 71, 3)) +>p : Symbol(p, Decl(objectSpread.ts, 71, 14)) +>c : Symbol(c, Decl(objectSpread.ts, 70, 3)) // own methods are enumerable let cplus: { p: number, plus(): void } = { ...c, plus() { return this.p + 1; } }; ->cplus : Symbol(cplus, Decl(objectSpread.ts, 56, 3)) ->p : Symbol(p, Decl(objectSpread.ts, 56, 12)) ->plus : Symbol(plus, Decl(objectSpread.ts, 56, 23)) ->c : Symbol(c, Decl(objectSpread.ts, 52, 3)) ->plus : Symbol(plus, Decl(objectSpread.ts, 56, 48)) +>cplus : Symbol(cplus, Decl(objectSpread.ts, 74, 3)) +>p : Symbol(p, Decl(objectSpread.ts, 74, 12)) +>plus : Symbol(plus, Decl(objectSpread.ts, 74, 23)) +>c : Symbol(c, Decl(objectSpread.ts, 70, 3)) +>plus : Symbol(plus, Decl(objectSpread.ts, 74, 48)) cplus.plus(); ->cplus.plus : Symbol(plus, Decl(objectSpread.ts, 56, 23)) ->cplus : Symbol(cplus, Decl(objectSpread.ts, 56, 3)) ->plus : Symbol(plus, Decl(objectSpread.ts, 56, 23)) +>cplus.plus : Symbol(plus, Decl(objectSpread.ts, 74, 23)) +>cplus : Symbol(cplus, Decl(objectSpread.ts, 74, 3)) +>plus : Symbol(plus, Decl(objectSpread.ts, 74, 23)) // new field's type conflicting with existing field is OK let changeTypeAfter: { a: string, b: string } = ->changeTypeAfter : Symbol(changeTypeAfter, Decl(objectSpread.ts, 60, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 60, 22)) ->b : Symbol(b, Decl(objectSpread.ts, 60, 33)) +>changeTypeAfter : Symbol(changeTypeAfter, Decl(objectSpread.ts, 78, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 78, 22)) +>b : Symbol(b, Decl(objectSpread.ts, 78, 33)) { ...o, a: 'wrong type?' } >o : Symbol(o, Decl(objectSpread.ts, 0, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 61, 11)) +>a : Symbol(a, Decl(objectSpread.ts, 79, 11)) let changeTypeBefore: { a: number, b: string } = ->changeTypeBefore : Symbol(changeTypeBefore, Decl(objectSpread.ts, 62, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 62, 23)) ->b : Symbol(b, Decl(objectSpread.ts, 62, 34)) +>changeTypeBefore : Symbol(changeTypeBefore, Decl(objectSpread.ts, 80, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 80, 23)) +>b : Symbol(b, Decl(objectSpread.ts, 80, 34)) { a: 'wrong type?', ...o }; ->a : Symbol(a, Decl(objectSpread.ts, 63, 5)) +>a : Symbol(a, Decl(objectSpread.ts, 81, 5)) >o : Symbol(o, Decl(objectSpread.ts, 0, 3)) let changeTypeBoth: { a: string, b: number } = ->changeTypeBoth : Symbol(changeTypeBoth, Decl(objectSpread.ts, 64, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 64, 21)) ->b : Symbol(b, Decl(objectSpread.ts, 64, 32)) +>changeTypeBoth : Symbol(changeTypeBoth, Decl(objectSpread.ts, 82, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 82, 21)) +>b : Symbol(b, Decl(objectSpread.ts, 82, 32)) { ...o, ...swap }; >o : Symbol(o, Decl(objectSpread.ts, 0, 3)) @@ -252,90 +314,90 @@ let changeTypeBoth: { a: string, b: number } = // optional function container( ->container : Symbol(container, Decl(objectSpread.ts, 65, 22)) +>container : Symbol(container, Decl(objectSpread.ts, 83, 22)) definiteBoolean: { sn: boolean }, ->definiteBoolean : Symbol(definiteBoolean, Decl(objectSpread.ts, 68, 19)) ->sn : Symbol(sn, Decl(objectSpread.ts, 69, 22)) +>definiteBoolean : Symbol(definiteBoolean, Decl(objectSpread.ts, 86, 19)) +>sn : Symbol(sn, Decl(objectSpread.ts, 87, 22)) definiteString: { sn: string }, ->definiteString : Symbol(definiteString, Decl(objectSpread.ts, 69, 37)) ->sn : Symbol(sn, Decl(objectSpread.ts, 70, 21)) +>definiteString : Symbol(definiteString, Decl(objectSpread.ts, 87, 37)) +>sn : Symbol(sn, Decl(objectSpread.ts, 88, 21)) optionalString: { sn?: string }, ->optionalString : Symbol(optionalString, Decl(objectSpread.ts, 70, 35)) ->sn : Symbol(sn, Decl(objectSpread.ts, 71, 21)) +>optionalString : Symbol(optionalString, Decl(objectSpread.ts, 88, 35)) +>sn : Symbol(sn, Decl(objectSpread.ts, 89, 21)) optionalNumber: { sn?: number }) { ->optionalNumber : Symbol(optionalNumber, Decl(objectSpread.ts, 71, 36)) ->sn : Symbol(sn, Decl(objectSpread.ts, 72, 21)) +>optionalNumber : Symbol(optionalNumber, Decl(objectSpread.ts, 89, 36)) +>sn : Symbol(sn, Decl(objectSpread.ts, 90, 21)) let optionalUnionStops: { sn: string | number | boolean } = { ...definiteBoolean, ...definiteString, ...optionalNumber }; ->optionalUnionStops : Symbol(optionalUnionStops, Decl(objectSpread.ts, 73, 7)) ->sn : Symbol(sn, Decl(objectSpread.ts, 73, 29)) ->definiteBoolean : Symbol(definiteBoolean, Decl(objectSpread.ts, 68, 19)) ->definiteString : Symbol(definiteString, Decl(objectSpread.ts, 69, 37)) ->optionalNumber : Symbol(optionalNumber, Decl(objectSpread.ts, 71, 36)) +>optionalUnionStops : Symbol(optionalUnionStops, Decl(objectSpread.ts, 91, 7)) +>sn : Symbol(sn, Decl(objectSpread.ts, 91, 29)) +>definiteBoolean : Symbol(definiteBoolean, Decl(objectSpread.ts, 86, 19)) +>definiteString : Symbol(definiteString, Decl(objectSpread.ts, 87, 37)) +>optionalNumber : Symbol(optionalNumber, Decl(objectSpread.ts, 89, 36)) let optionalUnionDuplicates: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...optionalString, ...optionalNumber }; ->optionalUnionDuplicates : Symbol(optionalUnionDuplicates, Decl(objectSpread.ts, 74, 7)) ->sn : Symbol(sn, Decl(objectSpread.ts, 74, 34)) ->definiteBoolean : Symbol(definiteBoolean, Decl(objectSpread.ts, 68, 19)) ->definiteString : Symbol(definiteString, Decl(objectSpread.ts, 69, 37)) ->optionalString : Symbol(optionalString, Decl(objectSpread.ts, 70, 35)) ->optionalNumber : Symbol(optionalNumber, Decl(objectSpread.ts, 71, 36)) +>optionalUnionDuplicates : Symbol(optionalUnionDuplicates, Decl(objectSpread.ts, 92, 7)) +>sn : Symbol(sn, Decl(objectSpread.ts, 92, 34)) +>definiteBoolean : Symbol(definiteBoolean, Decl(objectSpread.ts, 86, 19)) +>definiteString : Symbol(definiteString, Decl(objectSpread.ts, 87, 37)) +>optionalString : Symbol(optionalString, Decl(objectSpread.ts, 88, 35)) +>optionalNumber : Symbol(optionalNumber, Decl(objectSpread.ts, 89, 36)) let allOptional: { sn?: string | number } = { ...optionalString, ...optionalNumber }; ->allOptional : Symbol(allOptional, Decl(objectSpread.ts, 75, 7)) ->sn : Symbol(sn, Decl(objectSpread.ts, 75, 22)) ->optionalString : Symbol(optionalString, Decl(objectSpread.ts, 70, 35)) ->optionalNumber : Symbol(optionalNumber, Decl(objectSpread.ts, 71, 36)) +>allOptional : Symbol(allOptional, Decl(objectSpread.ts, 93, 7)) +>sn : Symbol(sn, Decl(objectSpread.ts, 93, 22)) +>optionalString : Symbol(optionalString, Decl(objectSpread.ts, 88, 35)) +>optionalNumber : Symbol(optionalNumber, Decl(objectSpread.ts, 89, 36)) // computed property let computedFirst: { a: number, b: string, "before everything": number } = ->computedFirst : Symbol(computedFirst, Decl(objectSpread.ts, 78, 7)) ->a : Symbol(a, Decl(objectSpread.ts, 78, 24)) ->b : Symbol(b, Decl(objectSpread.ts, 78, 35)) +>computedFirst : Symbol(computedFirst, Decl(objectSpread.ts, 96, 7)) +>a : Symbol(a, Decl(objectSpread.ts, 96, 24)) +>b : Symbol(b, Decl(objectSpread.ts, 96, 35)) { ['before everything']: 12, ...o, b: 'yes' } ->'before everything' : Symbol(['before everything'], Decl(objectSpread.ts, 79, 9)) +>'before everything' : Symbol(['before everything'], Decl(objectSpread.ts, 97, 9)) >o : Symbol(o, Decl(objectSpread.ts, 0, 3)) ->b : Symbol(b, Decl(objectSpread.ts, 79, 42)) +>b : Symbol(b, Decl(objectSpread.ts, 97, 42)) let computedMiddle: { a: number, b: string, c: boolean, "in the middle": number } = ->computedMiddle : Symbol(computedMiddle, Decl(objectSpread.ts, 80, 7)) ->a : Symbol(a, Decl(objectSpread.ts, 80, 25)) ->b : Symbol(b, Decl(objectSpread.ts, 80, 36)) ->c : Symbol(c, Decl(objectSpread.ts, 80, 47)) +>computedMiddle : Symbol(computedMiddle, Decl(objectSpread.ts, 98, 7)) +>a : Symbol(a, Decl(objectSpread.ts, 98, 25)) +>b : Symbol(b, Decl(objectSpread.ts, 98, 36)) +>c : Symbol(c, Decl(objectSpread.ts, 98, 47)) { ...o, ['in the middle']: 13, b: 'maybe?', ...o2 } >o : Symbol(o, Decl(objectSpread.ts, 0, 3)) ->'in the middle' : Symbol(['in the middle'], Decl(objectSpread.ts, 81, 15)) ->b : Symbol(b, Decl(objectSpread.ts, 81, 38)) +>'in the middle' : Symbol(['in the middle'], Decl(objectSpread.ts, 99, 15)) +>b : Symbol(b, Decl(objectSpread.ts, 99, 38)) >o2 : Symbol(o2, Decl(objectSpread.ts, 1, 3)) let computedAfter: { a: number, b: string, "at the end": number } = ->computedAfter : Symbol(computedAfter, Decl(objectSpread.ts, 82, 7)) ->a : Symbol(a, Decl(objectSpread.ts, 82, 24)) ->b : Symbol(b, Decl(objectSpread.ts, 82, 35)) +>computedAfter : Symbol(computedAfter, Decl(objectSpread.ts, 100, 7)) +>a : Symbol(a, Decl(objectSpread.ts, 100, 24)) +>b : Symbol(b, Decl(objectSpread.ts, 100, 35)) { ...o, b: 'yeah', ['at the end']: 14 } >o : Symbol(o, Decl(objectSpread.ts, 0, 3)) ->b : Symbol(b, Decl(objectSpread.ts, 83, 15)) ->'at the end' : Symbol(['at the end'], Decl(objectSpread.ts, 83, 26)) +>b : Symbol(b, Decl(objectSpread.ts, 101, 15)) +>'at the end' : Symbol(['at the end'], Decl(objectSpread.ts, 101, 26)) } // shortcut syntax let a = 12; ->a : Symbol(a, Decl(objectSpread.ts, 86, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 104, 3)) let shortCutted: { a: number, b: string } = { ...o, a } ->shortCutted : Symbol(shortCutted, Decl(objectSpread.ts, 87, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 87, 18)) ->b : Symbol(b, Decl(objectSpread.ts, 87, 29)) +>shortCutted : Symbol(shortCutted, Decl(objectSpread.ts, 105, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 105, 18)) +>b : Symbol(b, Decl(objectSpread.ts, 105, 29)) >o : Symbol(o, Decl(objectSpread.ts, 0, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 87, 51)) +>a : Symbol(a, Decl(objectSpread.ts, 105, 51)) // non primitive let spreadNonPrimitive = { ...{}}; ->spreadNonPrimitive : Symbol(spreadNonPrimitive, Decl(objectSpread.ts, 89, 3)) +>spreadNonPrimitive : Symbol(spreadNonPrimitive, Decl(objectSpread.ts, 107, 3)) diff --git a/tests/baselines/reference/objectSpread.types b/tests/baselines/reference/objectSpread.types index d696ed9ac7c..10d8af02440 100644 --- a/tests/baselines/reference/objectSpread.types +++ b/tests/baselines/reference/objectSpread.types @@ -231,8 +231,8 @@ let spreadFunc = { ...(function () { }) }; >function () { } : () => void // boolean && T results in Partial -function conditionalSpread(b: boolean) : { x?: number | undefined, y?: number | undefined } { ->conditionalSpread : (b: boolean) => { x?: number | undefined; y?: number | undefined; } +function conditionalSpreadBoolean(b: boolean) : { x?: number | undefined, y?: number | undefined } { +>conditionalSpreadBoolean : (b: boolean) => { x?: number | undefined; y?: number | undefined; } >b : boolean >x : number | undefined >y : number | undefined @@ -247,6 +247,88 @@ function conditionalSpread(b: boolean) : { x?: number | undefined, y?: number | >y : number >2 : 2 } +function conditionalSpreadNumber(nt: number): { x?: number | undefined, y: number } { +>conditionalSpreadNumber : (nt: number) => { x?: number | undefined; y: number; } +>nt : number +>x : number | undefined +>y : number + + let o = { x: 12, y: 13 } +>o : { x: number; y: number; } +>{ x: 12, y: 13 } : { x: number; y: number; } +>x : number +>12 : 12 +>y : number +>13 : 13 + + o = { +>o = { ...o, ...nt && { x: nt } } : { x: number; y: number; } +>o : { x: number; y: number; } +>{ ...o, ...nt && { x: nt } } : { x: number; y: number; } + + ...o, +>o : { x: number; y: number; } + + ...nt && { x: nt } +>nt && { x: nt } : 0 | { x: number; } +>nt : number +>{ x: nt } : { x: number; } +>x : number +>nt : number + } + let o2 = { ...nt && { x: nt }} +>o2 : { x?: number | undefined; } +>{ ...nt && { x: nt }} : { x?: number | undefined; } +>nt && { x: nt } : 0 | { x: number; } +>nt : number +>{ x: nt } : { x: number; } +>x : number +>nt : number + + return o; +>o : { x: number; y: number; } +} +function conditionalSpreadString(st: string): { x?: string | undefined, y: number } { +>conditionalSpreadString : (st: string) => { x?: string | undefined; y: number; } +>st : string +>x : string | undefined +>y : number + + let o = { x: 'hi', y: 13 } +>o : { x: string; y: number; } +>{ x: 'hi', y: 13 } : { x: string; y: number; } +>x : string +>'hi' : "hi" +>y : number +>13 : 13 + + o = { +>o = { ...o, ...st && { x: st } } : { x: string; y: number; } +>o : { x: string; y: number; } +>{ ...o, ...st && { x: st } } : { x: string; y: number; } + + ...o, +>o : { x: string; y: number; } + + ...st && { x: st } +>st && { x: st } : "" | { x: string; } +>st : string +>{ x: st } : { x: string; } +>x : string +>st : string + } + let o2 = { ...st && { x: st }} +>o2 : { x?: string | undefined; } +>{ ...st && { x: st }} : { x?: string | undefined; } +>st && { x: st } : "" | { x: string; } +>st : string +>{ x: st } : { x: string; } +>x : string +>st : string + + return o; +>o : { x: string; y: number; } +} // other booleans result in { } let spreadBool = { ... true } >spreadBool : {} diff --git a/tests/baselines/reference/objectSpreadNegative.errors.txt b/tests/baselines/reference/objectSpreadNegative.errors.txt index 14eba9d6f2a..305c149841b 100644 --- a/tests/baselines/reference/objectSpreadNegative.errors.txt +++ b/tests/baselines/reference/objectSpreadNegative.errors.txt @@ -7,9 +7,8 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(25,1): error TS2322 Property 's' is missing in type '{ b: boolean; }'. tests/cases/conformance/types/spread/objectSpreadNegative.ts(28,36): error TS2300: Duplicate identifier 'b'. tests/cases/conformance/types/spread/objectSpreadNegative.ts(28,53): error TS2300: Duplicate identifier 'b'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(32,19): error TS2698: Spread types may only be created from object types. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(33,19): error TS2698: Spread types may only be created from object types. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(34,19): error TS2698: Spread types may only be created from object types. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(35,11): error TS2339: Property 'length' does not exist on type '{}'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(36,11): error TS2339: Property 'charAt' does not exist on type '{}'. tests/cases/conformance/types/spread/objectSpreadNegative.ts(39,1): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type '{}' has no compatible call signatures. tests/cases/conformance/types/spread/objectSpreadNegative.ts(43,12): error TS2339: Property 'b' does not exist on type '{}'. tests/cases/conformance/types/spread/objectSpreadNegative.ts(49,9): error TS2339: Property 'm' does not exist on type '{ p: number; }'. @@ -24,7 +23,7 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(80,7): error TS2322 Object literal may only specify known properties, and 'extra' does not exist in type 'A'. -==== tests/cases/conformance/types/spread/objectSpreadNegative.ts (18 errors) ==== +==== tests/cases/conformance/types/spread/objectSpreadNegative.ts (17 errors) ==== let o = { a: 1, b: 'no' } /// private propagates @@ -72,16 +71,14 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(80,7): error TS2322 // primitives are not allowed let spreadNum = { ...12 }; - ~~~~~ -!!! error TS2698: Spread types may only be created from object types. let spreadSum = { ...1 + 1 }; - ~~~~~~~~ -!!! error TS2698: Spread types may only be created from object types. let spreadStr = { ...'foo' }; - ~~~~~~~~ -!!! error TS2698: Spread types may only be created from object types. spreadStr.length; // error, no 'length' + ~~~~~~ +!!! error TS2339: Property 'length' does not exist on type '{}'. spreadStr.charAt(1); // error, no methods either + ~~~~~~ +!!! error TS2339: Property 'charAt' does not exist on type '{}'. // functions are skipped let spreadFunc = { ...function () { } } spreadFunc(); // error, no call signature diff --git a/tests/baselines/reference/objectSpreadNegativeParse.errors.txt b/tests/baselines/reference/objectSpreadNegativeParse.errors.txt index b37200c4f02..41651fb1d1c 100644 --- a/tests/baselines/reference/objectSpreadNegativeParse.errors.txt +++ b/tests/baselines/reference/objectSpreadNegativeParse.errors.txt @@ -1,6 +1,5 @@ tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(1,15): error TS2304: Cannot find name 'o'. tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(1,18): error TS1109: Expression expected. -tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(2,12): error TS2698: Spread types may only be created from object types. tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(2,15): error TS1109: Expression expected. tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(2,16): error TS2304: Cannot find name 'o'. tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(3,15): error TS2304: Cannot find name 'matchMedia'. @@ -10,15 +9,13 @@ tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(4,16): error T tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(4,20): error TS1005: ',' expected. -==== tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts (10 errors) ==== +==== tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts (9 errors) ==== let o7 = { ...o? }; ~ !!! error TS2304: Cannot find name 'o'. ~ !!! error TS1109: Expression expected. let o8 = { ...*o }; - ~~~~~ -!!! error TS2698: Spread types may only be created from object types. ~ !!! error TS1109: Expression expected. ~ diff --git a/tests/cases/conformance/types/spread/objectSpread.ts b/tests/cases/conformance/types/spread/objectSpread.ts index 378c5558fc5..566c9eb0384 100644 --- a/tests/cases/conformance/types/spread/objectSpread.ts +++ b/tests/cases/conformance/types/spread/objectSpread.ts @@ -40,9 +40,27 @@ getter.a = 12; let spreadFunc = { ...(function () { }) }; // boolean && T results in Partial -function conditionalSpread(b: boolean) : { x?: number | undefined, y?: number | undefined } { +function conditionalSpreadBoolean(b: boolean) : { x?: number | undefined, y?: number | undefined } { return { ...b && { x: 1, y: 2 } }; } +function conditionalSpreadNumber(nt: number): { x?: number | undefined, y: number } { + let o = { x: 12, y: 13 } + o = { + ...o, + ...nt && { x: nt } + } + let o2 = { ...nt && { x: nt }} + return o; +} +function conditionalSpreadString(st: string): { x?: string | undefined, y: number } { + let o = { x: 'hi', y: 13 } + o = { + ...o, + ...st && { x: st } + } + let o2 = { ...st && { x: st }} + return o; +} // other booleans result in { } let spreadBool = { ... true } From fbdb14833ad2865bec8a8df173bafbcef04f2910 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Wed, 13 Sep 2017 14:58:35 -0700 Subject: [PATCH 04/10] Improve naming of getPartialTypeFromFalsyUnion --- src/compiler/checker.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ff796879071..e4696363ebb 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7833,7 +7833,7 @@ namespace ts { } if (left.flags & TypeFlags.Union) { // if the union is `false | T` make all the properties of T optional - const wl = getPartialTypeFromFalseUnion(left as UnionType); + const wl = getPartialTypeFromFalsyUnion(left as UnionType); if (wl) { left = wl; } @@ -7842,7 +7842,7 @@ namespace ts { } } if (right.flags & TypeFlags.Union) { - const wr = getPartialTypeFromFalseUnion(right as UnionType); + const wr = getPartialTypeFromFalsyUnion(right as UnionType); if (wr) { right = wr; } @@ -7921,7 +7921,7 @@ namespace ts { return prop.flags & SymbolFlags.Method && find(prop.declarations, decl => isClassLike(decl.parent)); } - function getPartialTypeFromFalseUnion(type: UnionType): Type | undefined { + function getPartialTypeFromFalsyUnion(type: UnionType): Type | undefined { if (type.types.length === 2) { // getFalsyFlagsOfTypes // getTypeFacts From d2e2faad5c9e48af39d2775063e1d599c8083113 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Wed, 13 Sep 2017 15:13:34 -0700 Subject: [PATCH 05/10] Update tests and baselines --- .../reference/objectSpreadNegative.errors.txt | 26 ++++---- .../reference/objectSpreadNegative.js | 8 +-- .../restInvalidArgumentType.errors.txt | 63 +++---------------- .../reference/restInvalidArgumentType.js | 46 +------------- .../spreadInvalidArgumentType.errors.txt | 62 +++--------------- .../reference/spreadInvalidArgumentType.js | 45 +------------ .../cases/compiler/restInvalidArgumentType.ts | 25 +------- .../compiler/spreadInvalidArgumentType.ts | 24 +------ .../types/spread/objectSpreadNegative.ts | 4 +- 9 files changed, 41 insertions(+), 262 deletions(-) diff --git a/tests/baselines/reference/objectSpreadNegative.errors.txt b/tests/baselines/reference/objectSpreadNegative.errors.txt index 305c149841b..39639af545e 100644 --- a/tests/baselines/reference/objectSpreadNegative.errors.txt +++ b/tests/baselines/reference/objectSpreadNegative.errors.txt @@ -7,20 +7,20 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(25,1): error TS2322 Property 's' is missing in type '{ b: boolean; }'. tests/cases/conformance/types/spread/objectSpreadNegative.ts(28,36): error TS2300: Duplicate identifier 'b'. tests/cases/conformance/types/spread/objectSpreadNegative.ts(28,53): error TS2300: Duplicate identifier 'b'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(35,11): error TS2339: Property 'length' does not exist on type '{}'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(36,11): error TS2339: Property 'charAt' does not exist on type '{}'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(39,1): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type '{}' has no compatible call signatures. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(43,12): error TS2339: Property 'b' does not exist on type '{}'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(49,9): error TS2339: Property 'm' does not exist on type '{ p: number; }'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(54,11): error TS2339: Property 'a' does not exist on type '{}'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(58,14): error TS2698: Spread types may only be created from object types. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(61,14): error TS2698: Spread types may only be created from object types. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(75,37): error TS2322: Type '{ a: string; b: string; extra: string; }' is not assignable to type 'A'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(33,11): error TS2339: Property 'length' does not exist on type '{}'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(34,11): error TS2339: Property 'charAt' does not exist on type '{}'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(37,1): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type '{}' has no compatible call signatures. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(41,12): error TS2339: Property 'b' does not exist on type '{}'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(47,9): error TS2339: Property 'm' does not exist on type '{ p: number; }'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(52,11): error TS2339: Property 'a' does not exist on type '{}'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(56,14): error TS2698: Spread types may only be created from object types. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(59,14): error TS2698: Spread types may only be created from object types. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(73,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(76,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(78,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(80,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 (17 errors) ==== @@ -69,9 +69,7 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(80,7): error TS2322 !!! error TS2300: Duplicate identifier 'b'. let duplicatedSpread = { ...o, ...o } - // primitives are not allowed - let spreadNum = { ...12 }; - let spreadSum = { ...1 + 1 }; + // primitives are skipped let spreadStr = { ...'foo' }; spreadStr.length; // error, no 'length' ~~~~~~ diff --git a/tests/baselines/reference/objectSpreadNegative.js b/tests/baselines/reference/objectSpreadNegative.js index 6e82a19acbc..41502dc028d 100644 --- a/tests/baselines/reference/objectSpreadNegative.js +++ b/tests/baselines/reference/objectSpreadNegative.js @@ -29,9 +29,7 @@ spread = b; // error, missing 's' let duplicated = { b: 'bad', ...o, b: 'bad', ...o2, b: 'bad' } let duplicatedSpread = { ...o, ...o } -// primitives are not allowed -let spreadNum = { ...12 }; -let spreadSum = { ...1 + 1 }; +// primitives are skipped let spreadStr = { ...'foo' }; spreadStr.length; // error, no 'length' spreadStr.charAt(1); // error, no methods either @@ -118,9 +116,7 @@ spread = b; // error, missing 's' // literal repeats are not allowed, but spread repeats are fine var duplicated = __assign({ b: 'bad' }, o, { b: 'bad' }, o2, { b: 'bad' }); var duplicatedSpread = __assign({}, o, o); -// primitives are not allowed -var spreadNum = __assign({}, 12); -var spreadSum = __assign({}, 1 + 1); +// primitives are skipped var spreadStr = __assign({}, 'foo'); spreadStr.length; // error, no 'length' spreadStr.charAt(1); // error, no methods either diff --git a/tests/baselines/reference/restInvalidArgumentType.errors.txt b/tests/baselines/reference/restInvalidArgumentType.errors.txt index fff2c7b3563..44577d5a24e 100644 --- a/tests/baselines/reference/restInvalidArgumentType.errors.txt +++ b/tests/baselines/reference/restInvalidArgumentType.errors.txt @@ -1,22 +1,13 @@ -tests/cases/compiler/restInvalidArgumentType.ts(31,13): error TS2700: Rest types may only be created from object types. -tests/cases/compiler/restInvalidArgumentType.ts(33,13): error TS2700: Rest types may only be created from object types. -tests/cases/compiler/restInvalidArgumentType.ts(35,13): error TS2700: Rest types may only be created from object types. -tests/cases/compiler/restInvalidArgumentType.ts(36,13): error TS2700: Rest types may only be created from object types. -tests/cases/compiler/restInvalidArgumentType.ts(38,13): error TS2700: Rest types may only be created from object types. -tests/cases/compiler/restInvalidArgumentType.ts(41,13): error TS2700: Rest types may only be created from object types. -tests/cases/compiler/restInvalidArgumentType.ts(42,13): error TS2700: Rest types may only be created from object types. -tests/cases/compiler/restInvalidArgumentType.ts(44,13): error TS2700: Rest types may only be created from object types. -tests/cases/compiler/restInvalidArgumentType.ts(45,13): error TS2700: Rest types may only be created from object types. -tests/cases/compiler/restInvalidArgumentType.ts(47,13): error TS2700: Rest types may only be created from object types. -tests/cases/compiler/restInvalidArgumentType.ts(48,13): error TS2700: Rest types may only be created from object types. -tests/cases/compiler/restInvalidArgumentType.ts(55,13): error TS2700: Rest types may only be created from object types. -tests/cases/compiler/restInvalidArgumentType.ts(56,13): error TS2700: Rest types may only be created from object types. -tests/cases/compiler/restInvalidArgumentType.ts(58,13): error TS2700: Rest types may only be created from object types. +tests/cases/compiler/restInvalidArgumentType.ts(18,13): error TS2700: Rest types may only be created from object types. +tests/cases/compiler/restInvalidArgumentType.ts(20,13): error TS2700: Rest types may only be created from object types. +tests/cases/compiler/restInvalidArgumentType.ts(22,13): error TS2700: Rest types may only be created from object types. +tests/cases/compiler/restInvalidArgumentType.ts(23,13): error TS2700: Rest types may only be created from object types. +tests/cases/compiler/restInvalidArgumentType.ts(25,13): error TS2700: Rest types may only be created from object types. +tests/cases/compiler/restInvalidArgumentType.ts(28,13): error TS2700: Rest types may only be created from object types. +tests/cases/compiler/restInvalidArgumentType.ts(30,13): error TS2700: Rest types may only be created from object types. -==== tests/cases/compiler/restInvalidArgumentType.ts (14 errors) ==== - enum E { v1, v2 }; - +==== tests/cases/compiler/restInvalidArgumentType.ts (7 errors) ==== function f(p1: T, p2: T[]) { var t: T; @@ -27,24 +18,13 @@ tests/cases/compiler/restInvalidArgumentType.ts(58,13): error TS2700: Rest types var mapped: {[P in "b"]: T[P]}; var union_generic: T | { a: number }; - var union_primitive: { a: number } | number; - var intersection_generic: T & { a: number }; - var intersection_premitive: { a: number } | string; - - var num: number; - var str: number; var u: undefined; var n: null; var a: any; - var literal_string: "string"; - var literal_number: 42; - - var e: E; - var {...r1} = p1; // Error, generic type paramterre ~~ !!! error TS2700: Rest types may only be created from object types. @@ -68,37 +48,14 @@ tests/cases/compiler/restInvalidArgumentType.ts(58,13): error TS2700: Rest types var {...r8} = union_generic; // Error, union with generic type parameter ~~ !!! error TS2700: Rest types may only be created from object types. - var {...r9} = union_primitive; // Error, union with generic type parameter - ~~ -!!! error TS2700: Rest types may only be created from object types. var {...r10} = intersection_generic; // Error, intersection with generic type parameter ~~~ !!! error TS2700: Rest types may only be created from object types. - var {...r11} = intersection_premitive; // Error, intersection with generic type parameter - ~~~ -!!! error TS2700: Rest types may only be created from object types. - - var {...r12} = num; // Error - ~~~ -!!! error TS2700: Rest types may only be created from object types. - var {...r13} = str; // Error - ~~~ -!!! error TS2700: Rest types may only be created from object types. var {...r14} = u; // OK var {...r15} = n; // OK var {...r16} = a; // OK - - var {...r17} = literal_string; // Error - ~~~ -!!! error TS2700: Rest types may only be created from object types. - var {...r18} = literal_number; // Error - ~~~ -!!! error TS2700: Rest types may only be created from object types. - - var {...r19} = e; // Error, enum - ~~~ -!!! error TS2700: Rest types may only be created from object types. - } \ No newline at end of file + } + \ No newline at end of file diff --git a/tests/baselines/reference/restInvalidArgumentType.js b/tests/baselines/reference/restInvalidArgumentType.js index 48e4e11e805..81bcfb63a17 100644 --- a/tests/baselines/reference/restInvalidArgumentType.js +++ b/tests/baselines/reference/restInvalidArgumentType.js @@ -1,6 +1,4 @@ //// [restInvalidArgumentType.ts] -enum E { v1, v2 }; - function f(p1: T, p2: T[]) { var t: T; @@ -11,24 +9,13 @@ function f(p1: T, p2: T[]) { var mapped: {[P in "b"]: T[P]}; var union_generic: T | { a: number }; - var union_primitive: { a: number } | number; - var intersection_generic: T & { a: number }; - var intersection_premitive: { a: number } | string; - - var num: number; - var str: number; var u: undefined; var n: null; var a: any; - var literal_string: "string"; - var literal_number: 42; - - var e: E; - var {...r1} = p1; // Error, generic type paramterre var {...r2} = p2; // OK var {...r3} = t; // Error, generic type paramter @@ -40,24 +27,15 @@ function f(p1: T, p2: T[]) { var {...r7} = mapped; // OK, non-generic mapped type var {...r8} = union_generic; // Error, union with generic type parameter - var {...r9} = union_primitive; // Error, union with generic type parameter var {...r10} = intersection_generic; // Error, intersection with generic type parameter - var {...r11} = intersection_premitive; // Error, intersection with generic type parameter - - var {...r12} = num; // Error - var {...r13} = str; // Error var {...r14} = u; // OK var {...r15} = n; // OK var {...r16} = a; // OK - - var {...r17} = literal_string; // Error - var {...r18} = literal_number; // Error - - var {...r19} = e; // Error, enum -} +} + //// [restInvalidArgumentType.js] var __rest = (this && this.__rest) || function (s, e) { @@ -69,12 +47,6 @@ var __rest = (this && this.__rest) || function (s, e) { t[p[i]] = s[p[i]]; return t; }; -var E; -(function (E) { - E[E["v1"] = 0] = "v1"; - E[E["v2"] = 1] = "v2"; -})(E || (E = {})); -; function f(p1, p2) { var t; var i; @@ -82,17 +54,10 @@ function f(p1, p2) { var mapped_generic; var mapped; var union_generic; - var union_primitive; var intersection_generic; - var intersection_premitive; - var num; - var str; var u; var n; var a; - var literal_string; - var literal_number; - var e; var r1 = __rest(p1, []); // Error, generic type paramterre var r2 = __rest(p2, []); // OK var r3 = __rest(t, []); // Error, generic type paramter @@ -101,15 +66,8 @@ function f(p1, p2) { var r6 = __rest(mapped_generic, []); // Error, generic mapped object type var r7 = __rest(mapped, []); // OK, non-generic mapped type var r8 = __rest(union_generic, []); // Error, union with generic type parameter - var r9 = __rest(union_primitive, []); // Error, union with generic type parameter var r10 = __rest(intersection_generic, []); // Error, intersection with generic type parameter - var r11 = __rest(intersection_premitive, []); // Error, intersection with generic type parameter - var r12 = __rest(num, []); // Error - var r13 = __rest(str, []); // Error var r14 = __rest(u, []); // OK var r15 = __rest(n, []); // OK var r16 = __rest(a, []); // OK - var r17 = __rest(literal_string, []); // Error - var r18 = __rest(literal_number, []); // Error - var r19 = __rest(e, []); // Error, enum } diff --git a/tests/baselines/reference/spreadInvalidArgumentType.errors.txt b/tests/baselines/reference/spreadInvalidArgumentType.errors.txt index 5088390f9ee..5b48e24ad0d 100644 --- a/tests/baselines/reference/spreadInvalidArgumentType.errors.txt +++ b/tests/baselines/reference/spreadInvalidArgumentType.errors.txt @@ -1,22 +1,13 @@ -tests/cases/compiler/spreadInvalidArgumentType.ts(31,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(35,16): error TS2698: Spread types may only be created from object types. -tests/cases/compiler/spreadInvalidArgumentType.ts(36,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(41,16): error TS2698: Spread types may only be created from object types. -tests/cases/compiler/spreadInvalidArgumentType.ts(42,16): 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. -tests/cases/compiler/spreadInvalidArgumentType.ts(47,17): error TS2698: Spread types may only be created from object types. -tests/cases/compiler/spreadInvalidArgumentType.ts(48,17): error TS2698: Spread types may only be created from object types. -tests/cases/compiler/spreadInvalidArgumentType.ts(55,17): error TS2698: Spread types may only be created from object types. -tests/cases/compiler/spreadInvalidArgumentType.ts(56,17): error TS2698: Spread types may only be created from object types. -tests/cases/compiler/spreadInvalidArgumentType.ts(58,17): error TS2698: Spread types may only be created from object types. +tests/cases/compiler/spreadInvalidArgumentType.ts(19,16): error TS2698: Spread types may only be created from object types. +tests/cases/compiler/spreadInvalidArgumentType.ts(21,16): error TS2698: Spread types may only be created from object types. +tests/cases/compiler/spreadInvalidArgumentType.ts(23,16): error TS2698: Spread types may only be created from object types. +tests/cases/compiler/spreadInvalidArgumentType.ts(24,16): error TS2698: Spread types may only be created from object types. +tests/cases/compiler/spreadInvalidArgumentType.ts(26,16): error TS2698: Spread types may only be created from object types. +tests/cases/compiler/spreadInvalidArgumentType.ts(29,16): error TS2698: Spread types may only be created from object types. +tests/cases/compiler/spreadInvalidArgumentType.ts(31,17): error TS2698: Spread types may only be created from object types. -==== tests/cases/compiler/spreadInvalidArgumentType.ts (14 errors) ==== - enum E { v1, v2 }; - +==== tests/cases/compiler/spreadInvalidArgumentType.ts (7 errors) ==== function f(p1: T, p2: T[]) { var t: T; @@ -27,24 +18,14 @@ tests/cases/compiler/spreadInvalidArgumentType.ts(58,17): error TS2698: Spread t var mapped: {[P in "b"]: T[P]}; var union_generic: T | { a: number }; - var union_primitive: { a: number } | number; var intersection_generic: T & { a: number }; - var intersection_premitive: { a: number } | string; - - var num: number; - var str: number; var u: undefined; var n: null; var a: any; - var literal_string: "string"; - var literal_number: 42; - - var e: E; - var o1 = { ...p1 }; // Error, generic type paramterre ~~~~~ !!! error TS2698: Spread types may only be created from object types. @@ -68,37 +49,14 @@ tests/cases/compiler/spreadInvalidArgumentType.ts(58,17): error TS2698: Spread t var o8 = { ...union_generic }; // Error, union with generic type parameter ~~~~~~~~~~~~~~~~ !!! error TS2698: Spread types may only be created from object types. - 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 o11 = { ...intersection_premitive }; // Error, intersection with generic type parameter - ~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2698: Spread types may only be created from object types. - - var o12 = { ...num }; // Error - ~~~~~~ -!!! error TS2698: Spread types may only be created from object types. - var o13 = { ...str }; // Error - ~~~~~~ -!!! error TS2698: Spread types may only be created from object types. var o14 = { ...u }; // OK var o15 = { ...n }; // OK var o16 = { ...a }; // OK - - var o17 = { ...literal_string }; // Error - ~~~~~~~~~~~~~~~~~ -!!! error TS2698: Spread types may only be created from object types. - var o18 = { ...literal_number }; // Error - ~~~~~~~~~~~~~~~~~ -!!! error TS2698: Spread types may only be created from object types. - - var o19 = { ...e }; // Error, enum - ~~~~ -!!! error TS2698: Spread types may only be created from object types. - } \ No newline at end of file + } + \ No newline at end of file diff --git a/tests/baselines/reference/spreadInvalidArgumentType.js b/tests/baselines/reference/spreadInvalidArgumentType.js index 26f958f224d..aa42419e59a 100644 --- a/tests/baselines/reference/spreadInvalidArgumentType.js +++ b/tests/baselines/reference/spreadInvalidArgumentType.js @@ -1,6 +1,4 @@ //// [spreadInvalidArgumentType.ts] -enum E { v1, v2 }; - function f(p1: T, p2: T[]) { var t: T; @@ -11,24 +9,14 @@ function f(p1: T, p2: T[]) { var mapped: {[P in "b"]: T[P]}; var union_generic: T | { a: number }; - var union_primitive: { a: number } | number; var intersection_generic: T & { a: number }; - var intersection_premitive: { a: number } | string; - - var num: number; - var str: number; var u: undefined; var n: null; var a: any; - var literal_string: "string"; - var literal_number: 42; - - var e: E; - var o1 = { ...p1 }; // Error, generic type paramterre var o2 = { ...p2 }; // OK var o3 = { ...t }; // Error, generic type paramter @@ -40,24 +28,15 @@ function f(p1: T, p2: T[]) { var o7 = { ...mapped }; // OK, non-generic mapped type var o8 = { ...union_generic }; // Error, 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 o11 = { ...intersection_premitive }; // Error, intersection with generic type parameter - - var o12 = { ...num }; // Error - var o13 = { ...str }; // Error var o14 = { ...u }; // OK var o15 = { ...n }; // OK var o16 = { ...a }; // OK - - var o17 = { ...literal_string }; // Error - var o18 = { ...literal_number }; // Error - - var o19 = { ...e }; // Error, enum -} +} + //// [spreadInvalidArgumentType.js] var __assign = (this && this.__assign) || Object.assign || function(t) { @@ -68,12 +47,6 @@ var __assign = (this && this.__assign) || Object.assign || function(t) { } return t; }; -var E; -(function (E) { - E[E["v1"] = 0] = "v1"; - E[E["v2"] = 1] = "v2"; -})(E || (E = {})); -; function f(p1, p2) { var t; var i; @@ -81,17 +54,10 @@ function f(p1, p2) { var mapped_generic; var mapped; var union_generic; - var union_primitive; var intersection_generic; - var intersection_premitive; - var num; - var str; var u; var n; var a; - var literal_string; - var literal_number; - var e; var o1 = __assign({}, p1); // Error, generic type paramterre var o2 = __assign({}, p2); // OK var o3 = __assign({}, t); // Error, generic type paramter @@ -100,15 +66,8 @@ function f(p1, p2) { var o6 = __assign({}, mapped_generic); // Error, 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 o9 = __assign({}, union_primitive); // Error, union with generic type parameter var o10 = __assign({}, intersection_generic); // Error, intersection with generic type parameter - var o11 = __assign({}, intersection_premitive); // Error, intersection with generic type parameter - var o12 = __assign({}, num); // Error - var o13 = __assign({}, str); // Error var o14 = __assign({}, u); // OK var o15 = __assign({}, n); // OK var o16 = __assign({}, a); // OK - var o17 = __assign({}, literal_string); // Error - var o18 = __assign({}, literal_number); // Error - var o19 = __assign({}, e); // Error, enum } diff --git a/tests/cases/compiler/restInvalidArgumentType.ts b/tests/cases/compiler/restInvalidArgumentType.ts index 488f546e231..2d50903328f 100644 --- a/tests/cases/compiler/restInvalidArgumentType.ts +++ b/tests/cases/compiler/restInvalidArgumentType.ts @@ -1,5 +1,3 @@ -enum E { v1, v2 }; - function f(p1: T, p2: T[]) { var t: T; @@ -10,24 +8,13 @@ function f(p1: T, p2: T[]) { var mapped: {[P in "b"]: T[P]}; var union_generic: T | { a: number }; - var union_primitive: { a: number } | number; - var intersection_generic: T & { a: number }; - var intersection_premitive: { a: number } | string; - - var num: number; - var str: number; var u: undefined; var n: null; var a: any; - var literal_string: "string"; - var literal_number: 42; - - var e: E; - var {...r1} = p1; // Error, generic type paramterre var {...r2} = p2; // OK var {...r3} = t; // Error, generic type paramter @@ -39,21 +26,11 @@ function f(p1: T, p2: T[]) { var {...r7} = mapped; // OK, non-generic mapped type var {...r8} = union_generic; // Error, union with generic type parameter - var {...r9} = union_primitive; // Error, union with generic type parameter var {...r10} = intersection_generic; // Error, intersection with generic type parameter - var {...r11} = intersection_premitive; // Error, intersection with generic type parameter - - var {...r12} = num; // Error - var {...r13} = str; // Error var {...r14} = u; // OK var {...r15} = n; // OK var {...r16} = a; // OK - - var {...r17} = literal_string; // Error - var {...r18} = literal_number; // Error - - var {...r19} = e; // Error, enum -} \ No newline at end of file +} diff --git a/tests/cases/compiler/spreadInvalidArgumentType.ts b/tests/cases/compiler/spreadInvalidArgumentType.ts index 2ac6aa921f4..bf7365e8ab0 100644 --- a/tests/cases/compiler/spreadInvalidArgumentType.ts +++ b/tests/cases/compiler/spreadInvalidArgumentType.ts @@ -1,5 +1,3 @@ -enum E { v1, v2 }; - function f(p1: T, p2: T[]) { var t: T; @@ -10,24 +8,14 @@ function f(p1: T, p2: T[]) { var mapped: {[P in "b"]: T[P]}; var union_generic: T | { a: number }; - var union_primitive: { a: number } | number; var intersection_generic: T & { a: number }; - var intersection_premitive: { a: number } | string; - - var num: number; - var str: number; var u: undefined; var n: null; var a: any; - var literal_string: "string"; - var literal_number: 42; - - var e: E; - var o1 = { ...p1 }; // Error, generic type paramterre var o2 = { ...p2 }; // OK var o3 = { ...t }; // Error, generic type paramter @@ -39,21 +27,11 @@ function f(p1: T, p2: T[]) { var o7 = { ...mapped }; // OK, non-generic mapped type var o8 = { ...union_generic }; // Error, 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 o11 = { ...intersection_premitive }; // Error, intersection with generic type parameter - - var o12 = { ...num }; // Error - var o13 = { ...str }; // Error var o14 = { ...u }; // OK var o15 = { ...n }; // OK var o16 = { ...a }; // OK - - var o17 = { ...literal_string }; // Error - var o18 = { ...literal_number }; // Error - - var o19 = { ...e }; // Error, enum -} \ No newline at end of file +} diff --git a/tests/cases/conformance/types/spread/objectSpreadNegative.ts b/tests/cases/conformance/types/spread/objectSpreadNegative.ts index beb9ff265b4..8fe9174f759 100644 --- a/tests/cases/conformance/types/spread/objectSpreadNegative.ts +++ b/tests/cases/conformance/types/spread/objectSpreadNegative.ts @@ -29,9 +29,7 @@ spread = b; // error, missing 's' let duplicated = { b: 'bad', ...o, b: 'bad', ...o2, b: 'bad' } let duplicatedSpread = { ...o, ...o } -// primitives are not allowed -let spreadNum = { ...12 }; -let spreadSum = { ...1 + 1 }; +// primitives are skipped let spreadStr = { ...'foo' }; spreadStr.length; // error, no 'length' spreadStr.charAt(1); // error, no methods either From 18653a5c5d31e08973520bcbf65d81872ac56923 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Thu, 14 Sep 2017 11:18:48 -0700 Subject: [PATCH 06/10] Use removeDefinitelyFalsyTypes for building partial type --- src/compiler/checker.ts | 13 ++-- tests/baselines/reference/spreadUnion2.js | 10 +-- .../baselines/reference/spreadUnion2.symbols | 24 ++++--- tests/baselines/reference/spreadUnion2.types | 66 +++++++++---------- .../reference/spreadUnion3.errors.txt | 12 ++-- .../conformance/types/spread/spreadUnion2.ts | 10 +-- 6 files changed, 63 insertions(+), 72 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c8b0100a02e..a7c98f657dc 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7923,15 +7923,10 @@ namespace ts { function getPartialTypeFromFalsyUnion(type: UnionType): Type | undefined { if (type.types.length === 2) { - // getFalsyFlagsOfTypes - // getTypeFacts - const i = Math.max(type.types.indexOf(falseType), - type.types.indexOf(zeroType), - type.types.indexOf(emptyStringType)); - if (i > -1) { + const truthy = removeDefinitelyFalsyTypes(type); + if (truthy !== type) { const members = createSymbolTable(); - const other = type.types[i === 0 ? 1 : 0]; - for (const prop of getPropertiesOfType(other)) { + for (const prop of getPropertiesOfType(truthy)) { if (prop.flags & SymbolFlags.Optional) { members.set(prop.escapedName, prop); } @@ -7943,7 +7938,7 @@ namespace ts { members.set(prop.escapedName, result); } } - return createAnonymousType(undefined, members, emptyArray, emptyArray, getIndexInfoOfType(other, IndexKind.String), getIndexInfoOfType(other, IndexKind.Number)); + return createAnonymousType(undefined, members, emptyArray, emptyArray, getIndexInfoOfType(truthy, IndexKind.String), getIndexInfoOfType(truthy, IndexKind.Number)); } } } diff --git a/tests/baselines/reference/spreadUnion2.js b/tests/baselines/reference/spreadUnion2.js index 6e49770617a..48b12731817 100644 --- a/tests/baselines/reference/spreadUnion2.js +++ b/tests/baselines/reference/spreadUnion2.js @@ -3,20 +3,20 @@ declare const undefinedUnion: { a: number } | undefined; declare const nullUnion: { b: number } | null; declare const nullAndUndefinedUnion: null | undefined; -var o1: {} | { a: number }; +var o1: { a?: number | undefined }; var o1 = { ...undefinedUnion }; -var o2: {} | { b: number }; +var o2: { b?: number | undefined }; var o2 = { ...nullUnion }; -var o3: {} | { b: number } | { a: number } | { a: number, b: number }; +var o3: { a?: number | undefined, b?: number | undefined }; var o3 = { ...undefinedUnion, ...nullUnion }; var o3 = { ...nullUnion, ...undefinedUnion }; -var o4: {} | { a: number }; +var o4: { a?: number | undefined }; var o4 = { ...undefinedUnion, ...undefinedUnion }; -var o5: {} | { b: number }; +var o5: { b?: number | undefined }; var o5 = { ...nullUnion, ...nullUnion }; var o6 = { ...nullAndUndefinedUnion, ...nullAndUndefinedUnion }; diff --git a/tests/baselines/reference/spreadUnion2.symbols b/tests/baselines/reference/spreadUnion2.symbols index c4d1f19b6d9..841bce12e42 100644 --- a/tests/baselines/reference/spreadUnion2.symbols +++ b/tests/baselines/reference/spreadUnion2.symbols @@ -10,28 +10,26 @@ declare const nullUnion: { b: number } | null; declare const nullAndUndefinedUnion: null | undefined; >nullAndUndefinedUnion : Symbol(nullAndUndefinedUnion, Decl(spreadUnion2.ts, 2, 13)) -var o1: {} | { a: number }; +var o1: { a?: number | undefined }; >o1 : Symbol(o1, Decl(spreadUnion2.ts, 4, 3), Decl(spreadUnion2.ts, 5, 3)) ->a : Symbol(a, Decl(spreadUnion2.ts, 4, 14)) +>a : Symbol(a, Decl(spreadUnion2.ts, 4, 9)) var o1 = { ...undefinedUnion }; >o1 : Symbol(o1, Decl(spreadUnion2.ts, 4, 3), Decl(spreadUnion2.ts, 5, 3)) >undefinedUnion : Symbol(undefinedUnion, Decl(spreadUnion2.ts, 0, 13)) -var o2: {} | { b: number }; +var o2: { b?: number | undefined }; >o2 : Symbol(o2, Decl(spreadUnion2.ts, 7, 3), Decl(spreadUnion2.ts, 8, 3)) ->b : Symbol(b, Decl(spreadUnion2.ts, 7, 14)) +>b : Symbol(b, Decl(spreadUnion2.ts, 7, 9)) var o2 = { ...nullUnion }; >o2 : Symbol(o2, Decl(spreadUnion2.ts, 7, 3), Decl(spreadUnion2.ts, 8, 3)) >nullUnion : Symbol(nullUnion, Decl(spreadUnion2.ts, 1, 13)) -var o3: {} | { b: number } | { a: number } | { a: number, b: number }; +var o3: { a?: number | undefined, b?: number | undefined }; >o3 : Symbol(o3, Decl(spreadUnion2.ts, 10, 3), Decl(spreadUnion2.ts, 11, 3), Decl(spreadUnion2.ts, 12, 3)) ->b : Symbol(b, Decl(spreadUnion2.ts, 10, 14)) ->a : Symbol(a, Decl(spreadUnion2.ts, 10, 30)) ->a : Symbol(a, Decl(spreadUnion2.ts, 10, 46)) ->b : Symbol(b, Decl(spreadUnion2.ts, 10, 57)) +>a : Symbol(a, Decl(spreadUnion2.ts, 10, 9)) +>b : Symbol(b, Decl(spreadUnion2.ts, 10, 33)) var o3 = { ...undefinedUnion, ...nullUnion }; >o3 : Symbol(o3, Decl(spreadUnion2.ts, 10, 3), Decl(spreadUnion2.ts, 11, 3), Decl(spreadUnion2.ts, 12, 3)) @@ -43,18 +41,18 @@ var o3 = { ...nullUnion, ...undefinedUnion }; >nullUnion : Symbol(nullUnion, Decl(spreadUnion2.ts, 1, 13)) >undefinedUnion : Symbol(undefinedUnion, Decl(spreadUnion2.ts, 0, 13)) -var o4: {} | { a: number }; +var o4: { a?: number | undefined }; >o4 : Symbol(o4, Decl(spreadUnion2.ts, 14, 3), Decl(spreadUnion2.ts, 15, 3)) ->a : Symbol(a, Decl(spreadUnion2.ts, 14, 14)) +>a : Symbol(a, Decl(spreadUnion2.ts, 14, 9)) var o4 = { ...undefinedUnion, ...undefinedUnion }; >o4 : Symbol(o4, Decl(spreadUnion2.ts, 14, 3), Decl(spreadUnion2.ts, 15, 3)) >undefinedUnion : Symbol(undefinedUnion, Decl(spreadUnion2.ts, 0, 13)) >undefinedUnion : Symbol(undefinedUnion, Decl(spreadUnion2.ts, 0, 13)) -var o5: {} | { b: number }; +var o5: { b?: number | undefined }; >o5 : Symbol(o5, Decl(spreadUnion2.ts, 17, 3), Decl(spreadUnion2.ts, 18, 3)) ->b : Symbol(b, Decl(spreadUnion2.ts, 17, 14)) +>b : Symbol(b, Decl(spreadUnion2.ts, 17, 9)) var o5 = { ...nullUnion, ...nullUnion }; >o5 : Symbol(o5, Decl(spreadUnion2.ts, 17, 3), Decl(spreadUnion2.ts, 18, 3)) diff --git a/tests/baselines/reference/spreadUnion2.types b/tests/baselines/reference/spreadUnion2.types index ea3364f296b..50f79cc7745 100644 --- a/tests/baselines/reference/spreadUnion2.types +++ b/tests/baselines/reference/spreadUnion2.types @@ -12,71 +12,69 @@ declare const nullAndUndefinedUnion: null | undefined; >nullAndUndefinedUnion : null | undefined >null : null -var o1: {} | { a: number }; ->o1 : {} | { a: number; } ->a : number +var o1: { a?: number | undefined }; +>o1 : { a?: number | undefined; } +>a : number | undefined var o1 = { ...undefinedUnion }; ->o1 : {} | { a: number; } ->{ ...undefinedUnion } : {} | { a: number; } +>o1 : { a?: number | undefined; } +>{ ...undefinedUnion } : { a?: number | undefined; } >undefinedUnion : { a: number; } | undefined -var o2: {} | { b: number }; ->o2 : {} | { b: number; } ->b : number +var o2: { b?: number | undefined }; +>o2 : { b?: number | undefined; } +>b : number | undefined var o2 = { ...nullUnion }; ->o2 : {} | { b: number; } ->{ ...nullUnion } : {} | { b: number; } +>o2 : { b?: number | undefined; } +>{ ...nullUnion } : { b?: number | undefined; } >nullUnion : { b: number; } | null -var o3: {} | { b: number } | { a: number } | { a: number, b: number }; ->o3 : {} | { b: number; } | { a: number; } | { a: number; b: number; } ->b : number ->a : number ->a : number ->b : number +var o3: { a?: number | undefined, b?: number | undefined }; +>o3 : { a?: number | undefined; b?: number | undefined; } +>a : number | undefined +>b : number | undefined var o3 = { ...undefinedUnion, ...nullUnion }; ->o3 : {} | { b: number; } | { a: number; } | { a: number; b: number; } ->{ ...undefinedUnion, ...nullUnion } : {} | { b: number; } | { a: number; } | { b: number; a: number; } +>o3 : { a?: number | undefined; b?: number | undefined; } +>{ ...undefinedUnion, ...nullUnion } : { b?: number | undefined; a?: number | undefined; } >undefinedUnion : { a: number; } | undefined >nullUnion : { b: number; } | null var o3 = { ...nullUnion, ...undefinedUnion }; ->o3 : {} | { b: number; } | { a: number; } | { a: number; b: number; } ->{ ...nullUnion, ...undefinedUnion } : {} | { a: number; } | { b: number; } | { a: number; b: number; } +>o3 : { a?: number | undefined; b?: number | undefined; } +>{ ...nullUnion, ...undefinedUnion } : { a?: number | undefined; b?: number | undefined; } >nullUnion : { b: number; } | null >undefinedUnion : { a: number; } | undefined -var o4: {} | { a: number }; ->o4 : {} | { a: number; } ->a : number +var o4: { a?: number | undefined }; +>o4 : { a?: number | undefined; } +>a : number | undefined var o4 = { ...undefinedUnion, ...undefinedUnion }; ->o4 : {} | { a: number; } ->{ ...undefinedUnion, ...undefinedUnion } : {} | { a: number; } | { a: number; } | { a: number; } +>o4 : { a?: number | undefined; } +>{ ...undefinedUnion, ...undefinedUnion } : { a?: number | undefined; } >undefinedUnion : { a: number; } | undefined >undefinedUnion : { a: number; } | undefined -var o5: {} | { b: number }; ->o5 : {} | { b: number; } ->b : number +var o5: { b?: number | undefined }; +>o5 : { b?: number | undefined; } +>b : number | undefined var o5 = { ...nullUnion, ...nullUnion }; ->o5 : {} | { b: number; } ->{ ...nullUnion, ...nullUnion } : {} | { b: number; } | { b: number; } | { b: number; } +>o5 : { b?: number | undefined; } +>{ ...nullUnion, ...nullUnion } : { b?: number | undefined; } >nullUnion : { b: number; } | null >nullUnion : { b: number; } | null var o6 = { ...nullAndUndefinedUnion, ...nullAndUndefinedUnion }; ->o6 : {} | {} | {} | {} ->{ ...nullAndUndefinedUnion, ...nullAndUndefinedUnion } : {} | {} | {} | {} +>o6 : {} +>{ ...nullAndUndefinedUnion, ...nullAndUndefinedUnion } : {} >nullAndUndefinedUnion : null | undefined >nullAndUndefinedUnion : null | undefined var o7 = { ...nullAndUndefinedUnion }; ->o7 : {} | {} ->{ ...nullAndUndefinedUnion } : {} | {} +>o7 : {} +>{ ...nullAndUndefinedUnion } : {} >nullAndUndefinedUnion : null | undefined diff --git a/tests/baselines/reference/spreadUnion3.errors.txt b/tests/baselines/reference/spreadUnion3.errors.txt index 5f5b620685c..f3fa2da7597 100644 --- a/tests/baselines/reference/spreadUnion3.errors.txt +++ b/tests/baselines/reference/spreadUnion3.errors.txt @@ -1,6 +1,6 @@ -tests/cases/conformance/types/spread/spreadUnion3.ts(2,5): error TS2322: Type '{ y: number; } | { y: string; }' is not assignable to type '{ y: string; }'. - Type '{ y: number; }' is not assignable to type '{ y: string; }'. - Types of property 'y' are incompatible. +tests/cases/conformance/types/spread/spreadUnion3.ts(2,5): error TS2322: Type '{ y: string | number; }' is not assignable to type '{ y: string; }'. + Types of property 'y' are incompatible. + Type 'string | number' is not assignable to type 'string'. Type 'number' is not assignable to type 'string'. tests/cases/conformance/types/spread/spreadUnion3.ts(9,23): error TS2339: Property 'a' does not exist on type '{} | {} | { a: number; }'. Property 'a' does not exist on type '{}'. @@ -10,9 +10,9 @@ tests/cases/conformance/types/spread/spreadUnion3.ts(9,23): error TS2339: Proper function f(x: { y: string } | undefined): { y: string } { return { y: 123, ...x } // y: string | number ~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2322: Type '{ y: number; } | { y: string; }' is not assignable to type '{ y: string; }'. -!!! error TS2322: Type '{ y: number; }' is not assignable to type '{ y: string; }'. -!!! error TS2322: Types of property 'y' are incompatible. +!!! error TS2322: Type '{ y: string | number; }' is not assignable to type '{ y: string; }'. +!!! error TS2322: Types of property 'y' are incompatible. +!!! error TS2322: Type 'string | number' is not assignable to type 'string'. !!! error TS2322: Type 'number' is not assignable to type 'string'. } f(undefined) diff --git a/tests/cases/conformance/types/spread/spreadUnion2.ts b/tests/cases/conformance/types/spread/spreadUnion2.ts index e2f72879915..17abdd4006a 100644 --- a/tests/cases/conformance/types/spread/spreadUnion2.ts +++ b/tests/cases/conformance/types/spread/spreadUnion2.ts @@ -4,20 +4,20 @@ declare const undefinedUnion: { a: number } | undefined; declare const nullUnion: { b: number } | null; declare const nullAndUndefinedUnion: null | undefined; -var o1: {} | { a: number }; +var o1: { a?: number | undefined }; var o1 = { ...undefinedUnion }; -var o2: {} | { b: number }; +var o2: { b?: number | undefined }; var o2 = { ...nullUnion }; -var o3: {} | { b: number } | { a: number } | { a: number, b: number }; +var o3: { a?: number | undefined, b?: number | undefined }; var o3 = { ...undefinedUnion, ...nullUnion }; var o3 = { ...nullUnion, ...undefinedUnion }; -var o4: {} | { a: number }; +var o4: { a?: number | undefined }; var o4 = { ...undefinedUnion, ...undefinedUnion }; -var o5: {} | { b: number }; +var o5: { b?: number | undefined }; var o5 = { ...nullUnion, ...nullUnion }; var o6 = { ...nullAndUndefinedUnion, ...nullAndUndefinedUnion }; From 9c6f65175b281438fe5ac935262bb4e3ba5f3c73 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Fri, 15 Sep 2017 10:05:14 -0700 Subject: [PATCH 07/10] Refactor truthy-spread-union creation for performance Only create properties once, only if needed, and don't create an intermediate anonymous type. The code is also inlined with the rest of `getSpreadType`. --- src/compiler/checker.ts | 62 +++++++++++++++-------------------------- 1 file changed, 23 insertions(+), 39 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index a7c98f657dc..2dbf8b9253f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7822,6 +7822,7 @@ namespace ts { * and right = the new element to be spread. */ function getSpreadType(left: Type, right: Type): Type { + let truthyRight: Type; if (left.flags & TypeFlags.Any || right.flags & TypeFlags.Any) { return anyType; } @@ -7832,25 +7833,18 @@ namespace ts { return left; } if (left.flags & TypeFlags.Union) { - // if the union is `false | T` make all the properties of T optional - const wl = getPartialTypeFromFalsyUnion(left as UnionType); - if (wl) { - left = wl; - } - else { - return mapType(left, t => getSpreadType(t, right)); - } + return mapType(left, t => getSpreadType(t, right)); } if (right.flags & TypeFlags.Union) { - const wr = getPartialTypeFromFalsyUnion(right as UnionType); - if (wr) { - right = wr; - } - else { + truthyRight = getTruthyTypeFromFalsyUnion(right as UnionType); + if (!truthyRight || truthyRight.flags & TypeFlags.Union) { return mapType(right, t => getSpreadType(left, t)); } + else { + right = truthyRight; + } } - if (right.flags & (TypeFlags.NonPrimitive | TypeFlags.BooleanLike | TypeFlags.NumberLike | TypeFlags.StringLike)) { + if (right.flags & (TypeFlags.NonPrimitive | TypeFlags.BooleanLike | TypeFlags.NumberLike | TypeFlags.StringLike | TypeFlags.EnumLike)) { return emptyObjectType; } @@ -7875,9 +7869,10 @@ namespace ts { skippedPrivateMembers.set(rightProp.escapedName, true); } else if (!isClassMethod(rightProp) && !isSetterWithoutGetter) { - members.set(rightProp.escapedName, getNonReadonlySymbol(rightProp)); + members.set(rightProp.escapedName, getSymbolOfSpreadProperty(rightProp, !!truthyRight)); } } + for (const leftProp of getPropertiesOfType(left)) { if (leftProp.flags & SymbolFlags.SetAccessor && !(leftProp.flags & SymbolFlags.GetAccessor) || skippedPrivateMembers.has(leftProp.escapedName) @@ -7899,19 +7894,22 @@ namespace ts { } } else { - members.set(leftProp.escapedName, getNonReadonlySymbol(leftProp)); + members.set(leftProp.escapedName, getSymbolOfSpreadProperty(leftProp, /*makeOptional*/ false)); } } return createAnonymousType(undefined, members, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo); } - function getNonReadonlySymbol(prop: Symbol) { - if (!isReadonlySymbol(prop)) { + function getSymbolOfSpreadProperty(prop: Symbol, makeOptional: boolean) { + if (!isReadonlySymbol(prop) && (!makeOptional || prop.flags & SymbolFlags.Optional)) { return prop; } - const flags = SymbolFlags.Property | (prop.flags & SymbolFlags.Optional); + const flags = SymbolFlags.Property | (makeOptional ? SymbolFlags.Optional : prop.flags & SymbolFlags.Optional); const result = createSymbol(flags, prop.escapedName); result.type = getTypeOfSymbol(prop); + if (makeOptional) { + result.type = getUnionType([result.type, undefinedType]); + } result.declarations = prop.declarations; result.syntheticOrigin = prop; return result; @@ -7921,25 +7919,10 @@ namespace ts { return prop.flags & SymbolFlags.Method && find(prop.declarations, decl => isClassLike(decl.parent)); } - function getPartialTypeFromFalsyUnion(type: UnionType): Type | undefined { - if (type.types.length === 2) { - const truthy = removeDefinitelyFalsyTypes(type); - if (truthy !== type) { - const members = createSymbolTable(); - for (const prop of getPropertiesOfType(truthy)) { - if (prop.flags & SymbolFlags.Optional) { - members.set(prop.escapedName, prop); - } - else { - const result = createSymbol(prop.flags | SymbolFlags.Optional, prop.escapedName); - result.type = getUnionType([getTypeOfSymbol(prop), undefinedType]); - result.declarations = prop.declarations; - result.syntheticOrigin = prop; - members.set(prop.escapedName, result); - } - } - return createAnonymousType(undefined, members, emptyArray, emptyArray, getIndexInfoOfType(truthy, IndexKind.String), getIndexInfoOfType(truthy, IndexKind.Number)); - } + function getTruthyTypeFromFalsyUnion(type: UnionType): Type | undefined { + const truthy = removeDefinitelyFalsyTypes(type); + if (truthy !== type) { + return truthy; } } @@ -13784,7 +13767,8 @@ namespace ts { } function isValidSpreadType(type: Type): boolean { - return !!(type.flags & (TypeFlags.Any | TypeFlags.PossiblyFalsy | TypeFlags.NonPrimitive) || + return !!(type.flags & (TypeFlags.Any | TypeFlags.NonPrimitive) || + getFalsyFlags(type) & TypeFlags.DefinitelyFalsy && isValidSpreadType(removeDefinitelyFalsyTypes(type)) || type.flags & TypeFlags.Object && !isGenericMappedType(type) || type.flags & TypeFlags.UnionOrIntersection && !forEach((type).types, t => !isValidSpreadType(t))); } From f97d5fa11d594762b4863d297a72ec4d038e4e99 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Fri, 15 Sep 2017 10:06:58 -0700 Subject: [PATCH 08/10] Update tests with improved spread-falsy-union rules --- tests/baselines/reference/objectSpread.js | 42 ++- .../baselines/reference/objectSpread.symbols | 299 ++++++++++-------- tests/baselines/reference/objectSpread.types | 114 +++++-- .../reference/objectSpreadNegative.errors.txt | 49 ++- .../reference/objectSpreadNegative.js | 16 +- .../objectSpreadNegativeParse.errors.txt | 5 +- .../restInvalidArgumentType.errors.txt | 65 +++- .../reference/restInvalidArgumentType.js | 48 ++- tests/baselines/reference/restUnion2.js | 14 +- tests/baselines/reference/restUnion2.symbols | 25 -- tests/baselines/reference/restUnion2.types | 27 -- .../baselines/reference/restUnion3.errors.txt | 17 + tests/baselines/reference/restUnion3.js | 25 ++ .../spreadInvalidArgumentType.errors.txt | 72 ++++- .../reference/spreadInvalidArgumentType.js | 53 +++- tests/baselines/reference/spreadUnion2.js | 5 - .../baselines/reference/spreadUnion2.symbols | 45 +-- tests/baselines/reference/spreadUnion2.types | 14 - .../reference/spreadUnion3.errors.txt | 23 +- tests/baselines/reference/spreadUnion3.js | 7 + .../cases/compiler/restInvalidArgumentType.ts | 24 +- tests/cases/compiler/restUnion2.ts | 9 - tests/cases/compiler/restUnion3.ts | 8 + .../compiler/spreadInvalidArgumentType.ts | 29 +- .../conformance/types/spread/objectSpread.ts | 28 +- .../types/spread/objectSpreadNegative.ts | 8 +- .../conformance/types/spread/spreadUnion2.ts | 3 - .../conformance/types/spread/spreadUnion3.ts | 5 + 28 files changed, 707 insertions(+), 372 deletions(-) create mode 100644 tests/baselines/reference/restUnion3.errors.txt create mode 100644 tests/baselines/reference/restUnion3.js create mode 100644 tests/cases/compiler/restUnion3.ts diff --git a/tests/baselines/reference/objectSpread.js b/tests/baselines/reference/objectSpread.js index 7eab2da265f..eea39c8e773 100644 --- a/tests/baselines/reference/objectSpread.js +++ b/tests/baselines/reference/objectSpread.js @@ -38,12 +38,26 @@ getter.a = 12; // functions result in { } let spreadFunc = { ...(function () { }) }; -// boolean && T results in Partial -function conditionalSpreadBoolean(b: boolean) : { x?: number | undefined, y?: number | undefined } { - return { ...b && { x: 1, y: 2 } }; +type Header = { head: string, body: string, authToken: string } +function from16326(this: { header: Header }, header: Header, authToken: string): Header { + return { + ...this.header, + ...header, + ...authToken && { authToken } + } } -function conditionalSpreadNumber(nt: number): { x?: number | undefined, y: number } { +// boolean && T results in Partial +function conditionalSpreadBoolean(b: boolean) : { x: number, y: number } { let o = { x: 12, y: 13 } + o = { + ...o, + ...b && { x: 14 } + } + let o2 = { ...b && { x: 21 }} + return o; +} +function conditionalSpreadNumber(nt: number): { x: number, y: number } { + let o = { x: 15, y: 16 } o = { ...o, ...nt && { x: nt } @@ -51,8 +65,8 @@ function conditionalSpreadNumber(nt: number): { x?: number | undefined, y: numbe let o2 = { ...nt && { x: nt }} return o; } -function conditionalSpreadString(st: string): { x?: string | undefined, y: number } { - let o = { x: 'hi', y: 13 } +function conditionalSpreadString(st: string): { x: string, y: number } { + let o = { x: 'hi', y: 17 } o = { ...o, ...st && { x: st } @@ -60,8 +74,6 @@ function conditionalSpreadString(st: string): { x?: string | undefined, y: numbe let o2 = { ...st && { x: st }} return o; } -// other booleans result in { } -let spreadBool = { ... true } // any results in any let anything: any; @@ -141,24 +153,28 @@ var getter = __assign({}, op, { c: 7 }); getter.a = 12; // functions result in { } var spreadFunc = __assign({}, (function () { })); +function from16326(header, authToken) { + return __assign({}, this.header, header, authToken && { authToken: authToken }); +} // boolean && T results in Partial function conditionalSpreadBoolean(b) { - return __assign({}, b && { x: 1, y: 2 }); + var o = { x: 12, y: 13 }; + o = __assign({}, o, b && { x: 14 }); + var o2 = __assign({}, b && { x: 21 }); + return o; } function conditionalSpreadNumber(nt) { - var o = { x: 12, y: 13 }; + var o = { x: 15, y: 16 }; o = __assign({}, o, nt && { x: nt }); var o2 = __assign({}, nt && { x: nt }); return o; } function conditionalSpreadString(st) { - var o = { x: 'hi', y: 13 }; + var o = { x: 'hi', y: 17 }; o = __assign({}, o, st && { x: st }); var o2 = __assign({}, st && { x: st }); return o; } -// other booleans result in { } -var spreadBool = __assign({}, true); // any results in any var anything; var spreadAny = __assign({}, anything); diff --git a/tests/baselines/reference/objectSpread.symbols b/tests/baselines/reference/objectSpread.symbols index 9f257870a0b..0cb15d4ea7a 100644 --- a/tests/baselines/reference/objectSpread.symbols +++ b/tests/baselines/reference/objectSpread.symbols @@ -169,144 +169,189 @@ getter.a = 12; let spreadFunc = { ...(function () { }) }; >spreadFunc : Symbol(spreadFunc, Decl(objectSpread.ts, 37, 3)) -// boolean && T results in Partial -function conditionalSpreadBoolean(b: boolean) : { x?: number | undefined, y?: number | undefined } { ->conditionalSpreadBoolean : Symbol(conditionalSpreadBoolean, Decl(objectSpread.ts, 37, 42)) ->b : Symbol(b, Decl(objectSpread.ts, 40, 34)) ->x : Symbol(x, Decl(objectSpread.ts, 40, 49)) ->y : Symbol(y, Decl(objectSpread.ts, 40, 73)) +type Header = { head: string, body: string, authToken: string } +>Header : Symbol(Header, Decl(objectSpread.ts, 37, 42)) +>head : Symbol(head, Decl(objectSpread.ts, 39, 15)) +>body : Symbol(body, Decl(objectSpread.ts, 39, 29)) +>authToken : Symbol(authToken, Decl(objectSpread.ts, 39, 43)) - return { ...b && { x: 1, y: 2 } }; ->b : Symbol(b, Decl(objectSpread.ts, 40, 34)) ->x : Symbol(x, Decl(objectSpread.ts, 41, 22)) ->y : Symbol(y, Decl(objectSpread.ts, 41, 28)) +function from16326(this: { header: Header }, header: Header, authToken: string): Header { +>from16326 : Symbol(from16326, Decl(objectSpread.ts, 39, 63)) +>this : Symbol(this, Decl(objectSpread.ts, 40, 19)) +>header : Symbol(header, Decl(objectSpread.ts, 40, 26)) +>Header : Symbol(Header, Decl(objectSpread.ts, 37, 42)) +>header : Symbol(header, Decl(objectSpread.ts, 40, 44)) +>Header : Symbol(Header, Decl(objectSpread.ts, 37, 42)) +>authToken : Symbol(authToken, Decl(objectSpread.ts, 40, 60)) +>Header : Symbol(Header, Decl(objectSpread.ts, 37, 42)) + + return { + ...this.header, +>this.header : Symbol(header, Decl(objectSpread.ts, 40, 26)) +>this : Symbol(this, Decl(objectSpread.ts, 40, 19)) +>header : Symbol(header, Decl(objectSpread.ts, 40, 26)) + + ...header, +>header : Symbol(header, Decl(objectSpread.ts, 40, 44)) + + ...authToken && { authToken } +>authToken : Symbol(authToken, Decl(objectSpread.ts, 40, 60)) +>authToken : Symbol(authToken, Decl(objectSpread.ts, 44, 25)) + } } -function conditionalSpreadNumber(nt: number): { x?: number | undefined, y: number } { ->conditionalSpreadNumber : Symbol(conditionalSpreadNumber, Decl(objectSpread.ts, 42, 1)) ->nt : Symbol(nt, Decl(objectSpread.ts, 43, 33)) ->x : Symbol(x, Decl(objectSpread.ts, 43, 47)) ->y : Symbol(y, Decl(objectSpread.ts, 43, 71)) +// boolean && T results in Partial +function conditionalSpreadBoolean(b: boolean) : { x: number, y: number } { +>conditionalSpreadBoolean : Symbol(conditionalSpreadBoolean, Decl(objectSpread.ts, 46, 1)) +>b : Symbol(b, Decl(objectSpread.ts, 48, 34)) +>x : Symbol(x, Decl(objectSpread.ts, 48, 49)) +>y : Symbol(y, Decl(objectSpread.ts, 48, 60)) let o = { x: 12, y: 13 } ->o : Symbol(o, Decl(objectSpread.ts, 44, 7)) ->x : Symbol(x, Decl(objectSpread.ts, 44, 13)) ->y : Symbol(y, Decl(objectSpread.ts, 44, 20)) +>o : Symbol(o, Decl(objectSpread.ts, 49, 7)) +>x : Symbol(x, Decl(objectSpread.ts, 49, 13)) +>y : Symbol(y, Decl(objectSpread.ts, 49, 20)) o = { ->o : Symbol(o, Decl(objectSpread.ts, 44, 7)) +>o : Symbol(o, Decl(objectSpread.ts, 49, 7)) ...o, ->o : Symbol(o, Decl(objectSpread.ts, 44, 7)) +>o : Symbol(o, Decl(objectSpread.ts, 49, 7)) + + ...b && { x: 14 } +>b : Symbol(b, Decl(objectSpread.ts, 48, 34)) +>x : Symbol(x, Decl(objectSpread.ts, 52, 17)) + } + let o2 = { ...b && { x: 21 }} +>o2 : Symbol(o2, Decl(objectSpread.ts, 54, 7)) +>b : Symbol(b, Decl(objectSpread.ts, 48, 34)) +>x : Symbol(x, Decl(objectSpread.ts, 54, 24)) + + return o; +>o : Symbol(o, Decl(objectSpread.ts, 49, 7)) +} +function conditionalSpreadNumber(nt: number): { x: number, y: number } { +>conditionalSpreadNumber : Symbol(conditionalSpreadNumber, Decl(objectSpread.ts, 56, 1)) +>nt : Symbol(nt, Decl(objectSpread.ts, 57, 33)) +>x : Symbol(x, Decl(objectSpread.ts, 57, 47)) +>y : Symbol(y, Decl(objectSpread.ts, 57, 58)) + + let o = { x: 15, y: 16 } +>o : Symbol(o, Decl(objectSpread.ts, 58, 7)) +>x : Symbol(x, Decl(objectSpread.ts, 58, 13)) +>y : Symbol(y, Decl(objectSpread.ts, 58, 20)) + + o = { +>o : Symbol(o, Decl(objectSpread.ts, 58, 7)) + + ...o, +>o : Symbol(o, Decl(objectSpread.ts, 58, 7)) ...nt && { x: nt } ->nt : Symbol(nt, Decl(objectSpread.ts, 43, 33)) ->x : Symbol(x, Decl(objectSpread.ts, 47, 18)) ->nt : Symbol(nt, Decl(objectSpread.ts, 43, 33)) +>nt : Symbol(nt, Decl(objectSpread.ts, 57, 33)) +>x : Symbol(x, Decl(objectSpread.ts, 61, 18)) +>nt : Symbol(nt, Decl(objectSpread.ts, 57, 33)) } let o2 = { ...nt && { x: nt }} ->o2 : Symbol(o2, Decl(objectSpread.ts, 49, 7)) ->nt : Symbol(nt, Decl(objectSpread.ts, 43, 33)) ->x : Symbol(x, Decl(objectSpread.ts, 49, 25)) ->nt : Symbol(nt, Decl(objectSpread.ts, 43, 33)) +>o2 : Symbol(o2, Decl(objectSpread.ts, 63, 7)) +>nt : Symbol(nt, Decl(objectSpread.ts, 57, 33)) +>x : Symbol(x, Decl(objectSpread.ts, 63, 25)) +>nt : Symbol(nt, Decl(objectSpread.ts, 57, 33)) return o; ->o : Symbol(o, Decl(objectSpread.ts, 44, 7)) +>o : Symbol(o, Decl(objectSpread.ts, 58, 7)) } -function conditionalSpreadString(st: string): { x?: string | undefined, y: number } { ->conditionalSpreadString : Symbol(conditionalSpreadString, Decl(objectSpread.ts, 51, 1)) ->st : Symbol(st, Decl(objectSpread.ts, 52, 33)) ->x : Symbol(x, Decl(objectSpread.ts, 52, 47)) ->y : Symbol(y, Decl(objectSpread.ts, 52, 71)) +function conditionalSpreadString(st: string): { x: string, y: number } { +>conditionalSpreadString : Symbol(conditionalSpreadString, Decl(objectSpread.ts, 65, 1)) +>st : Symbol(st, Decl(objectSpread.ts, 66, 33)) +>x : Symbol(x, Decl(objectSpread.ts, 66, 47)) +>y : Symbol(y, Decl(objectSpread.ts, 66, 58)) - let o = { x: 'hi', y: 13 } ->o : Symbol(o, Decl(objectSpread.ts, 53, 7)) ->x : Symbol(x, Decl(objectSpread.ts, 53, 13)) ->y : Symbol(y, Decl(objectSpread.ts, 53, 22)) + let o = { x: 'hi', y: 17 } +>o : Symbol(o, Decl(objectSpread.ts, 67, 7)) +>x : Symbol(x, Decl(objectSpread.ts, 67, 13)) +>y : Symbol(y, Decl(objectSpread.ts, 67, 22)) o = { ->o : Symbol(o, Decl(objectSpread.ts, 53, 7)) +>o : Symbol(o, Decl(objectSpread.ts, 67, 7)) ...o, ->o : Symbol(o, Decl(objectSpread.ts, 53, 7)) +>o : Symbol(o, Decl(objectSpread.ts, 67, 7)) ...st && { x: st } ->st : Symbol(st, Decl(objectSpread.ts, 52, 33)) ->x : Symbol(x, Decl(objectSpread.ts, 56, 18)) ->st : Symbol(st, Decl(objectSpread.ts, 52, 33)) +>st : Symbol(st, Decl(objectSpread.ts, 66, 33)) +>x : Symbol(x, Decl(objectSpread.ts, 70, 18)) +>st : Symbol(st, Decl(objectSpread.ts, 66, 33)) } let o2 = { ...st && { x: st }} ->o2 : Symbol(o2, Decl(objectSpread.ts, 58, 7)) ->st : Symbol(st, Decl(objectSpread.ts, 52, 33)) ->x : Symbol(x, Decl(objectSpread.ts, 58, 25)) ->st : Symbol(st, Decl(objectSpread.ts, 52, 33)) +>o2 : Symbol(o2, Decl(objectSpread.ts, 72, 7)) +>st : Symbol(st, Decl(objectSpread.ts, 66, 33)) +>x : Symbol(x, Decl(objectSpread.ts, 72, 25)) +>st : Symbol(st, Decl(objectSpread.ts, 66, 33)) return o; ->o : Symbol(o, Decl(objectSpread.ts, 53, 7)) +>o : Symbol(o, Decl(objectSpread.ts, 67, 7)) } -// other booleans result in { } -let spreadBool = { ... true } ->spreadBool : Symbol(spreadBool, Decl(objectSpread.ts, 62, 3)) // any results in any let anything: any; ->anything : Symbol(anything, Decl(objectSpread.ts, 65, 3)) +>anything : Symbol(anything, Decl(objectSpread.ts, 77, 3)) let spreadAny = { ...anything }; ->spreadAny : Symbol(spreadAny, Decl(objectSpread.ts, 66, 3)) ->anything : Symbol(anything, Decl(objectSpread.ts, 65, 3)) +>spreadAny : Symbol(spreadAny, Decl(objectSpread.ts, 78, 3)) +>anything : Symbol(anything, Decl(objectSpread.ts, 77, 3)) // methods are not enumerable class C { p = 1; m() { } } ->C : Symbol(C, Decl(objectSpread.ts, 66, 32)) ->p : Symbol(C.p, Decl(objectSpread.ts, 69, 9)) ->m : Symbol(C.m, Decl(objectSpread.ts, 69, 16)) +>C : Symbol(C, Decl(objectSpread.ts, 78, 32)) +>p : Symbol(C.p, Decl(objectSpread.ts, 81, 9)) +>m : Symbol(C.m, Decl(objectSpread.ts, 81, 16)) let c: C = new C() ->c : Symbol(c, Decl(objectSpread.ts, 70, 3)) ->C : Symbol(C, Decl(objectSpread.ts, 66, 32)) ->C : Symbol(C, Decl(objectSpread.ts, 66, 32)) +>c : Symbol(c, Decl(objectSpread.ts, 82, 3)) +>C : Symbol(C, Decl(objectSpread.ts, 78, 32)) +>C : Symbol(C, Decl(objectSpread.ts, 78, 32)) let spreadC: { p: number } = { ...c } ->spreadC : Symbol(spreadC, Decl(objectSpread.ts, 71, 3)) ->p : Symbol(p, Decl(objectSpread.ts, 71, 14)) ->c : Symbol(c, Decl(objectSpread.ts, 70, 3)) +>spreadC : Symbol(spreadC, Decl(objectSpread.ts, 83, 3)) +>p : Symbol(p, Decl(objectSpread.ts, 83, 14)) +>c : Symbol(c, Decl(objectSpread.ts, 82, 3)) // own methods are enumerable let cplus: { p: number, plus(): void } = { ...c, plus() { return this.p + 1; } }; ->cplus : Symbol(cplus, Decl(objectSpread.ts, 74, 3)) ->p : Symbol(p, Decl(objectSpread.ts, 74, 12)) ->plus : Symbol(plus, Decl(objectSpread.ts, 74, 23)) ->c : Symbol(c, Decl(objectSpread.ts, 70, 3)) ->plus : Symbol(plus, Decl(objectSpread.ts, 74, 48)) +>cplus : Symbol(cplus, Decl(objectSpread.ts, 86, 3)) +>p : Symbol(p, Decl(objectSpread.ts, 86, 12)) +>plus : Symbol(plus, Decl(objectSpread.ts, 86, 23)) +>c : Symbol(c, Decl(objectSpread.ts, 82, 3)) +>plus : Symbol(plus, Decl(objectSpread.ts, 86, 48)) cplus.plus(); ->cplus.plus : Symbol(plus, Decl(objectSpread.ts, 74, 23)) ->cplus : Symbol(cplus, Decl(objectSpread.ts, 74, 3)) ->plus : Symbol(plus, Decl(objectSpread.ts, 74, 23)) +>cplus.plus : Symbol(plus, Decl(objectSpread.ts, 86, 23)) +>cplus : Symbol(cplus, Decl(objectSpread.ts, 86, 3)) +>plus : Symbol(plus, Decl(objectSpread.ts, 86, 23)) // new field's type conflicting with existing field is OK let changeTypeAfter: { a: string, b: string } = ->changeTypeAfter : Symbol(changeTypeAfter, Decl(objectSpread.ts, 78, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 78, 22)) ->b : Symbol(b, Decl(objectSpread.ts, 78, 33)) +>changeTypeAfter : Symbol(changeTypeAfter, Decl(objectSpread.ts, 90, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 90, 22)) +>b : Symbol(b, Decl(objectSpread.ts, 90, 33)) { ...o, a: 'wrong type?' } >o : Symbol(o, Decl(objectSpread.ts, 0, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 79, 11)) +>a : Symbol(a, Decl(objectSpread.ts, 91, 11)) let changeTypeBefore: { a: number, b: string } = ->changeTypeBefore : Symbol(changeTypeBefore, Decl(objectSpread.ts, 80, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 80, 23)) ->b : Symbol(b, Decl(objectSpread.ts, 80, 34)) +>changeTypeBefore : Symbol(changeTypeBefore, Decl(objectSpread.ts, 92, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 92, 23)) +>b : Symbol(b, Decl(objectSpread.ts, 92, 34)) { a: 'wrong type?', ...o }; ->a : Symbol(a, Decl(objectSpread.ts, 81, 5)) +>a : Symbol(a, Decl(objectSpread.ts, 93, 5)) >o : Symbol(o, Decl(objectSpread.ts, 0, 3)) let changeTypeBoth: { a: string, b: number } = ->changeTypeBoth : Symbol(changeTypeBoth, Decl(objectSpread.ts, 82, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 82, 21)) ->b : Symbol(b, Decl(objectSpread.ts, 82, 32)) +>changeTypeBoth : Symbol(changeTypeBoth, Decl(objectSpread.ts, 94, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 94, 21)) +>b : Symbol(b, Decl(objectSpread.ts, 94, 32)) { ...o, ...swap }; >o : Symbol(o, Decl(objectSpread.ts, 0, 3)) @@ -314,90 +359,90 @@ let changeTypeBoth: { a: string, b: number } = // optional function container( ->container : Symbol(container, Decl(objectSpread.ts, 83, 22)) +>container : Symbol(container, Decl(objectSpread.ts, 95, 22)) definiteBoolean: { sn: boolean }, ->definiteBoolean : Symbol(definiteBoolean, Decl(objectSpread.ts, 86, 19)) ->sn : Symbol(sn, Decl(objectSpread.ts, 87, 22)) +>definiteBoolean : Symbol(definiteBoolean, Decl(objectSpread.ts, 98, 19)) +>sn : Symbol(sn, Decl(objectSpread.ts, 99, 22)) definiteString: { sn: string }, ->definiteString : Symbol(definiteString, Decl(objectSpread.ts, 87, 37)) ->sn : Symbol(sn, Decl(objectSpread.ts, 88, 21)) +>definiteString : Symbol(definiteString, Decl(objectSpread.ts, 99, 37)) +>sn : Symbol(sn, Decl(objectSpread.ts, 100, 21)) optionalString: { sn?: string }, ->optionalString : Symbol(optionalString, Decl(objectSpread.ts, 88, 35)) ->sn : Symbol(sn, Decl(objectSpread.ts, 89, 21)) +>optionalString : Symbol(optionalString, Decl(objectSpread.ts, 100, 35)) +>sn : Symbol(sn, Decl(objectSpread.ts, 101, 21)) optionalNumber: { sn?: number }) { ->optionalNumber : Symbol(optionalNumber, Decl(objectSpread.ts, 89, 36)) ->sn : Symbol(sn, Decl(objectSpread.ts, 90, 21)) +>optionalNumber : Symbol(optionalNumber, Decl(objectSpread.ts, 101, 36)) +>sn : Symbol(sn, Decl(objectSpread.ts, 102, 21)) let optionalUnionStops: { sn: string | number | boolean } = { ...definiteBoolean, ...definiteString, ...optionalNumber }; ->optionalUnionStops : Symbol(optionalUnionStops, Decl(objectSpread.ts, 91, 7)) ->sn : Symbol(sn, Decl(objectSpread.ts, 91, 29)) ->definiteBoolean : Symbol(definiteBoolean, Decl(objectSpread.ts, 86, 19)) ->definiteString : Symbol(definiteString, Decl(objectSpread.ts, 87, 37)) ->optionalNumber : Symbol(optionalNumber, Decl(objectSpread.ts, 89, 36)) +>optionalUnionStops : Symbol(optionalUnionStops, Decl(objectSpread.ts, 103, 7)) +>sn : Symbol(sn, Decl(objectSpread.ts, 103, 29)) +>definiteBoolean : Symbol(definiteBoolean, Decl(objectSpread.ts, 98, 19)) +>definiteString : Symbol(definiteString, Decl(objectSpread.ts, 99, 37)) +>optionalNumber : Symbol(optionalNumber, Decl(objectSpread.ts, 101, 36)) let optionalUnionDuplicates: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...optionalString, ...optionalNumber }; ->optionalUnionDuplicates : Symbol(optionalUnionDuplicates, Decl(objectSpread.ts, 92, 7)) ->sn : Symbol(sn, Decl(objectSpread.ts, 92, 34)) ->definiteBoolean : Symbol(definiteBoolean, Decl(objectSpread.ts, 86, 19)) ->definiteString : Symbol(definiteString, Decl(objectSpread.ts, 87, 37)) ->optionalString : Symbol(optionalString, Decl(objectSpread.ts, 88, 35)) ->optionalNumber : Symbol(optionalNumber, Decl(objectSpread.ts, 89, 36)) +>optionalUnionDuplicates : Symbol(optionalUnionDuplicates, Decl(objectSpread.ts, 104, 7)) +>sn : Symbol(sn, Decl(objectSpread.ts, 104, 34)) +>definiteBoolean : Symbol(definiteBoolean, Decl(objectSpread.ts, 98, 19)) +>definiteString : Symbol(definiteString, Decl(objectSpread.ts, 99, 37)) +>optionalString : Symbol(optionalString, Decl(objectSpread.ts, 100, 35)) +>optionalNumber : Symbol(optionalNumber, Decl(objectSpread.ts, 101, 36)) let allOptional: { sn?: string | number } = { ...optionalString, ...optionalNumber }; ->allOptional : Symbol(allOptional, Decl(objectSpread.ts, 93, 7)) ->sn : Symbol(sn, Decl(objectSpread.ts, 93, 22)) ->optionalString : Symbol(optionalString, Decl(objectSpread.ts, 88, 35)) ->optionalNumber : Symbol(optionalNumber, Decl(objectSpread.ts, 89, 36)) +>allOptional : Symbol(allOptional, Decl(objectSpread.ts, 105, 7)) +>sn : Symbol(sn, Decl(objectSpread.ts, 105, 22)) +>optionalString : Symbol(optionalString, Decl(objectSpread.ts, 100, 35)) +>optionalNumber : Symbol(optionalNumber, Decl(objectSpread.ts, 101, 36)) // computed property let computedFirst: { a: number, b: string, "before everything": number } = ->computedFirst : Symbol(computedFirst, Decl(objectSpread.ts, 96, 7)) ->a : Symbol(a, Decl(objectSpread.ts, 96, 24)) ->b : Symbol(b, Decl(objectSpread.ts, 96, 35)) +>computedFirst : Symbol(computedFirst, Decl(objectSpread.ts, 108, 7)) +>a : Symbol(a, Decl(objectSpread.ts, 108, 24)) +>b : Symbol(b, Decl(objectSpread.ts, 108, 35)) { ['before everything']: 12, ...o, b: 'yes' } ->'before everything' : Symbol(['before everything'], Decl(objectSpread.ts, 97, 9)) +>'before everything' : Symbol(['before everything'], Decl(objectSpread.ts, 109, 9)) >o : Symbol(o, Decl(objectSpread.ts, 0, 3)) ->b : Symbol(b, Decl(objectSpread.ts, 97, 42)) +>b : Symbol(b, Decl(objectSpread.ts, 109, 42)) let computedMiddle: { a: number, b: string, c: boolean, "in the middle": number } = ->computedMiddle : Symbol(computedMiddle, Decl(objectSpread.ts, 98, 7)) ->a : Symbol(a, Decl(objectSpread.ts, 98, 25)) ->b : Symbol(b, Decl(objectSpread.ts, 98, 36)) ->c : Symbol(c, Decl(objectSpread.ts, 98, 47)) +>computedMiddle : Symbol(computedMiddle, Decl(objectSpread.ts, 110, 7)) +>a : Symbol(a, Decl(objectSpread.ts, 110, 25)) +>b : Symbol(b, Decl(objectSpread.ts, 110, 36)) +>c : Symbol(c, Decl(objectSpread.ts, 110, 47)) { ...o, ['in the middle']: 13, b: 'maybe?', ...o2 } >o : Symbol(o, Decl(objectSpread.ts, 0, 3)) ->'in the middle' : Symbol(['in the middle'], Decl(objectSpread.ts, 99, 15)) ->b : Symbol(b, Decl(objectSpread.ts, 99, 38)) +>'in the middle' : Symbol(['in the middle'], Decl(objectSpread.ts, 111, 15)) +>b : Symbol(b, Decl(objectSpread.ts, 111, 38)) >o2 : Symbol(o2, Decl(objectSpread.ts, 1, 3)) let computedAfter: { a: number, b: string, "at the end": number } = ->computedAfter : Symbol(computedAfter, Decl(objectSpread.ts, 100, 7)) ->a : Symbol(a, Decl(objectSpread.ts, 100, 24)) ->b : Symbol(b, Decl(objectSpread.ts, 100, 35)) +>computedAfter : Symbol(computedAfter, Decl(objectSpread.ts, 112, 7)) +>a : Symbol(a, Decl(objectSpread.ts, 112, 24)) +>b : Symbol(b, Decl(objectSpread.ts, 112, 35)) { ...o, b: 'yeah', ['at the end']: 14 } >o : Symbol(o, Decl(objectSpread.ts, 0, 3)) ->b : Symbol(b, Decl(objectSpread.ts, 101, 15)) ->'at the end' : Symbol(['at the end'], Decl(objectSpread.ts, 101, 26)) +>b : Symbol(b, Decl(objectSpread.ts, 113, 15)) +>'at the end' : Symbol(['at the end'], Decl(objectSpread.ts, 113, 26)) } // shortcut syntax let a = 12; ->a : Symbol(a, Decl(objectSpread.ts, 104, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 116, 3)) let shortCutted: { a: number, b: string } = { ...o, a } ->shortCutted : Symbol(shortCutted, Decl(objectSpread.ts, 105, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 105, 18)) ->b : Symbol(b, Decl(objectSpread.ts, 105, 29)) +>shortCutted : Symbol(shortCutted, Decl(objectSpread.ts, 117, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 117, 18)) +>b : Symbol(b, Decl(objectSpread.ts, 117, 29)) >o : Symbol(o, Decl(objectSpread.ts, 0, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 105, 51)) +>a : Symbol(a, Decl(objectSpread.ts, 117, 51)) // non primitive let spreadNonPrimitive = { ...{}}; ->spreadNonPrimitive : Symbol(spreadNonPrimitive, Decl(objectSpread.ts, 107, 3)) +>spreadNonPrimitive : Symbol(spreadNonPrimitive, Decl(objectSpread.ts, 119, 3)) diff --git a/tests/baselines/reference/objectSpread.types b/tests/baselines/reference/objectSpread.types index 10d8af02440..da24a558d51 100644 --- a/tests/baselines/reference/objectSpread.types +++ b/tests/baselines/reference/objectSpread.types @@ -230,27 +230,45 @@ let spreadFunc = { ...(function () { }) }; >(function () { }) : () => void >function () { } : () => void -// boolean && T results in Partial -function conditionalSpreadBoolean(b: boolean) : { x?: number | undefined, y?: number | undefined } { ->conditionalSpreadBoolean : (b: boolean) => { x?: number | undefined; y?: number | undefined; } ->b : boolean ->x : number | undefined ->y : number | undefined +type Header = { head: string, body: string, authToken: string } +>Header : Header +>head : string +>body : string +>authToken : string - return { ...b && { x: 1, y: 2 } }; ->{ ...b && { x: 1, y: 2 } } : { x?: number | undefined; y?: number | undefined; } ->b && { x: 1, y: 2 } : false | { x: number; y: number; } ->b : boolean ->{ x: 1, y: 2 } : { x: number; y: number; } ->x : number ->1 : 1 ->y : number ->2 : 2 +function from16326(this: { header: Header }, header: Header, authToken: string): Header { +>from16326 : (this: { header: Header; }, header: Header, authToken: string) => Header +>this : { header: Header; } +>header : Header +>Header : Header +>header : Header +>Header : Header +>authToken : string +>Header : Header + + return { +>{ ...this.header, ...header, ...authToken && { authToken } } : { authToken: string; head: string; body: string; } + + ...this.header, +>this.header : Header +>this : { header: Header; } +>header : Header + + ...header, +>header : Header + + ...authToken && { authToken } +>authToken && { authToken } : "" | { authToken: string; } +>authToken : string +>{ authToken } : { authToken: string; } +>authToken : string + } } -function conditionalSpreadNumber(nt: number): { x?: number | undefined, y: number } { ->conditionalSpreadNumber : (nt: number) => { x?: number | undefined; y: number; } ->nt : number ->x : number | undefined +// boolean && T results in Partial +function conditionalSpreadBoolean(b: boolean) : { x: number, y: number } { +>conditionalSpreadBoolean : (b: boolean) => { x: number; y: number; } +>b : boolean +>x : number >y : number let o = { x: 12, y: 13 } @@ -261,6 +279,47 @@ function conditionalSpreadNumber(nt: number): { x?: number | undefined, y: numbe >y : number >13 : 13 + o = { +>o = { ...o, ...b && { x: 14 } } : { x: number; y: number; } +>o : { x: number; y: number; } +>{ ...o, ...b && { x: 14 } } : { x: number; y: number; } + + ...o, +>o : { x: number; y: number; } + + ...b && { x: 14 } +>b && { x: 14 } : false | { x: number; } +>b : boolean +>{ x: 14 } : { x: number; } +>x : number +>14 : 14 + } + let o2 = { ...b && { x: 21 }} +>o2 : { x?: number | undefined; } +>{ ...b && { x: 21 }} : { x?: number | undefined; } +>b && { x: 21 } : false | { x: number; } +>b : boolean +>{ x: 21 } : { x: number; } +>x : number +>21 : 21 + + return o; +>o : { x: number; y: number; } +} +function conditionalSpreadNumber(nt: number): { x: number, y: number } { +>conditionalSpreadNumber : (nt: number) => { x: number; y: number; } +>nt : number +>x : number +>y : number + + let o = { x: 15, y: 16 } +>o : { x: number; y: number; } +>{ x: 15, y: 16 } : { x: number; y: number; } +>x : number +>15 : 15 +>y : number +>16 : 16 + o = { >o = { ...o, ...nt && { x: nt } } : { x: number; y: number; } >o : { x: number; y: number; } @@ -288,19 +347,19 @@ function conditionalSpreadNumber(nt: number): { x?: number | undefined, y: numbe return o; >o : { x: number; y: number; } } -function conditionalSpreadString(st: string): { x?: string | undefined, y: number } { ->conditionalSpreadString : (st: string) => { x?: string | undefined; y: number; } +function conditionalSpreadString(st: string): { x: string, y: number } { +>conditionalSpreadString : (st: string) => { x: string; y: number; } >st : string ->x : string | undefined +>x : string >y : number - let o = { x: 'hi', y: 13 } + let o = { x: 'hi', y: 17 } >o : { x: string; y: number; } ->{ x: 'hi', y: 13 } : { x: string; y: number; } +>{ x: 'hi', y: 17 } : { x: string; y: number; } >x : string >'hi' : "hi" >y : number ->13 : 13 +>17 : 17 o = { >o = { ...o, ...st && { x: st } } : { x: string; y: number; } @@ -329,11 +388,6 @@ function conditionalSpreadString(st: string): { x?: string | undefined, y: numbe return o; >o : { x: string; y: number; } } -// other booleans result in { } -let spreadBool = { ... true } ->spreadBool : {} ->{ ... true } : {} ->true : true // any results in any let anything: any; diff --git a/tests/baselines/reference/objectSpreadNegative.errors.txt b/tests/baselines/reference/objectSpreadNegative.errors.txt index 39639af545e..92225755c71 100644 --- a/tests/baselines/reference/objectSpreadNegative.errors.txt +++ b/tests/baselines/reference/objectSpreadNegative.errors.txt @@ -7,23 +7,26 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(25,1): error TS2322 Property 's' is missing in type '{ b: boolean; }'. tests/cases/conformance/types/spread/objectSpreadNegative.ts(28,36): error TS2300: Duplicate identifier 'b'. tests/cases/conformance/types/spread/objectSpreadNegative.ts(28,53): error TS2300: Duplicate identifier 'b'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(33,11): error TS2339: Property 'length' does not exist on type '{}'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(34,11): error TS2339: Property 'charAt' does not exist on type '{}'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(37,1): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type '{}' has no compatible call signatures. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(41,12): error TS2339: Property 'b' does not exist on type '{}'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(47,9): error TS2339: Property 'm' does not exist on type '{ p: number; }'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(52,11): error TS2339: Property 'a' does not exist on type '{}'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(56,14): error TS2698: Spread types may only be created from object types. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(59,14): error TS2698: Spread types may only be created from object types. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(73,37): error TS2322: Type '{ a: string; b: string; extra: string; }' is not assignable to type 'A'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(32,19): error TS2698: Spread types may only be created from object types. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(33,19): error TS2698: Spread types may only be created from object types. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(34,20): error TS2698: Spread types may only be created from object types. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(36,20): error TS2698: Spread types may only be created from object types. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(38,19): error TS2698: Spread types may only be created from object types. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(43,1): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type '{}' has no compatible call signatures. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(47,12): error TS2339: Property 'b' does not exist on type '{}'. +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(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(76,7): error TS2322: Type '{ a: string; b: string; extra: string; }' is not assignable to 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(78,7): error TS2322: Type '{ a: string; b: string; extra: string; }' is not assignable to 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 (17 errors) ==== +==== tests/cases/conformance/types/spread/objectSpreadNegative.ts (20 errors) ==== let o = { a: 1, b: 'no' } /// private propagates @@ -69,14 +72,26 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(78,7): error TS2322 !!! error TS2300: Duplicate identifier 'b'. let duplicatedSpread = { ...o, ...o } - // primitives are skipped + // primitives are not allowed, except for falsy ones + let spreadNum = { ...12 }; + ~~~~~ +!!! error TS2698: Spread types may only be created from object types. + let spreadSum = { ...1 + 1 }; + ~~~~~~~~ +!!! error TS2698: Spread types may only be created from object types. + let spreadZero = { ...0 }; + ~~~~ +!!! error TS2698: Spread types may only be created from object types. + spreadZero.toFixed(); // error, no methods even from a falsy number + let spreadBool = { ...true }; + ~~~~~~~ +!!! error TS2698: Spread types may only be created from object types. + spreadBool.valueOf(); let spreadStr = { ...'foo' }; + ~~~~~~~~ +!!! error TS2698: Spread types may only be created from object types. spreadStr.length; // error, no 'length' - ~~~~~~ -!!! error TS2339: Property 'length' does not exist on type '{}'. spreadStr.charAt(1); // error, no methods either - ~~~~~~ -!!! error TS2339: Property 'charAt' does not exist on type '{}'. // functions are skipped let spreadFunc = { ...function () { } } spreadFunc(); // error, no call signature diff --git a/tests/baselines/reference/objectSpreadNegative.js b/tests/baselines/reference/objectSpreadNegative.js index 41502dc028d..7e6720b9b16 100644 --- a/tests/baselines/reference/objectSpreadNegative.js +++ b/tests/baselines/reference/objectSpreadNegative.js @@ -29,7 +29,13 @@ spread = b; // error, missing 's' let duplicated = { b: 'bad', ...o, b: 'bad', ...o2, b: 'bad' } let duplicatedSpread = { ...o, ...o } -// primitives are skipped +// primitives are not allowed, except for falsy ones +let spreadNum = { ...12 }; +let spreadSum = { ...1 + 1 }; +let spreadZero = { ...0 }; +spreadZero.toFixed(); // error, no methods even from a falsy number +let spreadBool = { ...true }; +spreadBool.valueOf(); let spreadStr = { ...'foo' }; spreadStr.length; // error, no 'length' spreadStr.charAt(1); // error, no methods either @@ -116,7 +122,13 @@ spread = b; // error, missing 's' // literal repeats are not allowed, but spread repeats are fine var duplicated = __assign({ b: 'bad' }, o, { b: 'bad' }, o2, { b: 'bad' }); var duplicatedSpread = __assign({}, o, o); -// primitives are skipped +// primitives are not allowed, except for falsy ones +var spreadNum = __assign({}, 12); +var spreadSum = __assign({}, 1 + 1); +var spreadZero = __assign({}, 0); +spreadZero.toFixed(); // error, no methods even from a falsy number +var spreadBool = __assign({}, true); +spreadBool.valueOf(); var spreadStr = __assign({}, 'foo'); spreadStr.length; // error, no 'length' spreadStr.charAt(1); // error, no methods either diff --git a/tests/baselines/reference/objectSpreadNegativeParse.errors.txt b/tests/baselines/reference/objectSpreadNegativeParse.errors.txt index 41651fb1d1c..b37200c4f02 100644 --- a/tests/baselines/reference/objectSpreadNegativeParse.errors.txt +++ b/tests/baselines/reference/objectSpreadNegativeParse.errors.txt @@ -1,5 +1,6 @@ tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(1,15): error TS2304: Cannot find name 'o'. tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(1,18): error TS1109: Expression expected. +tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(2,12): error TS2698: Spread types may only be created from object types. tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(2,15): error TS1109: Expression expected. tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(2,16): error TS2304: Cannot find name 'o'. tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(3,15): error TS2304: Cannot find name 'matchMedia'. @@ -9,13 +10,15 @@ tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(4,16): error T tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(4,20): error TS1005: ',' expected. -==== tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts (9 errors) ==== +==== tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts (10 errors) ==== let o7 = { ...o? }; ~ !!! error TS2304: Cannot find name 'o'. ~ !!! error TS1109: Expression expected. let o8 = { ...*o }; + ~~~~~ +!!! error TS2698: Spread types may only be created from object types. ~ !!! error TS1109: Expression expected. ~ diff --git a/tests/baselines/reference/restInvalidArgumentType.errors.txt b/tests/baselines/reference/restInvalidArgumentType.errors.txt index 44577d5a24e..0cc4faea557 100644 --- a/tests/baselines/reference/restInvalidArgumentType.errors.txt +++ b/tests/baselines/reference/restInvalidArgumentType.errors.txt @@ -1,13 +1,24 @@ -tests/cases/compiler/restInvalidArgumentType.ts(18,13): error TS2700: Rest types may only be created from object types. -tests/cases/compiler/restInvalidArgumentType.ts(20,13): error TS2700: Rest types may only be created from object types. -tests/cases/compiler/restInvalidArgumentType.ts(22,13): error TS2700: Rest types may only be created from object types. -tests/cases/compiler/restInvalidArgumentType.ts(23,13): error TS2700: Rest types may only be created from object types. -tests/cases/compiler/restInvalidArgumentType.ts(25,13): error TS2700: Rest types may only be created from object types. -tests/cases/compiler/restInvalidArgumentType.ts(28,13): error TS2700: Rest types may only be created from object types. +tests/cases/compiler/restInvalidArgumentType.ts(27,13): error TS2700: Rest types may only be created from object types. +tests/cases/compiler/restInvalidArgumentType.ts(29,13): error TS2700: Rest types may only be created from object types. tests/cases/compiler/restInvalidArgumentType.ts(30,13): error TS2700: Rest types may only be created from object types. +tests/cases/compiler/restInvalidArgumentType.ts(31,13): error TS2700: Rest types may only be created from object types. +tests/cases/compiler/restInvalidArgumentType.ts(33,13): error TS2700: Rest types may only be created from object types. +tests/cases/compiler/restInvalidArgumentType.ts(36,13): error TS2700: Rest types may only be created from object types. +tests/cases/compiler/restInvalidArgumentType.ts(37,13): error TS2700: Rest types may only be created from object types. +tests/cases/compiler/restInvalidArgumentType.ts(39,13): error TS2700: Rest types may only be created from object types. +tests/cases/compiler/restInvalidArgumentType.ts(40,13): error TS2700: Rest types may only be created from object types. +tests/cases/compiler/restInvalidArgumentType.ts(42,13): error TS2700: Rest types may only be created from object types. +tests/cases/compiler/restInvalidArgumentType.ts(43,13): error TS2700: Rest types may only be created from object types. +tests/cases/compiler/restInvalidArgumentType.ts(45,13): error TS2700: Rest types may only be created from object types. +tests/cases/compiler/restInvalidArgumentType.ts(46,13): error TS2700: Rest types may only be created from object types. +tests/cases/compiler/restInvalidArgumentType.ts(50,13): error TS2700: Rest types may only be created from object types. +tests/cases/compiler/restInvalidArgumentType.ts(51,13): error TS2700: Rest types may only be created from object types. +tests/cases/compiler/restInvalidArgumentType.ts(53,13): error TS2700: Rest types may only be created from object types. -==== tests/cases/compiler/restInvalidArgumentType.ts (7 errors) ==== +==== tests/cases/compiler/restInvalidArgumentType.ts (16 errors) ==== + enum E { v1, v2 }; + function f(p1: T, p2: T[]) { var t: T; @@ -18,7 +29,14 @@ tests/cases/compiler/restInvalidArgumentType.ts(30,13): error TS2700: Rest types var mapped: {[P in "b"]: T[P]}; var union_generic: T | { a: number }; + var union_primitive: { a: number } | number; var intersection_generic: T & { a: number }; + var intersection_primitive: { a: number } & string; + var num: number; + var str: string; + var literal_string: "string"; + var literal_number: 42; + var e: E; var u: undefined; var n: null; @@ -32,7 +50,6 @@ tests/cases/compiler/restInvalidArgumentType.ts(30,13): error TS2700: Rest types var {...r3} = t; // Error, generic type paramter ~~ !!! error TS2700: Rest types may only be created from object types. - var {...r4} = i; // Error, index access ~~ !!! error TS2700: Rest types may only be created from object types. @@ -48,14 +65,42 @@ tests/cases/compiler/restInvalidArgumentType.ts(30,13): error TS2700: Rest types var {...r8} = union_generic; // Error, union with generic type parameter ~~ !!! error TS2700: Rest types may only be created from object types. + var {...r9} = union_primitive; // Error, union with generic type parameter + ~~ +!!! error TS2700: Rest types may only be created from object types. var {...r10} = intersection_generic; // Error, intersection with generic type parameter ~~~ !!! error TS2700: Rest types may only be created from object types. + var {...r11} = intersection_primitive; // Error, intersection with generic type parameter + ~~~ +!!! error TS2700: Rest types may only be created from object types. - var {...r14} = u; // OK - var {...r15} = n; // OK + var {...r12} = num; // Error + ~~~ +!!! error TS2700: Rest types may only be created from object types. + var {...r13} = str; // Error + ~~~ +!!! error TS2700: Rest types may only be created from object types. + + var {...r14} = u; // error, undefined-only not allowed + ~~~ +!!! error TS2700: Rest types may only be created from object types. + var {...r15} = n; // error, null-only not allowed + ~~~ +!!! error TS2700: Rest types may only be created from object types. var {...r16} = a; // OK + + var {...r17} = literal_string; // Error + ~~~ +!!! error TS2700: Rest types may only be created from object types. + var {...r18} = literal_number; // Error + ~~~ +!!! error TS2700: Rest types may only be created from object types. + + var {...r19} = e; // Error, enum + ~~~ +!!! error TS2700: Rest types may only be created from object types. } \ No newline at end of file diff --git a/tests/baselines/reference/restInvalidArgumentType.js b/tests/baselines/reference/restInvalidArgumentType.js index 81bcfb63a17..75b52a8c6e8 100644 --- a/tests/baselines/reference/restInvalidArgumentType.js +++ b/tests/baselines/reference/restInvalidArgumentType.js @@ -1,4 +1,6 @@ //// [restInvalidArgumentType.ts] +enum E { v1, v2 }; + function f(p1: T, p2: T[]) { var t: T; @@ -9,7 +11,14 @@ function f(p1: T, p2: T[]) { var mapped: {[P in "b"]: T[P]}; var union_generic: T | { a: number }; + var union_primitive: { a: number } | number; var intersection_generic: T & { a: number }; + var intersection_primitive: { a: number } & string; + var num: number; + var str: string; + var literal_string: "string"; + var literal_number: 42; + var e: E; var u: undefined; var n: null; @@ -19,7 +28,6 @@ function f(p1: T, p2: T[]) { var {...r1} = p1; // Error, generic type paramterre var {...r2} = p2; // OK var {...r3} = t; // Error, generic type paramter - var {...r4} = i; // Error, index access var {...r5} = k; // Error, index @@ -27,13 +35,23 @@ function f(p1: T, p2: T[]) { var {...r7} = mapped; // OK, non-generic mapped type var {...r8} = union_generic; // Error, union with generic type parameter + var {...r9} = union_primitive; // Error, union with generic type parameter var {...r10} = intersection_generic; // Error, intersection with generic type parameter + var {...r11} = intersection_primitive; // Error, intersection with generic type parameter - var {...r14} = u; // OK - var {...r15} = n; // OK + var {...r12} = num; // Error + var {...r13} = str; // Error + + var {...r14} = u; // error, undefined-only not allowed + var {...r15} = n; // error, null-only not allowed var {...r16} = a; // OK + + var {...r17} = literal_string; // Error + var {...r18} = literal_number; // Error + + var {...r19} = e; // Error, enum } @@ -47,6 +65,12 @@ var __rest = (this && this.__rest) || function (s, e) { t[p[i]] = s[p[i]]; return t; }; +var E; +(function (E) { + E[E["v1"] = 0] = "v1"; + E[E["v2"] = 1] = "v2"; +})(E || (E = {})); +; function f(p1, p2) { var t; var i; @@ -54,7 +78,14 @@ function f(p1, p2) { var mapped_generic; var mapped; var union_generic; + var union_primitive; var intersection_generic; + var intersection_primitive; + var num; + var str; + var literal_string; + var literal_number; + var e; var u; var n; var a; @@ -66,8 +97,15 @@ function f(p1, p2) { var r6 = __rest(mapped_generic, []); // Error, generic mapped object type var r7 = __rest(mapped, []); // OK, non-generic mapped type var r8 = __rest(union_generic, []); // Error, union with generic type parameter + var r9 = __rest(union_primitive, []); // Error, union with generic type parameter var r10 = __rest(intersection_generic, []); // Error, intersection with generic type parameter - var r14 = __rest(u, []); // OK - var r15 = __rest(n, []); // OK + var r11 = __rest(intersection_primitive, []); // Error, intersection with generic type parameter + var r12 = __rest(num, []); // Error + var r13 = __rest(str, []); // Error + var r14 = __rest(u, []); // error, undefined-only not allowed + var r15 = __rest(n, []); // error, null-only not allowed var r16 = __rest(a, []); // OK + var r17 = __rest(literal_string, []); // Error + var r18 = __rest(literal_number, []); // Error + var r19 = __rest(e, []); // Error, enum } diff --git a/tests/baselines/reference/restUnion2.js b/tests/baselines/reference/restUnion2.js index 71f4b06cfef..437ea780193 100644 --- a/tests/baselines/reference/restUnion2.js +++ b/tests/baselines/reference/restUnion2.js @@ -7,15 +7,7 @@ var {...rest2 } = undefinedUnion; declare const nullUnion: { n: number } | null; var rest3: { n: number }; var {...rest3 } = nullUnion; - - -declare const nullAndUndefinedUnion: null | undefined; -var rest4: { }; -var {...rest4 } = nullAndUndefinedUnion; - -declare const unionWithIntersection: ({ n: number } & { s: string }) & undefined | null; -var rest5: { n: number, s: string }; -var {...rest5 } = unionWithIntersection; + //// [restUnion2.js] var __rest = (this && this.__rest) || function (s, e) { @@ -31,7 +23,3 @@ var rest2; var rest2 = __rest(undefinedUnion, []); var rest3; var rest3 = __rest(nullUnion, []); -var rest4; -var rest4 = __rest(nullAndUndefinedUnion, []); -var rest5; -var rest5 = __rest(unionWithIntersection, []); diff --git a/tests/baselines/reference/restUnion2.symbols b/tests/baselines/reference/restUnion2.symbols index 54ac47f0694..c6c34511b17 100644 --- a/tests/baselines/reference/restUnion2.symbols +++ b/tests/baselines/reference/restUnion2.symbols @@ -24,28 +24,3 @@ var {...rest3 } = nullUnion; >rest3 : Symbol(rest3, Decl(restUnion2.ts, 6, 3), Decl(restUnion2.ts, 7, 5)) >nullUnion : Symbol(nullUnion, Decl(restUnion2.ts, 5, 13)) - -declare const nullAndUndefinedUnion: null | undefined; ->nullAndUndefinedUnion : Symbol(nullAndUndefinedUnion, Decl(restUnion2.ts, 10, 13)) - -var rest4: { }; ->rest4 : Symbol(rest4, Decl(restUnion2.ts, 11, 3), Decl(restUnion2.ts, 12, 5)) - -var {...rest4 } = nullAndUndefinedUnion; ->rest4 : Symbol(rest4, Decl(restUnion2.ts, 11, 3), Decl(restUnion2.ts, 12, 5)) ->nullAndUndefinedUnion : Symbol(nullAndUndefinedUnion, Decl(restUnion2.ts, 10, 13)) - -declare const unionWithIntersection: ({ n: number } & { s: string }) & undefined | null; ->unionWithIntersection : Symbol(unionWithIntersection, Decl(restUnion2.ts, 14, 13)) ->n : Symbol(n, Decl(restUnion2.ts, 14, 39)) ->s : Symbol(s, Decl(restUnion2.ts, 14, 55)) - -var rest5: { n: number, s: string }; ->rest5 : Symbol(rest5, Decl(restUnion2.ts, 15, 3), Decl(restUnion2.ts, 16, 5)) ->n : Symbol(n, Decl(restUnion2.ts, 15, 12)) ->s : Symbol(s, Decl(restUnion2.ts, 15, 23)) - -var {...rest5 } = unionWithIntersection; ->rest5 : Symbol(rest5, Decl(restUnion2.ts, 15, 3), Decl(restUnion2.ts, 16, 5)) ->unionWithIntersection : Symbol(unionWithIntersection, Decl(restUnion2.ts, 14, 13)) - diff --git a/tests/baselines/reference/restUnion2.types b/tests/baselines/reference/restUnion2.types index 03c8d577e66..0e464930b07 100644 --- a/tests/baselines/reference/restUnion2.types +++ b/tests/baselines/reference/restUnion2.types @@ -25,30 +25,3 @@ var {...rest3 } = nullUnion; >rest3 : { n: number; } >nullUnion : { n: number; } | null - -declare const nullAndUndefinedUnion: null | undefined; ->nullAndUndefinedUnion : null | undefined ->null : null - -var rest4: { }; ->rest4 : {} - -var {...rest4 } = nullAndUndefinedUnion; ->rest4 : {} ->nullAndUndefinedUnion : null | undefined - -declare const unionWithIntersection: ({ n: number } & { s: string }) & undefined | null; ->unionWithIntersection : ({ n: number; } & { s: string; } & undefined) | null ->n : number ->s : string ->null : null - -var rest5: { n: number, s: string }; ->rest5 : { n: number; s: string; } ->n : number ->s : string - -var {...rest5 } = unionWithIntersection; ->rest5 : { n: number; s: string; } ->unionWithIntersection : ({ n: number; } & { s: string; } & undefined) | null - diff --git a/tests/baselines/reference/restUnion3.errors.txt b/tests/baselines/reference/restUnion3.errors.txt new file mode 100644 index 00000000000..a960ad4a33b --- /dev/null +++ b/tests/baselines/reference/restUnion3.errors.txt @@ -0,0 +1,17 @@ +tests/cases/compiler/restUnion3.ts(3,9): error TS2700: Rest types may only be created from object types. +tests/cases/compiler/restUnion3.ts(7,9): error TS2700: Rest types may only be created from object types. + + +==== tests/cases/compiler/restUnion3.ts (2 errors) ==== + declare const nullAndUndefinedUnion: null | undefined; + var rest4: { }; + var {...rest4 } = nullAndUndefinedUnion; + ~~~~~ +!!! error TS2700: Rest types may only be created from object types. + + declare const unionWithIntersection: ({ n: number } & { s: string }) & undefined | null; + var rest5: { n: number, s: string }; + var {...rest5 } = unionWithIntersection; + ~~~~~ +!!! error TS2700: Rest types may only be created from object types. + \ No newline at end of file diff --git a/tests/baselines/reference/restUnion3.js b/tests/baselines/reference/restUnion3.js new file mode 100644 index 00000000000..f10bd7ed0a7 --- /dev/null +++ b/tests/baselines/reference/restUnion3.js @@ -0,0 +1,25 @@ +//// [restUnion3.ts] +declare const nullAndUndefinedUnion: null | undefined; +var rest4: { }; +var {...rest4 } = nullAndUndefinedUnion; + +declare const unionWithIntersection: ({ n: number } & { s: string }) & undefined | null; +var rest5: { n: number, s: string }; +var {...rest5 } = unionWithIntersection; + + +//// [restUnion3.js] +"use strict"; +var __rest = (this && this.__rest) || function (s, e) { + var t = {}; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) + t[p] = s[p]; + if (s != null && typeof Object.getOwnPropertySymbols === "function") + for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0) + t[p[i]] = s[p[i]]; + return t; +}; +var rest4; +var rest4 = __rest(nullAndUndefinedUnion, []); +var rest5; +var rest5 = __rest(unionWithIntersection, []); diff --git a/tests/baselines/reference/spreadInvalidArgumentType.errors.txt b/tests/baselines/reference/spreadInvalidArgumentType.errors.txt index 5b48e24ad0d..4c1aa286aad 100644 --- a/tests/baselines/reference/spreadInvalidArgumentType.errors.txt +++ b/tests/baselines/reference/spreadInvalidArgumentType.errors.txt @@ -1,13 +1,24 @@ -tests/cases/compiler/spreadInvalidArgumentType.ts(19,16): error TS2698: Spread types may only be created from object types. -tests/cases/compiler/spreadInvalidArgumentType.ts(21,16): error TS2698: Spread types may only be created from object types. -tests/cases/compiler/spreadInvalidArgumentType.ts(23,16): error TS2698: Spread types may only be created from object types. -tests/cases/compiler/spreadInvalidArgumentType.ts(24,16): error TS2698: Spread types may only be created from object types. -tests/cases/compiler/spreadInvalidArgumentType.ts(26,16): error TS2698: Spread types may only be created from object types. -tests/cases/compiler/spreadInvalidArgumentType.ts(29,16): error TS2698: Spread types may only be created from object types. -tests/cases/compiler/spreadInvalidArgumentType.ts(31,17): error TS2698: Spread types may only be created from object types. +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. +tests/cases/compiler/spreadInvalidArgumentType.ts(47,17): error TS2698: Spread types may only be created from object types. +tests/cases/compiler/spreadInvalidArgumentType.ts(48,17): error TS2698: Spread types may only be created from object types. +tests/cases/compiler/spreadInvalidArgumentType.ts(52,17): error TS2698: Spread types may only be created from object types. +tests/cases/compiler/spreadInvalidArgumentType.ts(53,17): error TS2698: Spread types may only be created from object types. +tests/cases/compiler/spreadInvalidArgumentType.ts(55,17): error TS2698: Spread types may only be created from object types. -==== tests/cases/compiler/spreadInvalidArgumentType.ts (7 errors) ==== +==== tests/cases/compiler/spreadInvalidArgumentType.ts (16 errors) ==== + enum E { v1, v2 }; + function f(p1: T, p2: T[]) { var t: T; @@ -18,14 +29,23 @@ tests/cases/compiler/spreadInvalidArgumentType.ts(31,17): error TS2698: Spread t var mapped: {[P in "b"]: T[P]}; var union_generic: T | { a: number }; + var union_primitive: { a: number } | number; var intersection_generic: T & { a: number }; + var intersection_primitive: { a: number } | string; + + var num: number; + var str: number; + var literal_string: "string"; + var literal_number: 42; var u: undefined; var n: null; - var a: any; + + var e: E; + var o1 = { ...p1 }; // Error, generic type paramterre ~~~~~ !!! error TS2698: Spread types may only be created from object types. @@ -33,14 +53,12 @@ tests/cases/compiler/spreadInvalidArgumentType.ts(31,17): error TS2698: Spread t 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 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. @@ -49,14 +67,42 @@ tests/cases/compiler/spreadInvalidArgumentType.ts(31,17): error TS2698: Spread t var o8 = { ...union_generic }; // Error, union with generic type parameter ~~~~~~~~~~~~~~~~ !!! error TS2698: Spread types may only be created from object types. + 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 o11 = { ...intersection_primitive }; // Error, intersection with generic type parameter + ~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2698: Spread types may only be created from object types. - var o14 = { ...u }; // OK - var o15 = { ...n }; // OK + var o12 = { ...num }; // Error + ~~~~~~ +!!! error TS2698: Spread types may only be created from object types. + var o13 = { ...str }; // Error + ~~~~~~ +!!! error TS2698: Spread types may only be created from object types. + + var o14 = { ...u }; // error, undefined-only not allowed + ~~~~ +!!! error TS2698: Spread types may only be created from object types. + var o15 = { ...n }; // error, null-only not allowed + ~~~~ +!!! error TS2698: Spread types may only be created from object types. var o16 = { ...a }; // OK + + var o17 = { ...literal_string }; // Error + ~~~~~~~~~~~~~~~~~ +!!! error TS2698: Spread types may only be created from object types. + var o18 = { ...literal_number }; // Error + ~~~~~~~~~~~~~~~~~ +!!! error TS2698: Spread types may only be created from object types. + + var o19 = { ...e }; // Error, enum + ~~~~ +!!! error TS2698: Spread types may only be created from object types. } \ No newline at end of file diff --git a/tests/baselines/reference/spreadInvalidArgumentType.js b/tests/baselines/reference/spreadInvalidArgumentType.js index aa42419e59a..7aa04616fd1 100644 --- a/tests/baselines/reference/spreadInvalidArgumentType.js +++ b/tests/baselines/reference/spreadInvalidArgumentType.js @@ -1,4 +1,6 @@ //// [spreadInvalidArgumentType.ts] +enum E { v1, v2 }; + function f(p1: T, p2: T[]) { var t: T; @@ -9,32 +11,49 @@ function f(p1: T, p2: T[]) { var mapped: {[P in "b"]: T[P]}; var union_generic: T | { a: number }; + var union_primitive: { a: number } | number; var intersection_generic: T & { a: number }; + var intersection_primitive: { a: number } | string; + + var num: number; + var str: number; + var literal_string: "string"; + var literal_number: 42; var u: undefined; var n: null; - var a: any; + + 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 o5 = { ...k }; // Error, index - var o6 = { ...mapped_generic }; // Error, generic mapped object type var o7 = { ...mapped }; // OK, non-generic mapped type var o8 = { ...union_generic }; // Error, 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 o11 = { ...intersection_primitive }; // Error, intersection with generic type parameter - var o14 = { ...u }; // OK - var o15 = { ...n }; // OK + var o12 = { ...num }; // Error + var o13 = { ...str }; // Error + + var o14 = { ...u }; // error, undefined-only not allowed + var o15 = { ...n }; // error, null-only not allowed var o16 = { ...a }; // OK + + var o17 = { ...literal_string }; // Error + var o18 = { ...literal_number }; // Error + + var o19 = { ...e }; // Error, enum } @@ -47,6 +66,12 @@ var __assign = (this && this.__assign) || Object.assign || function(t) { } return t; }; +var E; +(function (E) { + E[E["v1"] = 0] = "v1"; + E[E["v2"] = 1] = "v2"; +})(E || (E = {})); +; function f(p1, p2) { var t; var i; @@ -54,10 +79,17 @@ function f(p1, p2) { var mapped_generic; var mapped; var union_generic; + var union_primitive; var intersection_generic; + var intersection_primitive; + var num; + var str; + var literal_string; + var literal_number; var u; var n; var a; + var e; var o1 = __assign({}, p1); // Error, generic type paramterre var o2 = __assign({}, p2); // OK var o3 = __assign({}, t); // Error, generic type paramter @@ -66,8 +98,15 @@ function f(p1, p2) { var o6 = __assign({}, mapped_generic); // Error, 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 o9 = __assign({}, union_primitive); // Error, union with generic type parameter var o10 = __assign({}, intersection_generic); // Error, intersection with generic type parameter - var o14 = __assign({}, u); // OK - var o15 = __assign({}, n); // OK + var o11 = __assign({}, intersection_primitive); // Error, intersection with generic type parameter + var o12 = __assign({}, num); // Error + var o13 = __assign({}, str); // Error + var o14 = __assign({}, u); // error, undefined-only not allowed + var o15 = __assign({}, n); // error, null-only not allowed var o16 = __assign({}, a); // OK + var o17 = __assign({}, literal_string); // Error + var o18 = __assign({}, literal_number); // Error + var o19 = __assign({}, e); // Error, enum } diff --git a/tests/baselines/reference/spreadUnion2.js b/tests/baselines/reference/spreadUnion2.js index 48b12731817..662b7cd3e46 100644 --- a/tests/baselines/reference/spreadUnion2.js +++ b/tests/baselines/reference/spreadUnion2.js @@ -1,7 +1,6 @@ //// [spreadUnion2.ts] declare const undefinedUnion: { a: number } | undefined; declare const nullUnion: { b: number } | null; -declare const nullAndUndefinedUnion: null | undefined; var o1: { a?: number | undefined }; var o1 = { ...undefinedUnion }; @@ -19,8 +18,6 @@ var o4 = { ...undefinedUnion, ...undefinedUnion }; var o5: { b?: number | undefined }; var o5 = { ...nullUnion, ...nullUnion }; -var o6 = { ...nullAndUndefinedUnion, ...nullAndUndefinedUnion }; -var o7 = { ...nullAndUndefinedUnion }; //// [spreadUnion2.js] @@ -43,5 +40,3 @@ var o4; var o4 = __assign({}, undefinedUnion, undefinedUnion); var o5; var o5 = __assign({}, nullUnion, nullUnion); -var o6 = __assign({}, nullAndUndefinedUnion, nullAndUndefinedUnion); -var o7 = __assign({}, nullAndUndefinedUnion); diff --git a/tests/baselines/reference/spreadUnion2.symbols b/tests/baselines/reference/spreadUnion2.symbols index 841bce12e42..2cc91f2980b 100644 --- a/tests/baselines/reference/spreadUnion2.symbols +++ b/tests/baselines/reference/spreadUnion2.symbols @@ -7,64 +7,53 @@ declare const nullUnion: { b: number } | null; >nullUnion : Symbol(nullUnion, Decl(spreadUnion2.ts, 1, 13)) >b : Symbol(b, Decl(spreadUnion2.ts, 1, 26)) -declare const nullAndUndefinedUnion: null | undefined; ->nullAndUndefinedUnion : Symbol(nullAndUndefinedUnion, Decl(spreadUnion2.ts, 2, 13)) - var o1: { a?: number | undefined }; ->o1 : Symbol(o1, Decl(spreadUnion2.ts, 4, 3), Decl(spreadUnion2.ts, 5, 3)) ->a : Symbol(a, Decl(spreadUnion2.ts, 4, 9)) +>o1 : Symbol(o1, Decl(spreadUnion2.ts, 3, 3), Decl(spreadUnion2.ts, 4, 3)) +>a : Symbol(a, Decl(spreadUnion2.ts, 3, 9)) var o1 = { ...undefinedUnion }; ->o1 : Symbol(o1, Decl(spreadUnion2.ts, 4, 3), Decl(spreadUnion2.ts, 5, 3)) +>o1 : Symbol(o1, Decl(spreadUnion2.ts, 3, 3), Decl(spreadUnion2.ts, 4, 3)) >undefinedUnion : Symbol(undefinedUnion, Decl(spreadUnion2.ts, 0, 13)) var o2: { b?: number | undefined }; ->o2 : Symbol(o2, Decl(spreadUnion2.ts, 7, 3), Decl(spreadUnion2.ts, 8, 3)) ->b : Symbol(b, Decl(spreadUnion2.ts, 7, 9)) +>o2 : Symbol(o2, Decl(spreadUnion2.ts, 6, 3), Decl(spreadUnion2.ts, 7, 3)) +>b : Symbol(b, Decl(spreadUnion2.ts, 6, 9)) var o2 = { ...nullUnion }; ->o2 : Symbol(o2, Decl(spreadUnion2.ts, 7, 3), Decl(spreadUnion2.ts, 8, 3)) +>o2 : Symbol(o2, Decl(spreadUnion2.ts, 6, 3), Decl(spreadUnion2.ts, 7, 3)) >nullUnion : Symbol(nullUnion, Decl(spreadUnion2.ts, 1, 13)) var o3: { a?: number | undefined, b?: number | undefined }; ->o3 : Symbol(o3, Decl(spreadUnion2.ts, 10, 3), Decl(spreadUnion2.ts, 11, 3), Decl(spreadUnion2.ts, 12, 3)) ->a : Symbol(a, Decl(spreadUnion2.ts, 10, 9)) ->b : Symbol(b, Decl(spreadUnion2.ts, 10, 33)) +>o3 : Symbol(o3, Decl(spreadUnion2.ts, 9, 3), Decl(spreadUnion2.ts, 10, 3), Decl(spreadUnion2.ts, 11, 3)) +>a : Symbol(a, Decl(spreadUnion2.ts, 9, 9)) +>b : Symbol(b, Decl(spreadUnion2.ts, 9, 33)) var o3 = { ...undefinedUnion, ...nullUnion }; ->o3 : Symbol(o3, Decl(spreadUnion2.ts, 10, 3), Decl(spreadUnion2.ts, 11, 3), Decl(spreadUnion2.ts, 12, 3)) +>o3 : Symbol(o3, Decl(spreadUnion2.ts, 9, 3), Decl(spreadUnion2.ts, 10, 3), Decl(spreadUnion2.ts, 11, 3)) >undefinedUnion : Symbol(undefinedUnion, Decl(spreadUnion2.ts, 0, 13)) >nullUnion : Symbol(nullUnion, Decl(spreadUnion2.ts, 1, 13)) var o3 = { ...nullUnion, ...undefinedUnion }; ->o3 : Symbol(o3, Decl(spreadUnion2.ts, 10, 3), Decl(spreadUnion2.ts, 11, 3), Decl(spreadUnion2.ts, 12, 3)) +>o3 : Symbol(o3, Decl(spreadUnion2.ts, 9, 3), Decl(spreadUnion2.ts, 10, 3), Decl(spreadUnion2.ts, 11, 3)) >nullUnion : Symbol(nullUnion, Decl(spreadUnion2.ts, 1, 13)) >undefinedUnion : Symbol(undefinedUnion, Decl(spreadUnion2.ts, 0, 13)) var o4: { a?: number | undefined }; ->o4 : Symbol(o4, Decl(spreadUnion2.ts, 14, 3), Decl(spreadUnion2.ts, 15, 3)) ->a : Symbol(a, Decl(spreadUnion2.ts, 14, 9)) +>o4 : Symbol(o4, Decl(spreadUnion2.ts, 13, 3), Decl(spreadUnion2.ts, 14, 3)) +>a : Symbol(a, Decl(spreadUnion2.ts, 13, 9)) var o4 = { ...undefinedUnion, ...undefinedUnion }; ->o4 : Symbol(o4, Decl(spreadUnion2.ts, 14, 3), Decl(spreadUnion2.ts, 15, 3)) +>o4 : Symbol(o4, Decl(spreadUnion2.ts, 13, 3), Decl(spreadUnion2.ts, 14, 3)) >undefinedUnion : Symbol(undefinedUnion, Decl(spreadUnion2.ts, 0, 13)) >undefinedUnion : Symbol(undefinedUnion, Decl(spreadUnion2.ts, 0, 13)) var o5: { b?: number | undefined }; ->o5 : Symbol(o5, Decl(spreadUnion2.ts, 17, 3), Decl(spreadUnion2.ts, 18, 3)) ->b : Symbol(b, Decl(spreadUnion2.ts, 17, 9)) +>o5 : Symbol(o5, Decl(spreadUnion2.ts, 16, 3), Decl(spreadUnion2.ts, 17, 3)) +>b : Symbol(b, Decl(spreadUnion2.ts, 16, 9)) var o5 = { ...nullUnion, ...nullUnion }; ->o5 : Symbol(o5, Decl(spreadUnion2.ts, 17, 3), Decl(spreadUnion2.ts, 18, 3)) +>o5 : Symbol(o5, Decl(spreadUnion2.ts, 16, 3), Decl(spreadUnion2.ts, 17, 3)) >nullUnion : Symbol(nullUnion, Decl(spreadUnion2.ts, 1, 13)) >nullUnion : Symbol(nullUnion, Decl(spreadUnion2.ts, 1, 13)) -var o6 = { ...nullAndUndefinedUnion, ...nullAndUndefinedUnion }; ->o6 : Symbol(o6, Decl(spreadUnion2.ts, 20, 3)) ->nullAndUndefinedUnion : Symbol(nullAndUndefinedUnion, Decl(spreadUnion2.ts, 2, 13)) ->nullAndUndefinedUnion : Symbol(nullAndUndefinedUnion, Decl(spreadUnion2.ts, 2, 13)) - -var o7 = { ...nullAndUndefinedUnion }; ->o7 : Symbol(o7, Decl(spreadUnion2.ts, 21, 3)) ->nullAndUndefinedUnion : Symbol(nullAndUndefinedUnion, Decl(spreadUnion2.ts, 2, 13)) diff --git a/tests/baselines/reference/spreadUnion2.types b/tests/baselines/reference/spreadUnion2.types index 50f79cc7745..ccf587af591 100644 --- a/tests/baselines/reference/spreadUnion2.types +++ b/tests/baselines/reference/spreadUnion2.types @@ -8,10 +8,6 @@ declare const nullUnion: { b: number } | null; >b : number >null : null -declare const nullAndUndefinedUnion: null | undefined; ->nullAndUndefinedUnion : null | undefined ->null : null - var o1: { a?: number | undefined }; >o1 : { a?: number | undefined; } >a : number | undefined @@ -67,14 +63,4 @@ var o5 = { ...nullUnion, ...nullUnion }; >nullUnion : { b: number; } | null >nullUnion : { b: number; } | null -var o6 = { ...nullAndUndefinedUnion, ...nullAndUndefinedUnion }; ->o6 : {} ->{ ...nullAndUndefinedUnion, ...nullAndUndefinedUnion } : {} ->nullAndUndefinedUnion : null | undefined ->nullAndUndefinedUnion : null | undefined - -var o7 = { ...nullAndUndefinedUnion }; ->o7 : {} ->{ ...nullAndUndefinedUnion } : {} ->nullAndUndefinedUnion : null | undefined diff --git a/tests/baselines/reference/spreadUnion3.errors.txt b/tests/baselines/reference/spreadUnion3.errors.txt index f3fa2da7597..24d864d96fe 100644 --- a/tests/baselines/reference/spreadUnion3.errors.txt +++ b/tests/baselines/reference/spreadUnion3.errors.txt @@ -2,11 +2,13 @@ tests/cases/conformance/types/spread/spreadUnion3.ts(2,5): error TS2322: Type '{ Types of property 'y' are incompatible. Type 'string | number' is not assignable to type 'string'. Type 'number' is not assignable to type 'string'. -tests/cases/conformance/types/spread/spreadUnion3.ts(9,23): error TS2339: Property 'a' does not exist on type '{} | {} | { a: number; }'. - Property 'a' does not exist on type '{}'. +tests/cases/conformance/types/spread/spreadUnion3.ts(9,9): error TS2322: Type 'number | undefined' is not assignable to type 'number'. + Type 'undefined' is not assignable to type 'number'. +tests/cases/conformance/types/spread/spreadUnion3.ts(17,11): error TS2698: Spread types may only be created from object types. +tests/cases/conformance/types/spread/spreadUnion3.ts(18,11): error TS2698: Spread types may only be created from object types. -==== tests/cases/conformance/types/spread/spreadUnion3.ts (2 errors) ==== +==== tests/cases/conformance/types/spread/spreadUnion3.ts (4 errors) ==== function f(x: { y: string } | undefined): { y: string } { return { y: 123, ...x } // y: string | number ~~~~~~~~~~~~~~~~~~~~~~~ @@ -21,11 +23,20 @@ tests/cases/conformance/types/spread/spreadUnion3.ts(9,23): error TS2339: Proper function g(t?: { a: number } | null): void { let b = { ...t }; let c: number = b.a; // might not have 'a' - ~ -!!! error TS2339: Property 'a' does not exist on type '{} | {} | { a: number; }'. -!!! error TS2339: Property 'a' does not exist on type '{}'. + ~ +!!! error TS2322: Type 'number | undefined' is not assignable to type 'number'. +!!! error TS2322: Type 'undefined' is not assignable to type 'number'. } g() g(undefined) g(null) + + // spreading nothing but null and undefined is not allowed + declare const nullAndUndefinedUnion: null | undefined; + var x = { ...nullAndUndefinedUnion, ...nullAndUndefinedUnion }; + ~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2698: Spread types may only be created from object types. + var y = { ...nullAndUndefinedUnion }; + ~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2698: Spread types may only be created from object types. \ No newline at end of file diff --git a/tests/baselines/reference/spreadUnion3.js b/tests/baselines/reference/spreadUnion3.js index 2aaf9efeb78..253c2998b9d 100644 --- a/tests/baselines/reference/spreadUnion3.js +++ b/tests/baselines/reference/spreadUnion3.js @@ -12,6 +12,11 @@ function g(t?: { a: number } | null): void { g() g(undefined) g(null) + +// spreading nothing but null and undefined is not allowed +declare const nullAndUndefinedUnion: null | undefined; +var x = { ...nullAndUndefinedUnion, ...nullAndUndefinedUnion }; +var y = { ...nullAndUndefinedUnion }; //// [spreadUnion3.js] @@ -34,3 +39,5 @@ function g(t) { g(); g(undefined); g(null); +var x = __assign({}, nullAndUndefinedUnion, nullAndUndefinedUnion); +var y = __assign({}, nullAndUndefinedUnion); diff --git a/tests/cases/compiler/restInvalidArgumentType.ts b/tests/cases/compiler/restInvalidArgumentType.ts index 2d50903328f..db372fbd4af 100644 --- a/tests/cases/compiler/restInvalidArgumentType.ts +++ b/tests/cases/compiler/restInvalidArgumentType.ts @@ -1,3 +1,5 @@ +enum E { v1, v2 }; + function f(p1: T, p2: T[]) { var t: T; @@ -8,7 +10,14 @@ function f(p1: T, p2: T[]) { var mapped: {[P in "b"]: T[P]}; var union_generic: T | { a: number }; + var union_primitive: { a: number } | number; var intersection_generic: T & { a: number }; + var intersection_primitive: { a: number } & string; + var num: number; + var str: string; + var literal_string: "string"; + var literal_number: 42; + var e: E; var u: undefined; var n: null; @@ -18,7 +27,6 @@ function f(p1: T, p2: T[]) { var {...r1} = p1; // Error, generic type paramterre var {...r2} = p2; // OK var {...r3} = t; // Error, generic type paramter - var {...r4} = i; // Error, index access var {...r5} = k; // Error, index @@ -26,11 +34,21 @@ function f(p1: T, p2: T[]) { var {...r7} = mapped; // OK, non-generic mapped type var {...r8} = union_generic; // Error, union with generic type parameter + var {...r9} = union_primitive; // Error, union with generic type parameter var {...r10} = intersection_generic; // Error, intersection with generic type parameter + var {...r11} = intersection_primitive; // Error, intersection with generic type parameter - var {...r14} = u; // OK - var {...r15} = n; // OK + var {...r12} = num; // Error + var {...r13} = str; // Error + + var {...r14} = u; // error, undefined-only not allowed + var {...r15} = n; // error, null-only not allowed var {...r16} = a; // OK + + var {...r17} = literal_string; // Error + var {...r18} = literal_number; // Error + + var {...r19} = e; // Error, enum } diff --git a/tests/cases/compiler/restUnion2.ts b/tests/cases/compiler/restUnion2.ts index 83d94e03a73..9ae6503fb13 100644 --- a/tests/cases/compiler/restUnion2.ts +++ b/tests/cases/compiler/restUnion2.ts @@ -8,12 +8,3 @@ var {...rest2 } = undefinedUnion; declare const nullUnion: { n: number } | null; var rest3: { n: number }; var {...rest3 } = nullUnion; - - -declare const nullAndUndefinedUnion: null | undefined; -var rest4: { }; -var {...rest4 } = nullAndUndefinedUnion; - -declare const unionWithIntersection: ({ n: number } & { s: string }) & undefined | null; -var rest5: { n: number, s: string }; -var {...rest5 } = unionWithIntersection; \ No newline at end of file diff --git a/tests/cases/compiler/restUnion3.ts b/tests/cases/compiler/restUnion3.ts new file mode 100644 index 00000000000..313d83d282d --- /dev/null +++ b/tests/cases/compiler/restUnion3.ts @@ -0,0 +1,8 @@ +// @strict: true +declare const nullAndUndefinedUnion: null | undefined; +var rest4: { }; +var {...rest4 } = nullAndUndefinedUnion; + +declare const unionWithIntersection: ({ n: number } & { s: string }) & undefined | null; +var rest5: { n: number, s: string }; +var {...rest5 } = unionWithIntersection; diff --git a/tests/cases/compiler/spreadInvalidArgumentType.ts b/tests/cases/compiler/spreadInvalidArgumentType.ts index bf7365e8ab0..f18e73b31ef 100644 --- a/tests/cases/compiler/spreadInvalidArgumentType.ts +++ b/tests/cases/compiler/spreadInvalidArgumentType.ts @@ -1,3 +1,5 @@ +enum E { v1, v2 }; + function f(p1: T, p2: T[]) { var t: T; @@ -8,30 +10,47 @@ function f(p1: T, p2: T[]) { var mapped: {[P in "b"]: T[P]}; var union_generic: T | { a: number }; + var union_primitive: { a: number } | number; var intersection_generic: T & { a: number }; + var intersection_primitive: { a: number } | string; + + var num: number; + var str: number; + var literal_string: "string"; + var literal_number: 42; var u: undefined; var n: null; - var a: any; + + 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 o5 = { ...k }; // Error, index - var o6 = { ...mapped_generic }; // Error, generic mapped object type var o7 = { ...mapped }; // OK, non-generic mapped type var o8 = { ...union_generic }; // Error, 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 o11 = { ...intersection_primitive }; // Error, intersection with generic type parameter - var o14 = { ...u }; // OK - var o15 = { ...n }; // OK + var o12 = { ...num }; // Error + var o13 = { ...str }; // Error + + var o14 = { ...u }; // error, undefined-only not allowed + var o15 = { ...n }; // error, null-only not allowed var o16 = { ...a }; // OK + + var o17 = { ...literal_string }; // Error + var o18 = { ...literal_number }; // Error + + var o19 = { ...e }; // Error, enum } diff --git a/tests/cases/conformance/types/spread/objectSpread.ts b/tests/cases/conformance/types/spread/objectSpread.ts index 566c9eb0384..c7cf5e49eed 100644 --- a/tests/cases/conformance/types/spread/objectSpread.ts +++ b/tests/cases/conformance/types/spread/objectSpread.ts @@ -39,12 +39,26 @@ getter.a = 12; // functions result in { } let spreadFunc = { ...(function () { }) }; -// boolean && T results in Partial -function conditionalSpreadBoolean(b: boolean) : { x?: number | undefined, y?: number | undefined } { - return { ...b && { x: 1, y: 2 } }; +type Header = { head: string, body: string, authToken: string } +function from16326(this: { header: Header }, header: Header, authToken: string): Header { + return { + ...this.header, + ...header, + ...authToken && { authToken } + } } -function conditionalSpreadNumber(nt: number): { x?: number | undefined, y: number } { +// boolean && T results in Partial +function conditionalSpreadBoolean(b: boolean) : { x: number, y: number } { let o = { x: 12, y: 13 } + o = { + ...o, + ...b && { x: 14 } + } + let o2 = { ...b && { x: 21 }} + return o; +} +function conditionalSpreadNumber(nt: number): { x: number, y: number } { + let o = { x: 15, y: 16 } o = { ...o, ...nt && { x: nt } @@ -52,8 +66,8 @@ function conditionalSpreadNumber(nt: number): { x?: number | undefined, y: numbe let o2 = { ...nt && { x: nt }} return o; } -function conditionalSpreadString(st: string): { x?: string | undefined, y: number } { - let o = { x: 'hi', y: 13 } +function conditionalSpreadString(st: string): { x: string, y: number } { + let o = { x: 'hi', y: 17 } o = { ...o, ...st && { x: st } @@ -61,8 +75,6 @@ function conditionalSpreadString(st: string): { x?: string | undefined, y: numbe let o2 = { ...st && { x: st }} return o; } -// other booleans result in { } -let spreadBool = { ... true } // any results in any let anything: any; diff --git a/tests/cases/conformance/types/spread/objectSpreadNegative.ts b/tests/cases/conformance/types/spread/objectSpreadNegative.ts index 8fe9174f759..b6e7c5b88c9 100644 --- a/tests/cases/conformance/types/spread/objectSpreadNegative.ts +++ b/tests/cases/conformance/types/spread/objectSpreadNegative.ts @@ -29,7 +29,13 @@ spread = b; // error, missing 's' let duplicated = { b: 'bad', ...o, b: 'bad', ...o2, b: 'bad' } let duplicatedSpread = { ...o, ...o } -// primitives are skipped +// primitives are not allowed, except for falsy ones +let spreadNum = { ...12 }; +let spreadSum = { ...1 + 1 }; +let spreadZero = { ...0 }; +spreadZero.toFixed(); // error, no methods even from a falsy number +let spreadBool = { ...true }; +spreadBool.valueOf(); let spreadStr = { ...'foo' }; spreadStr.length; // error, no 'length' spreadStr.charAt(1); // error, no methods either diff --git a/tests/cases/conformance/types/spread/spreadUnion2.ts b/tests/cases/conformance/types/spread/spreadUnion2.ts index 17abdd4006a..549441be411 100644 --- a/tests/cases/conformance/types/spread/spreadUnion2.ts +++ b/tests/cases/conformance/types/spread/spreadUnion2.ts @@ -2,7 +2,6 @@ declare const undefinedUnion: { a: number } | undefined; declare const nullUnion: { b: number } | null; -declare const nullAndUndefinedUnion: null | undefined; var o1: { a?: number | undefined }; var o1 = { ...undefinedUnion }; @@ -20,5 +19,3 @@ var o4 = { ...undefinedUnion, ...undefinedUnion }; var o5: { b?: number | undefined }; var o5 = { ...nullUnion, ...nullUnion }; -var o6 = { ...nullAndUndefinedUnion, ...nullAndUndefinedUnion }; -var o7 = { ...nullAndUndefinedUnion }; diff --git a/tests/cases/conformance/types/spread/spreadUnion3.ts b/tests/cases/conformance/types/spread/spreadUnion3.ts index c16acbdf7d3..42ad1a1c652 100644 --- a/tests/cases/conformance/types/spread/spreadUnion3.ts +++ b/tests/cases/conformance/types/spread/spreadUnion3.ts @@ -12,3 +12,8 @@ function g(t?: { a: number } | null): void { g() g(undefined) g(null) + +// spreading nothing but null and undefined is not allowed +declare const nullAndUndefinedUnion: null | undefined; +var x = { ...nullAndUndefinedUnion, ...nullAndUndefinedUnion }; +var y = { ...nullAndUndefinedUnion }; From 0197357e31007a1ff63290253a9ee269c5f96542 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Fri, 15 Sep 2017 10:28:13 -0700 Subject: [PATCH 09/10] Remove mistakenly added test file Intended for a different PR --- .../narrowContextualTypeOfObjectLiteral2.ts | 21 ------------------- 1 file changed, 21 deletions(-) delete mode 100644 tests/cases/compiler/narrowContextualTypeOfObjectLiteral2.ts diff --git a/tests/cases/compiler/narrowContextualTypeOfObjectLiteral2.ts b/tests/cases/compiler/narrowContextualTypeOfObjectLiteral2.ts deleted file mode 100644 index 2a199b74bd7..00000000000 --- a/tests/cases/compiler/narrowContextualTypeOfObjectLiteral2.ts +++ /dev/null @@ -1,21 +0,0 @@ -interface X { - type1: 'x'; - value: string; -} - -interface Y { - type2: 'y'; - value: 'none' | 'done'; -} - -function foo(bar: X | Y) { } - -foo({ - type2: 'y', - value: 'done', -}); -// you could do this (amybe) by noting that -// (1) the argument is a fresh object literal -// (2) of X | Y, the object literal is only assignable to Y -// - you can do *that* cheaply (ie, symbolically) just by throwing out types -// that are missing one of the fields in the object literal From cb8d9d6143c2d50b79e330599acff88ec20ac0b1 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Fri, 15 Sep 2017 16:11:41 -0700 Subject: [PATCH 10/10] Revert spread-falsy-union/fix spread of primitive Turns out partialising falsy unions wasn't needed -- I was just returning the wrong thing when spreading primitives. --- src/compiler/checker.ts | 36 ++++-------- tests/baselines/reference/objectSpread.types | 30 +++++----- .../reference/objectSpreadNegative.errors.txt | 4 +- tests/baselines/reference/spreadUnion2.js | 10 ++-- .../baselines/reference/spreadUnion2.symbols | 24 ++++---- tests/baselines/reference/spreadUnion2.types | 58 ++++++++++--------- .../reference/spreadUnion3.errors.txt | 22 +++---- .../conformance/types/spread/spreadUnion2.ts | 10 ++-- 8 files changed, 92 insertions(+), 102 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 1b55c592784..62d44d160a7 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7846,7 +7846,6 @@ namespace ts { * and right = the new element to be spread. */ function getSpreadType(left: Type, right: Type): Type { - let truthyRight: Type; if (left.flags & TypeFlags.Any || right.flags & TypeFlags.Any) { return anyType; } @@ -7860,16 +7859,13 @@ namespace ts { return mapType(left, t => getSpreadType(t, right)); } if (right.flags & TypeFlags.Union) { - truthyRight = getTruthyTypeFromFalsyUnion(right as UnionType); - if (!truthyRight || truthyRight.flags & TypeFlags.Union) { - return mapType(right, t => getSpreadType(left, t)); - } - else { - right = truthyRight; - } + return mapType(right, t => getSpreadType(left, t)); } - if (right.flags & (TypeFlags.NonPrimitive | TypeFlags.BooleanLike | TypeFlags.NumberLike | TypeFlags.StringLike | TypeFlags.EnumLike)) { - return emptyObjectType; + if (right.flags & TypeFlags.NonPrimitive) { + return nonPrimitiveType; + } + if (right.flags & (TypeFlags.BooleanLike | TypeFlags.NumberLike | TypeFlags.StringLike | TypeFlags.EnumLike)) { + return left; } const members = createSymbolTable(); @@ -7893,7 +7889,7 @@ namespace ts { skippedPrivateMembers.set(rightProp.escapedName, true); } else if (!isClassMethod(rightProp) && !isSetterWithoutGetter) { - members.set(rightProp.escapedName, getSymbolOfSpreadProperty(rightProp, !!truthyRight)); + members.set(rightProp.escapedName, getNonReadonlySymbol(rightProp)); } } @@ -7918,22 +7914,19 @@ namespace ts { } } else { - members.set(leftProp.escapedName, getSymbolOfSpreadProperty(leftProp, /*makeOptional*/ false)); + members.set(leftProp.escapedName, getNonReadonlySymbol(leftProp)); } } return createAnonymousType(undefined, members, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo); } - function getSymbolOfSpreadProperty(prop: Symbol, makeOptional: boolean) { - if (!isReadonlySymbol(prop) && (!makeOptional || prop.flags & SymbolFlags.Optional)) { + function getNonReadonlySymbol(prop: Symbol) { + if (!isReadonlySymbol(prop)) { return prop; } - const flags = SymbolFlags.Property | (makeOptional ? SymbolFlags.Optional : prop.flags & SymbolFlags.Optional); + const flags = SymbolFlags.Property | (prop.flags & SymbolFlags.Optional); const result = createSymbol(flags, prop.escapedName); result.type = getTypeOfSymbol(prop); - if (makeOptional) { - result.type = getUnionType([result.type, undefinedType]); - } result.declarations = prop.declarations; result.syntheticOrigin = prop; return result; @@ -7943,13 +7936,6 @@ namespace ts { return prop.flags & SymbolFlags.Method && find(prop.declarations, decl => isClassLike(decl.parent)); } - function getTruthyTypeFromFalsyUnion(type: UnionType): Type | undefined { - const truthy = removeDefinitelyFalsyTypes(type); - if (truthy !== type) { - return truthy; - } - } - function createLiteralType(flags: TypeFlags, value: string | number, symbol: Symbol) { const type = createType(flags); type.symbol = symbol; diff --git a/tests/baselines/reference/objectSpread.types b/tests/baselines/reference/objectSpread.types index da24a558d51..0caef49f439 100644 --- a/tests/baselines/reference/objectSpread.types +++ b/tests/baselines/reference/objectSpread.types @@ -247,7 +247,7 @@ function from16326(this: { header: Header }, header: Header, authToken: string): >Header : Header return { ->{ ...this.header, ...header, ...authToken && { authToken } } : { authToken: string; head: string; body: string; } +>{ ...this.header, ...header, ...authToken && { authToken } } : { head: string; body: string; authToken: string; } | { authToken: string; head: string; body: string; } ...this.header, >this.header : Header @@ -280,9 +280,9 @@ function conditionalSpreadBoolean(b: boolean) : { x: number, y: number } { >13 : 13 o = { ->o = { ...o, ...b && { x: 14 } } : { x: number; y: number; } +>o = { ...o, ...b && { x: 14 } } : { x: number; y: number; } | { x: number; y: number; } >o : { x: number; y: number; } ->{ ...o, ...b && { x: 14 } } : { x: number; y: number; } +>{ ...o, ...b && { x: 14 } } : { x: number; y: number; } | { x: number; y: number; } ...o, >o : { x: number; y: number; } @@ -295,8 +295,8 @@ function conditionalSpreadBoolean(b: boolean) : { x: number, y: number } { >14 : 14 } let o2 = { ...b && { x: 21 }} ->o2 : { x?: number | undefined; } ->{ ...b && { x: 21 }} : { x?: number | undefined; } +>o2 : {} | { x: number; } +>{ ...b && { x: 21 }} : {} | { x: number; } >b && { x: 21 } : false | { x: number; } >b : boolean >{ x: 21 } : { x: number; } @@ -321,9 +321,9 @@ function conditionalSpreadNumber(nt: number): { x: number, y: number } { >16 : 16 o = { ->o = { ...o, ...nt && { x: nt } } : { x: number; y: number; } +>o = { ...o, ...nt && { x: nt } } : { x: number; y: number; } | { x: number; y: number; } >o : { x: number; y: number; } ->{ ...o, ...nt && { x: nt } } : { x: number; y: number; } +>{ ...o, ...nt && { x: nt } } : { x: number; y: number; } | { x: number; y: number; } ...o, >o : { x: number; y: number; } @@ -336,8 +336,8 @@ function conditionalSpreadNumber(nt: number): { x: number, y: number } { >nt : number } let o2 = { ...nt && { x: nt }} ->o2 : { x?: number | undefined; } ->{ ...nt && { x: nt }} : { x?: number | undefined; } +>o2 : {} | { x: number; } +>{ ...nt && { x: nt }} : {} | { x: number; } >nt && { x: nt } : 0 | { x: number; } >nt : number >{ x: nt } : { x: number; } @@ -362,9 +362,9 @@ function conditionalSpreadString(st: string): { x: string, y: number } { >17 : 17 o = { ->o = { ...o, ...st && { x: st } } : { x: string; y: number; } +>o = { ...o, ...st && { x: st } } : { x: string; y: number; } | { x: string; y: number; } >o : { x: string; y: number; } ->{ ...o, ...st && { x: st } } : { x: string; y: number; } +>{ ...o, ...st && { x: st } } : { x: string; y: number; } | { x: string; y: number; } ...o, >o : { x: string; y: number; } @@ -377,8 +377,8 @@ function conditionalSpreadString(st: string): { x: string, y: number } { >st : string } let o2 = { ...st && { x: st }} ->o2 : { x?: string | undefined; } ->{ ...st && { x: st }} : { x?: string | undefined; } +>o2 : {} | { x: string; } +>{ ...st && { x: st }} : {} | { x: string; } >st && { x: st } : "" | { x: string; } >st : string >{ x: st } : { x: string; } @@ -571,8 +571,8 @@ let shortCutted: { a: number, b: string } = { ...o, a } // non primitive let spreadNonPrimitive = { ...{}}; ->spreadNonPrimitive : {} ->{ ...{}} : {} +>spreadNonPrimitive : object +>{ ...{}} : object >{} : object >{} : {} diff --git a/tests/baselines/reference/objectSpreadNegative.errors.txt b/tests/baselines/reference/objectSpreadNegative.errors.txt index 92225755c71..5b78f10f281 100644 --- a/tests/baselines/reference/objectSpreadNegative.errors.txt +++ b/tests/baselines/reference/objectSpreadNegative.errors.txt @@ -15,7 +15,7 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(38,19): error TS269 tests/cases/conformance/types/spread/objectSpreadNegative.ts(43,1): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type '{}' has no compatible call signatures. tests/cases/conformance/types/spread/objectSpreadNegative.ts(47,12): error TS2339: Property 'b' does not exist on type '{}'. 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(58,11): error TS2339: Property 'a' does not exist on type 'object'. 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'. @@ -117,7 +117,7 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(84,7): error TS2322 let spreadObj = { ...obj }; spreadObj.a; // error 'a' is not in {} ~ -!!! error TS2339: Property 'a' does not exist on type '{}'. +!!! error TS2339: Property 'a' does not exist on type 'object'. // generics function f(t: T, u: U) { diff --git a/tests/baselines/reference/spreadUnion2.js b/tests/baselines/reference/spreadUnion2.js index 662b7cd3e46..0ae63266da3 100644 --- a/tests/baselines/reference/spreadUnion2.js +++ b/tests/baselines/reference/spreadUnion2.js @@ -2,20 +2,20 @@ declare const undefinedUnion: { a: number } | undefined; declare const nullUnion: { b: number } | null; -var o1: { a?: number | undefined }; +var o1: {} | { a: number }; var o1 = { ...undefinedUnion }; -var o2: { b?: number | undefined }; +var o2: {} | { b: number }; var o2 = { ...nullUnion }; -var o3: { a?: number | undefined, b?: number | undefined }; +var o3: {} | { a: number } | { b: number } | { a: number, b: number }; var o3 = { ...undefinedUnion, ...nullUnion }; var o3 = { ...nullUnion, ...undefinedUnion }; -var o4: { a?: number | undefined }; +var o4: {} | { a: number }; var o4 = { ...undefinedUnion, ...undefinedUnion }; -var o5: { b?: number | undefined }; +var o5: {} | { b: number }; var o5 = { ...nullUnion, ...nullUnion }; diff --git a/tests/baselines/reference/spreadUnion2.symbols b/tests/baselines/reference/spreadUnion2.symbols index 2cc91f2980b..72e373d862d 100644 --- a/tests/baselines/reference/spreadUnion2.symbols +++ b/tests/baselines/reference/spreadUnion2.symbols @@ -7,26 +7,28 @@ declare const nullUnion: { b: number } | null; >nullUnion : Symbol(nullUnion, Decl(spreadUnion2.ts, 1, 13)) >b : Symbol(b, Decl(spreadUnion2.ts, 1, 26)) -var o1: { a?: number | undefined }; +var o1: {} | { a: number }; >o1 : Symbol(o1, Decl(spreadUnion2.ts, 3, 3), Decl(spreadUnion2.ts, 4, 3)) ->a : Symbol(a, Decl(spreadUnion2.ts, 3, 9)) +>a : Symbol(a, Decl(spreadUnion2.ts, 3, 14)) var o1 = { ...undefinedUnion }; >o1 : Symbol(o1, Decl(spreadUnion2.ts, 3, 3), Decl(spreadUnion2.ts, 4, 3)) >undefinedUnion : Symbol(undefinedUnion, Decl(spreadUnion2.ts, 0, 13)) -var o2: { b?: number | undefined }; +var o2: {} | { b: number }; >o2 : Symbol(o2, Decl(spreadUnion2.ts, 6, 3), Decl(spreadUnion2.ts, 7, 3)) ->b : Symbol(b, Decl(spreadUnion2.ts, 6, 9)) +>b : Symbol(b, Decl(spreadUnion2.ts, 6, 14)) var o2 = { ...nullUnion }; >o2 : Symbol(o2, Decl(spreadUnion2.ts, 6, 3), Decl(spreadUnion2.ts, 7, 3)) >nullUnion : Symbol(nullUnion, Decl(spreadUnion2.ts, 1, 13)) -var o3: { a?: number | undefined, b?: number | undefined }; +var o3: {} | { a: number } | { b: number } | { a: number, b: number }; >o3 : Symbol(o3, Decl(spreadUnion2.ts, 9, 3), Decl(spreadUnion2.ts, 10, 3), Decl(spreadUnion2.ts, 11, 3)) ->a : Symbol(a, Decl(spreadUnion2.ts, 9, 9)) ->b : Symbol(b, Decl(spreadUnion2.ts, 9, 33)) +>a : Symbol(a, Decl(spreadUnion2.ts, 9, 14)) +>b : Symbol(b, Decl(spreadUnion2.ts, 9, 30)) +>a : Symbol(a, Decl(spreadUnion2.ts, 9, 46)) +>b : Symbol(b, Decl(spreadUnion2.ts, 9, 57)) var o3 = { ...undefinedUnion, ...nullUnion }; >o3 : Symbol(o3, Decl(spreadUnion2.ts, 9, 3), Decl(spreadUnion2.ts, 10, 3), Decl(spreadUnion2.ts, 11, 3)) @@ -38,18 +40,18 @@ var o3 = { ...nullUnion, ...undefinedUnion }; >nullUnion : Symbol(nullUnion, Decl(spreadUnion2.ts, 1, 13)) >undefinedUnion : Symbol(undefinedUnion, Decl(spreadUnion2.ts, 0, 13)) -var o4: { a?: number | undefined }; +var o4: {} | { a: number }; >o4 : Symbol(o4, Decl(spreadUnion2.ts, 13, 3), Decl(spreadUnion2.ts, 14, 3)) ->a : Symbol(a, Decl(spreadUnion2.ts, 13, 9)) +>a : Symbol(a, Decl(spreadUnion2.ts, 13, 14)) var o4 = { ...undefinedUnion, ...undefinedUnion }; >o4 : Symbol(o4, Decl(spreadUnion2.ts, 13, 3), Decl(spreadUnion2.ts, 14, 3)) >undefinedUnion : Symbol(undefinedUnion, Decl(spreadUnion2.ts, 0, 13)) >undefinedUnion : Symbol(undefinedUnion, Decl(spreadUnion2.ts, 0, 13)) -var o5: { b?: number | undefined }; +var o5: {} | { b: number }; >o5 : Symbol(o5, Decl(spreadUnion2.ts, 16, 3), Decl(spreadUnion2.ts, 17, 3)) ->b : Symbol(b, Decl(spreadUnion2.ts, 16, 9)) +>b : Symbol(b, Decl(spreadUnion2.ts, 16, 14)) var o5 = { ...nullUnion, ...nullUnion }; >o5 : Symbol(o5, Decl(spreadUnion2.ts, 16, 3), Decl(spreadUnion2.ts, 17, 3)) diff --git a/tests/baselines/reference/spreadUnion2.types b/tests/baselines/reference/spreadUnion2.types index ccf587af591..5077949bc97 100644 --- a/tests/baselines/reference/spreadUnion2.types +++ b/tests/baselines/reference/spreadUnion2.types @@ -8,58 +8,60 @@ declare const nullUnion: { b: number } | null; >b : number >null : null -var o1: { a?: number | undefined }; ->o1 : { a?: number | undefined; } ->a : number | undefined +var o1: {} | { a: number }; +>o1 : {} | { a: number; } +>a : number var o1 = { ...undefinedUnion }; ->o1 : { a?: number | undefined; } ->{ ...undefinedUnion } : { a?: number | undefined; } +>o1 : {} | { a: number; } +>{ ...undefinedUnion } : {} | { a: number; } >undefinedUnion : { a: number; } | undefined -var o2: { b?: number | undefined }; ->o2 : { b?: number | undefined; } ->b : number | undefined +var o2: {} | { b: number }; +>o2 : {} | { b: number; } +>b : number var o2 = { ...nullUnion }; ->o2 : { b?: number | undefined; } ->{ ...nullUnion } : { b?: number | undefined; } +>o2 : {} | { b: number; } +>{ ...nullUnion } : {} | { b: number; } >nullUnion : { b: number; } | null -var o3: { a?: number | undefined, b?: number | undefined }; ->o3 : { a?: number | undefined; b?: number | undefined; } ->a : number | undefined ->b : number | undefined +var o3: {} | { a: number } | { b: number } | { a: number, b: number }; +>o3 : {} | { a: number; } | { b: number; } | { a: number; b: number; } +>a : number +>b : number +>a : number +>b : number var o3 = { ...undefinedUnion, ...nullUnion }; ->o3 : { a?: number | undefined; b?: number | undefined; } ->{ ...undefinedUnion, ...nullUnion } : { b?: number | undefined; a?: number | undefined; } +>o3 : {} | { a: number; } | { b: number; } | { a: number; b: number; } +>{ ...undefinedUnion, ...nullUnion } : {} | { b: number; } | { a: number; } | { b: number; a: number; } >undefinedUnion : { a: number; } | undefined >nullUnion : { b: number; } | null var o3 = { ...nullUnion, ...undefinedUnion }; ->o3 : { a?: number | undefined; b?: number | undefined; } ->{ ...nullUnion, ...undefinedUnion } : { a?: number | undefined; b?: number | undefined; } +>o3 : {} | { a: number; } | { b: number; } | { a: number; b: number; } +>{ ...nullUnion, ...undefinedUnion } : {} | { a: number; } | { b: number; } | { a: number; b: number; } >nullUnion : { b: number; } | null >undefinedUnion : { a: number; } | undefined -var o4: { a?: number | undefined }; ->o4 : { a?: number | undefined; } ->a : number | undefined +var o4: {} | { a: number }; +>o4 : {} | { a: number; } +>a : number var o4 = { ...undefinedUnion, ...undefinedUnion }; ->o4 : { a?: number | undefined; } ->{ ...undefinedUnion, ...undefinedUnion } : { a?: number | undefined; } +>o4 : {} | { a: number; } +>{ ...undefinedUnion, ...undefinedUnion } : {} | { a: number; } | { a: number; } | { a: number; } >undefinedUnion : { a: number; } | undefined >undefinedUnion : { a: number; } | undefined -var o5: { b?: number | undefined }; ->o5 : { b?: number | undefined; } ->b : number | undefined +var o5: {} | { b: number }; +>o5 : {} | { b: number; } +>b : number var o5 = { ...nullUnion, ...nullUnion }; ->o5 : { b?: number | undefined; } ->{ ...nullUnion, ...nullUnion } : { b?: number | undefined; } +>o5 : {} | { b: number; } +>{ ...nullUnion, ...nullUnion } : {} | { b: number; } | { b: number; } | { b: number; } >nullUnion : { b: number; } | null >nullUnion : { b: number; } | null diff --git a/tests/baselines/reference/spreadUnion3.errors.txt b/tests/baselines/reference/spreadUnion3.errors.txt index 24d864d96fe..b7c59697946 100644 --- a/tests/baselines/reference/spreadUnion3.errors.txt +++ b/tests/baselines/reference/spreadUnion3.errors.txt @@ -1,9 +1,9 @@ -tests/cases/conformance/types/spread/spreadUnion3.ts(2,5): error TS2322: Type '{ y: string | number; }' is not assignable to type '{ y: string; }'. - Types of property 'y' are incompatible. - Type 'string | number' is not assignable to type 'string'. +tests/cases/conformance/types/spread/spreadUnion3.ts(2,5): error TS2322: Type '{ y: number; } | { y: string; }' is not assignable to type '{ y: string; }'. + Type '{ y: number; }' is not assignable to type '{ y: string; }'. + Types of property 'y' are incompatible. Type 'number' is not assignable to type 'string'. -tests/cases/conformance/types/spread/spreadUnion3.ts(9,9): error TS2322: Type 'number | undefined' is not assignable to type 'number'. - Type 'undefined' is not assignable to type 'number'. +tests/cases/conformance/types/spread/spreadUnion3.ts(9,23): error TS2339: Property 'a' does not exist on type '{} | {} | { a: number; }'. + Property 'a' does not exist on type '{}'. tests/cases/conformance/types/spread/spreadUnion3.ts(17,11): error TS2698: Spread types may only be created from object types. tests/cases/conformance/types/spread/spreadUnion3.ts(18,11): error TS2698: Spread types may only be created from object types. @@ -12,9 +12,9 @@ tests/cases/conformance/types/spread/spreadUnion3.ts(18,11): error TS2698: Sprea function f(x: { y: string } | undefined): { y: string } { return { y: 123, ...x } // y: string | number ~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2322: Type '{ y: string | number; }' is not assignable to type '{ y: string; }'. -!!! error TS2322: Types of property 'y' are incompatible. -!!! error TS2322: Type 'string | number' is not assignable to type 'string'. +!!! error TS2322: Type '{ y: number; } | { y: string; }' is not assignable to type '{ y: string; }'. +!!! error TS2322: Type '{ y: number; }' is not assignable to type '{ y: string; }'. +!!! error TS2322: Types of property 'y' are incompatible. !!! error TS2322: Type 'number' is not assignable to type 'string'. } f(undefined) @@ -23,9 +23,9 @@ tests/cases/conformance/types/spread/spreadUnion3.ts(18,11): error TS2698: Sprea function g(t?: { a: number } | null): void { let b = { ...t }; let c: number = b.a; // might not have 'a' - ~ -!!! error TS2322: Type 'number | undefined' is not assignable to type 'number'. -!!! error TS2322: Type 'undefined' is not assignable to type 'number'. + ~ +!!! error TS2339: Property 'a' does not exist on type '{} | {} | { a: number; }'. +!!! error TS2339: Property 'a' does not exist on type '{}'. } g() g(undefined) diff --git a/tests/cases/conformance/types/spread/spreadUnion2.ts b/tests/cases/conformance/types/spread/spreadUnion2.ts index 549441be411..5fbca1d4bf2 100644 --- a/tests/cases/conformance/types/spread/spreadUnion2.ts +++ b/tests/cases/conformance/types/spread/spreadUnion2.ts @@ -3,19 +3,19 @@ declare const undefinedUnion: { a: number } | undefined; declare const nullUnion: { b: number } | null; -var o1: { a?: number | undefined }; +var o1: {} | { a: number }; var o1 = { ...undefinedUnion }; -var o2: { b?: number | undefined }; +var o2: {} | { b: number }; var o2 = { ...nullUnion }; -var o3: { a?: number | undefined, b?: number | undefined }; +var o3: {} | { a: number } | { b: number } | { a: number, b: number }; var o3 = { ...undefinedUnion, ...nullUnion }; var o3 = { ...nullUnion, ...undefinedUnion }; -var o4: { a?: number | undefined }; +var o4: {} | { a: number }; var o4 = { ...undefinedUnion, ...undefinedUnion }; -var o5: { b?: number | undefined }; +var o5: {} | { b: number }; var o5 = { ...nullUnion, ...nullUnion };