From 74e3ad97358ffc6fcb6063d3aba72456231f7751 Mon Sep 17 00:00:00 2001 From: Oleksandr T Date: Sun, 21 Feb 2021 12:05:26 +0200 Subject: [PATCH] fix(42339): skip return if spread type is wrong --- src/compiler/checker.ts | 23 ++++++--- .../reference/spreadUnion3.errors.txt | 5 +- .../reference/unusedImportWithSpread.js | 44 ++++++++++++++++ .../reference/unusedImportWithSpread.symbols | 38 ++++++++++++++ .../reference/unusedImportWithSpread.types | 50 +++++++++++++++++++ .../cases/compiler/unusedImportWithSpread.ts | 24 +++++++++ 6 files changed, 176 insertions(+), 8 deletions(-) create mode 100644 tests/baselines/reference/unusedImportWithSpread.js create mode 100644 tests/baselines/reference/unusedImportWithSpread.symbols create mode 100644 tests/baselines/reference/unusedImportWithSpread.types create mode 100644 tests/cases/compiler/unusedImportWithSpread.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 7c7fab73585..f1fbd71fdf1 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -25318,15 +25318,20 @@ namespace ts { hasComputedNumberProperty = false; } const type = getReducedType(checkExpression(memberDecl.expression)); - if (!isValidSpreadType(type)) { + if (isValidSpreadType(type)) { + if (allPropertiesTable) { + checkSpreadPropOverrides(type, allPropertiesTable, memberDecl); + } + offset = propertiesArray.length; + if (spread === errorType) { + continue; + } + spread = getSpreadType(spread, type, node.symbol, objectFlags, inConstContext); + } + else { error(memberDecl, Diagnostics.Spread_types_may_only_be_created_from_object_types); - return errorType; + spread = errorType; } - if (allPropertiesTable) { - checkSpreadPropOverrides(type, allPropertiesTable, memberDecl); - } - spread = getSpreadType(spread, type, node.symbol, objectFlags, inConstContext); - offset = propertiesArray.length; continue; } else { @@ -25375,6 +25380,10 @@ namespace ts { } } + if (spread === errorType) { + return errorType; + } + if (spread !== emptyObjectType) { if (propertiesArray.length > 0) { spread = getSpreadType(spread, createObjectLiteralType(), node.symbol, objectFlags, inConstContext); diff --git a/tests/baselines/reference/spreadUnion3.errors.txt b/tests/baselines/reference/spreadUnion3.errors.txt index 231c04d1d99..6d5aaad7b3e 100644 --- a/tests/baselines/reference/spreadUnion3.errors.txt +++ b/tests/baselines/reference/spreadUnion3.errors.txt @@ -2,10 +2,11 @@ tests/cases/conformance/types/spread/spreadUnion3.ts(2,14): error TS2322: 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(17,37): 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 (4 errors) ==== +==== tests/cases/conformance/types/spread/spreadUnion3.ts (5 errors) ==== function f(x: { y: string } | undefined): { y: string } { return { y: 123, ...x } // y: string | number ~ @@ -30,6 +31,8 @@ tests/cases/conformance/types/spread/spreadUnion3.ts(18,11): error TS2698: Sprea declare const nullAndUndefinedUnion: null | undefined; var x = { ...nullAndUndefinedUnion, ...nullAndUndefinedUnion }; ~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2698: Spread types may only be created from object types. + ~~~~~~~~~~~~~~~~~~~~~~~~ !!! error TS2698: Spread types may only be created from object types. var y = { ...nullAndUndefinedUnion }; ~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/tests/baselines/reference/unusedImportWithSpread.js b/tests/baselines/reference/unusedImportWithSpread.js new file mode 100644 index 00000000000..3e52c0f7446 --- /dev/null +++ b/tests/baselines/reference/unusedImportWithSpread.js @@ -0,0 +1,44 @@ +//// [tests/cases/compiler/unusedImportWithSpread.ts] //// + +//// [a.ts] +export default { a: 1 }; + +//// [b1.ts] +import a from "./a"; + +const b1 = {} as unknown; +({ + // @ts-ignore + ...b1, + a +}) + +//// [b2.ts] +import a from "./a"; + +const b2 = {} as never; +({ + // @ts-ignore + ...b2, + a +}) + + +//// [a.js] +export default { a: 1 }; +//// [b1.js] +import a from "./a"; +const b1 = {}; +({ + // @ts-ignore + ...b1, + a +}); +//// [b2.js] +import a from "./a"; +const b2 = {}; +({ + // @ts-ignore + ...b2, + a +}); diff --git a/tests/baselines/reference/unusedImportWithSpread.symbols b/tests/baselines/reference/unusedImportWithSpread.symbols new file mode 100644 index 00000000000..2fcff0e6adc --- /dev/null +++ b/tests/baselines/reference/unusedImportWithSpread.symbols @@ -0,0 +1,38 @@ +=== tests/cases/compiler/a.ts === +export default { a: 1 }; +>a : Symbol(a, Decl(a.ts, 0, 16)) + +=== tests/cases/compiler/b1.ts === +import a from "./a"; +>a : Symbol(a, Decl(b1.ts, 0, 6)) + +const b1 = {} as unknown; +>b1 : Symbol(b1, Decl(b1.ts, 2, 5)) + +({ + // @ts-ignore + ...b1, +>b1 : Symbol(b1, Decl(b1.ts, 2, 5)) + + a +>a : Symbol(a, Decl(b1.ts, 5, 10)) + +}) + +=== tests/cases/compiler/b2.ts === +import a from "./a"; +>a : Symbol(a, Decl(b2.ts, 0, 6)) + +const b2 = {} as never; +>b2 : Symbol(b2, Decl(b2.ts, 2, 5)) + +({ + // @ts-ignore + ...b2, +>b2 : Symbol(b2, Decl(b2.ts, 2, 5)) + + a +>a : Symbol(a, Decl(b2.ts, 5, 10)) + +}) + diff --git a/tests/baselines/reference/unusedImportWithSpread.types b/tests/baselines/reference/unusedImportWithSpread.types new file mode 100644 index 00000000000..16cf33f8163 --- /dev/null +++ b/tests/baselines/reference/unusedImportWithSpread.types @@ -0,0 +1,50 @@ +=== tests/cases/compiler/a.ts === +export default { a: 1 }; +>{ a: 1 } : { a: number; } +>a : number +>1 : 1 + +=== tests/cases/compiler/b1.ts === +import a from "./a"; +>a : { a: number; } + +const b1 = {} as unknown; +>b1 : unknown +>{} as unknown : unknown +>{} : {} + +({ +>({ // @ts-ignore ...b1, a}) : error +>{ // @ts-ignore ...b1, a} : error + + // @ts-ignore + ...b1, +>b1 : unknown + + a +>a : { a: number; } + +}) + +=== tests/cases/compiler/b2.ts === +import a from "./a"; +>a : { a: number; } + +const b2 = {} as never; +>b2 : never +>{} as never : never +>{} : {} + +({ +>({ // @ts-ignore ...b2, a}) : error +>{ // @ts-ignore ...b2, a} : error + + // @ts-ignore + ...b2, +>b2 : never + + a +>a : { a: number; } + +}) + diff --git a/tests/cases/compiler/unusedImportWithSpread.ts b/tests/cases/compiler/unusedImportWithSpread.ts new file mode 100644 index 00000000000..2986b592b7b --- /dev/null +++ b/tests/cases/compiler/unusedImportWithSpread.ts @@ -0,0 +1,24 @@ +// @target: esnext + +// @filename: a.ts +export default { a: 1 }; + +// @filename: b1.ts +import a from "./a"; + +const b1 = {} as unknown; +({ + // @ts-ignore + ...b1, + a +}) + +// @filename: b2.ts +import a from "./a"; + +const b2 = {} as never; +({ + // @ts-ignore + ...b2, + a +})