diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index dde8033d1e976..e4ea3740a62f6 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7640,11 +7640,11 @@ namespace ts { if (members.has(leftProp.name)) { const rightProp = members.get(leftProp.name); const rightType = getTypeOfSymbol(rightProp); - if (maybeTypeOfKind(rightType, TypeFlags.Undefined) || rightProp.flags & SymbolFlags.Optional) { + if (rightProp.flags & SymbolFlags.Optional) { const declarations: Declaration[] = concatenate(leftProp.declarations, rightProp.declarations); const flags = SymbolFlags.Property | (leftProp.flags & SymbolFlags.Optional); const result = createSymbol(flags, leftProp.name); - result.type = getUnionType([getTypeOfSymbol(leftProp), getTypeWithFacts(rightType, TypeFacts.NEUndefined)]); + result.type = getUnionType([getTypeOfSymbol(leftProp), rightType]); result.leftSpread = leftProp; result.rightSpread = rightProp; result.declarations = declarations; diff --git a/tests/baselines/reference/objectSpreadStrictNull.errors.txt b/tests/baselines/reference/objectSpreadStrictNull.errors.txt new file mode 100644 index 0000000000000..f3c5cc7de25b0 --- /dev/null +++ b/tests/baselines/reference/objectSpreadStrictNull.errors.txt @@ -0,0 +1,84 @@ +tests/cases/conformance/types/spread/objectSpreadStrictNull.ts(9,9): error TS2322: Type '{ sn: string | number | undefined; }' is not assignable to type '{ sn: string | number; }'. + Types of property 'sn' are incompatible. + Type 'string | number | undefined' is not assignable to type 'string | number'. + Type 'undefined' is not assignable to type 'string | number'. +tests/cases/conformance/types/spread/objectSpreadStrictNull.ts(10,9): error TS2322: Type '{ sn: string | number | undefined; }' is not assignable to type '{ sn: string | number; }'. + Types of property 'sn' are incompatible. + Type 'string | number | undefined' is not assignable to type 'string | number'. + Type 'undefined' is not assignable to type 'string | number'. +tests/cases/conformance/types/spread/objectSpreadStrictNull.ts(14,9): error TS2322: Type '{ sn: number | undefined; }' is not assignable to type '{ sn: string | number; }'. + Types of property 'sn' are incompatible. + Type 'number | undefined' is not assignable to type 'string | number'. + Type 'undefined' is not assignable to type 'string | number'. +tests/cases/conformance/types/spread/objectSpreadStrictNull.ts(15,9): error TS2322: Type '{ sn: number | undefined; }' is not assignable to type '{ sn: string | number; }'. + Types of property 'sn' are incompatible. + Type 'number | undefined' is not assignable to type 'string | number'. + Type 'undefined' is not assignable to type 'string | number'. +tests/cases/conformance/types/spread/objectSpreadStrictNull.ts(18,9): error TS2322: Type '{ sn: string | number | undefined; }' is not assignable to type '{ sn: string | number | boolean; }'. + Types of property 'sn' are incompatible. + Type 'string | number | undefined' is not assignable to type 'string | number | boolean'. + Type 'undefined' is not assignable to type 'string | number | boolean'. +tests/cases/conformance/types/spread/objectSpreadStrictNull.ts(28,7): error TS2322: Type '{ title: undefined; yearReleased: number; }' is not assignable to type 'Movie'. + Types of property 'title' are incompatible. + Type 'undefined' is not assignable to type 'string'. + + +==== tests/cases/conformance/types/spread/objectSpreadStrictNull.ts (6 errors) ==== + function f( + definiteBoolean: { sn: boolean }, + definiteString: { sn: string }, + optionalString: { sn?: string }, + optionalNumber: { sn?: number }, + undefinedString: { sn: string | undefined }, + undefinedNumber: { sn: number | undefined }) { + // optional + let optionalUnionStops: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...optionalNumber }; + ~~~~~~~~~~~~~~~~~~ +!!! error TS2322: Type '{ sn: string | number | undefined; }' is not assignable to type '{ sn: string | number; }'. +!!! error TS2322: Types of property 'sn' are incompatible. +!!! error TS2322: Type 'string | number | undefined' is not assignable to type 'string | number'. +!!! error TS2322: Type 'undefined' is not assignable to type 'string | number'. + let optionalUnionDuplicates: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...optionalString, ...optionalNumber }; + ~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2322: Type '{ sn: string | number | undefined; }' is not assignable to type '{ sn: string | number; }'. +!!! error TS2322: Types of property 'sn' are incompatible. +!!! error TS2322: Type 'string | number | undefined' is not assignable to type 'string | number'. +!!! error TS2322: Type 'undefined' is not assignable to type 'string | number'. + let allOptional: { sn?: string | number } = { ...optionalString, ...optionalNumber }; + + // undefined + let undefinedUnionStops: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...undefinedNumber }; + ~~~~~~~~~~~~~~~~~~~ +!!! error TS2322: Type '{ sn: number | undefined; }' is not assignable to type '{ sn: string | number; }'. +!!! error TS2322: Types of property 'sn' are incompatible. +!!! error TS2322: Type 'number | undefined' is not assignable to type 'string | number'. +!!! error TS2322: Type 'undefined' is not assignable to type 'string | number'. + let undefinedUnionDuplicates: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...undefinedString, ...undefinedNumber }; + ~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2322: Type '{ sn: number | undefined; }' is not assignable to type '{ sn: string | number; }'. +!!! error TS2322: Types of property 'sn' are incompatible. +!!! error TS2322: Type 'number | undefined' is not assignable to type 'string | number'. +!!! error TS2322: Type 'undefined' is not assignable to type 'string | number'. + let allUndefined: { sn: string | number | undefined } = { ...undefinedString, ...undefinedNumber }; + + let undefinedWithOptionalContinues: { sn: string | number | boolean } = { ...definiteBoolean, ...undefinedString, ...optionalNumber }; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2322: Type '{ sn: string | number | undefined; }' is not assignable to type '{ sn: string | number | boolean; }'. +!!! error TS2322: Types of property 'sn' are incompatible. +!!! error TS2322: Type 'string | number | undefined' is not assignable to type 'string | number | boolean'. +!!! error TS2322: Type 'undefined' is not assignable to type 'string | number | boolean'. + } + + type Movie = { + title: string; + yearReleased: number; + } + + const m = { title: "The Matrix", yearReleased: 1999 }; + // should error here because title: undefined is not assignable to string + const x: Movie = { ...m, title: undefined }; + ~ +!!! error TS2322: Type '{ title: undefined; yearReleased: number; }' is not assignable to type 'Movie'. +!!! error TS2322: Types of property 'title' are incompatible. +!!! error TS2322: Type 'undefined' is not assignable to type 'string'. + \ No newline at end of file diff --git a/tests/baselines/reference/objectSpreadStrictNull.js b/tests/baselines/reference/objectSpreadStrictNull.js index 8a4cf0e5f9fc6..a21b5e2467cc7 100644 --- a/tests/baselines/reference/objectSpreadStrictNull.js +++ b/tests/baselines/reference/objectSpreadStrictNull.js @@ -18,6 +18,15 @@ function f( let undefinedWithOptionalContinues: { sn: string | number | boolean } = { ...definiteBoolean, ...undefinedString, ...optionalNumber }; } + +type Movie = { + title: string; + yearReleased: number; +} + +const m = { title: "The Matrix", yearReleased: 1999 }; +// should error here because title: undefined is not assignable to string +const x: Movie = { ...m, title: undefined }; //// [objectSpreadStrictNull.js] @@ -40,3 +49,6 @@ function f(definiteBoolean, definiteString, optionalString, optionalNumber, unde var allUndefined = __assign({}, undefinedString, undefinedNumber); var undefinedWithOptionalContinues = __assign({}, definiteBoolean, undefinedString, optionalNumber); } +var m = { title: "The Matrix", yearReleased: 1999 }; +// should error here because title: undefined is not assignable to string +var x = __assign({}, m, { title: undefined }); diff --git a/tests/baselines/reference/objectSpreadStrictNull.symbols b/tests/baselines/reference/objectSpreadStrictNull.symbols deleted file mode 100644 index e9202767945f8..0000000000000 --- a/tests/baselines/reference/objectSpreadStrictNull.symbols +++ /dev/null @@ -1,80 +0,0 @@ -=== tests/cases/conformance/types/spread/objectSpreadStrictNull.ts === -function f( ->f : Symbol(f, Decl(objectSpreadStrictNull.ts, 0, 0)) - - definiteBoolean: { sn: boolean }, ->definiteBoolean : Symbol(definiteBoolean, Decl(objectSpreadStrictNull.ts, 0, 11)) ->sn : Symbol(sn, Decl(objectSpreadStrictNull.ts, 1, 22)) - - definiteString: { sn: string }, ->definiteString : Symbol(definiteString, Decl(objectSpreadStrictNull.ts, 1, 37)) ->sn : Symbol(sn, Decl(objectSpreadStrictNull.ts, 2, 21)) - - optionalString: { sn?: string }, ->optionalString : Symbol(optionalString, Decl(objectSpreadStrictNull.ts, 2, 35)) ->sn : Symbol(sn, Decl(objectSpreadStrictNull.ts, 3, 21)) - - optionalNumber: { sn?: number }, ->optionalNumber : Symbol(optionalNumber, Decl(objectSpreadStrictNull.ts, 3, 36)) ->sn : Symbol(sn, Decl(objectSpreadStrictNull.ts, 4, 21)) - - undefinedString: { sn: string | undefined }, ->undefinedString : Symbol(undefinedString, Decl(objectSpreadStrictNull.ts, 4, 36)) ->sn : Symbol(sn, Decl(objectSpreadStrictNull.ts, 5, 22)) - - undefinedNumber: { sn: number | undefined }) { ->undefinedNumber : Symbol(undefinedNumber, Decl(objectSpreadStrictNull.ts, 5, 48)) ->sn : Symbol(sn, Decl(objectSpreadStrictNull.ts, 6, 22)) - - // optional - let optionalUnionStops: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...optionalNumber }; ->optionalUnionStops : Symbol(optionalUnionStops, Decl(objectSpreadStrictNull.ts, 8, 7)) ->sn : Symbol(sn, Decl(objectSpreadStrictNull.ts, 8, 29)) ->definiteBoolean : Symbol(definiteBoolean, Decl(objectSpreadStrictNull.ts, 0, 11)) ->definiteString : Symbol(definiteString, Decl(objectSpreadStrictNull.ts, 1, 37)) ->optionalNumber : Symbol(optionalNumber, Decl(objectSpreadStrictNull.ts, 3, 36)) - - let optionalUnionDuplicates: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...optionalString, ...optionalNumber }; ->optionalUnionDuplicates : Symbol(optionalUnionDuplicates, Decl(objectSpreadStrictNull.ts, 9, 7)) ->sn : Symbol(sn, Decl(objectSpreadStrictNull.ts, 9, 34)) ->definiteBoolean : Symbol(definiteBoolean, Decl(objectSpreadStrictNull.ts, 0, 11)) ->definiteString : Symbol(definiteString, Decl(objectSpreadStrictNull.ts, 1, 37)) ->optionalString : Symbol(optionalString, Decl(objectSpreadStrictNull.ts, 2, 35)) ->optionalNumber : Symbol(optionalNumber, Decl(objectSpreadStrictNull.ts, 3, 36)) - - let allOptional: { sn?: string | number } = { ...optionalString, ...optionalNumber }; ->allOptional : Symbol(allOptional, Decl(objectSpreadStrictNull.ts, 10, 7)) ->sn : Symbol(sn, Decl(objectSpreadStrictNull.ts, 10, 22)) ->optionalString : Symbol(optionalString, Decl(objectSpreadStrictNull.ts, 2, 35)) ->optionalNumber : Symbol(optionalNumber, Decl(objectSpreadStrictNull.ts, 3, 36)) - - // undefined - let undefinedUnionStops: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...undefinedNumber }; ->undefinedUnionStops : Symbol(undefinedUnionStops, Decl(objectSpreadStrictNull.ts, 13, 7)) ->sn : Symbol(sn, Decl(objectSpreadStrictNull.ts, 13, 30)) ->definiteBoolean : Symbol(definiteBoolean, Decl(objectSpreadStrictNull.ts, 0, 11)) ->definiteString : Symbol(definiteString, Decl(objectSpreadStrictNull.ts, 1, 37)) ->undefinedNumber : Symbol(undefinedNumber, Decl(objectSpreadStrictNull.ts, 5, 48)) - - let undefinedUnionDuplicates: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...undefinedString, ...undefinedNumber }; ->undefinedUnionDuplicates : Symbol(undefinedUnionDuplicates, Decl(objectSpreadStrictNull.ts, 14, 7)) ->sn : Symbol(sn, Decl(objectSpreadStrictNull.ts, 14, 35)) ->definiteBoolean : Symbol(definiteBoolean, Decl(objectSpreadStrictNull.ts, 0, 11)) ->definiteString : Symbol(definiteString, Decl(objectSpreadStrictNull.ts, 1, 37)) ->undefinedString : Symbol(undefinedString, Decl(objectSpreadStrictNull.ts, 4, 36)) ->undefinedNumber : Symbol(undefinedNumber, Decl(objectSpreadStrictNull.ts, 5, 48)) - - let allUndefined: { sn: string | number | undefined } = { ...undefinedString, ...undefinedNumber }; ->allUndefined : Symbol(allUndefined, Decl(objectSpreadStrictNull.ts, 15, 7)) ->sn : Symbol(sn, Decl(objectSpreadStrictNull.ts, 15, 23)) ->undefinedString : Symbol(undefinedString, Decl(objectSpreadStrictNull.ts, 4, 36)) ->undefinedNumber : Symbol(undefinedNumber, Decl(objectSpreadStrictNull.ts, 5, 48)) - - let undefinedWithOptionalContinues: { sn: string | number | boolean } = { ...definiteBoolean, ...undefinedString, ...optionalNumber }; ->undefinedWithOptionalContinues : Symbol(undefinedWithOptionalContinues, Decl(objectSpreadStrictNull.ts, 17, 7)) ->sn : Symbol(sn, Decl(objectSpreadStrictNull.ts, 17, 41)) ->definiteBoolean : Symbol(definiteBoolean, Decl(objectSpreadStrictNull.ts, 0, 11)) ->undefinedString : Symbol(undefinedString, Decl(objectSpreadStrictNull.ts, 4, 36)) ->optionalNumber : Symbol(optionalNumber, Decl(objectSpreadStrictNull.ts, 3, 36)) -} - diff --git a/tests/baselines/reference/objectSpreadStrictNull.types b/tests/baselines/reference/objectSpreadStrictNull.types deleted file mode 100644 index f70f0a9cad26c..0000000000000 --- a/tests/baselines/reference/objectSpreadStrictNull.types +++ /dev/null @@ -1,87 +0,0 @@ -=== tests/cases/conformance/types/spread/objectSpreadStrictNull.ts === -function f( ->f : (definiteBoolean: { sn: boolean; }, definiteString: { sn: string; }, optionalString: { sn?: string | undefined; }, optionalNumber: { sn?: number | undefined; }, undefinedString: { sn: string | undefined; }, undefinedNumber: { sn: number | undefined; }) => void - - definiteBoolean: { sn: boolean }, ->definiteBoolean : { sn: boolean; } ->sn : boolean - - definiteString: { sn: string }, ->definiteString : { sn: string; } ->sn : string - - optionalString: { sn?: string }, ->optionalString : { sn?: string | undefined; } ->sn : string | undefined - - optionalNumber: { sn?: number }, ->optionalNumber : { sn?: number | undefined; } ->sn : number | undefined - - undefinedString: { sn: string | undefined }, ->undefinedString : { sn: string | undefined; } ->sn : string | undefined - - undefinedNumber: { sn: number | undefined }) { ->undefinedNumber : { sn: number | undefined; } ->sn : number | undefined - - // optional - let optionalUnionStops: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...optionalNumber }; ->optionalUnionStops : { sn: string | number; } ->sn : string | number ->{ ...definiteBoolean, ...definiteString, ...optionalNumber } : { sn: string | number; } ->definiteBoolean : { sn: boolean; } ->definiteString : { sn: string; } ->optionalNumber : { sn?: number | undefined; } - - 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 | undefined; } ->optionalNumber : { sn?: number | undefined; } - - 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; } - - // undefined - let undefinedUnionStops: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...undefinedNumber }; ->undefinedUnionStops : { sn: string | number; } ->sn : string | number ->{ ...definiteBoolean, ...definiteString, ...undefinedNumber } : { sn: string | number; } ->definiteBoolean : { sn: boolean; } ->definiteString : { sn: string; } ->undefinedNumber : { sn: number | undefined; } - - let undefinedUnionDuplicates: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...undefinedString, ...undefinedNumber }; ->undefinedUnionDuplicates : { sn: string | number; } ->sn : string | number ->{ ...definiteBoolean, ...definiteString, ...undefinedString, ...undefinedNumber } : { sn: string | number; } ->definiteBoolean : { sn: boolean; } ->definiteString : { sn: string; } ->undefinedString : { sn: string | undefined; } ->undefinedNumber : { sn: number | undefined; } - - let allUndefined: { sn: string | number | undefined } = { ...undefinedString, ...undefinedNumber }; ->allUndefined : { sn: string | number | undefined; } ->sn : string | number | undefined ->{ ...undefinedString, ...undefinedNumber } : { sn: string | number | undefined; } ->undefinedString : { sn: string | undefined; } ->undefinedNumber : { sn: number | undefined; } - - let undefinedWithOptionalContinues: { sn: string | number | boolean } = { ...definiteBoolean, ...undefinedString, ...optionalNumber }; ->undefinedWithOptionalContinues : { sn: string | number | boolean; } ->sn : string | number | boolean ->{ ...definiteBoolean, ...undefinedString, ...optionalNumber } : { sn: string | number | boolean; } ->definiteBoolean : { sn: boolean; } ->undefinedString : { sn: string | undefined; } ->optionalNumber : { sn?: number | undefined; } -} - diff --git a/tests/cases/conformance/types/spread/objectSpreadStrictNull.ts b/tests/cases/conformance/types/spread/objectSpreadStrictNull.ts index 087d47df26c35..979a6feed03bd 100644 --- a/tests/cases/conformance/types/spread/objectSpreadStrictNull.ts +++ b/tests/cases/conformance/types/spread/objectSpreadStrictNull.ts @@ -19,3 +19,12 @@ function f( let undefinedWithOptionalContinues: { sn: string | number | boolean } = { ...definiteBoolean, ...undefinedString, ...optionalNumber }; } + +type Movie = { + title: string; + yearReleased: number; +} + +const m = { title: "The Matrix", yearReleased: 1999 }; +// should error here because title: undefined is not assignable to string +const x: Movie = { ...m, title: undefined };