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