diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index a5f1515b94a..c751c37c6d5 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -13597,6 +13597,9 @@ namespace ts { // union includes empty object types (e.g. reducing {} | string to just {}). return getUnionType(widenedTypes, some(widenedTypes, isEmptyObjectType) ? UnionReduction.Subtype : UnionReduction.Literal); } + if (type.flags & TypeFlags.Intersection) { + return getIntersectionType(sameMap((type).types, getWidenedType)); + } if (isArrayType(type) || isTupleType(type)) { return createTypeReference((type).target, sameMap((type).typeArguments, getWidenedType)); } diff --git a/tests/baselines/reference/literalTypeWidening.js b/tests/baselines/reference/literalTypeWidening.js index fc805ac6706..93655fe0fc9 100644 --- a/tests/baselines/reference/literalTypeWidening.js +++ b/tests/baselines/reference/literalTypeWidening.js @@ -128,11 +128,38 @@ export type LangCode = keyof typeof langCodeSet export const langCodes = keys(langCodeSet) const arr: Obj[] = langCodes.map(code => ({ code })) + +// Repro from #29081 + +function test(obj: T): T { + let { a, ...rest } = obj; + return { a: 'hello', ...rest } as T; +} //// [literalTypeWidening.js] "use strict"; // Widening vs. non-widening literal types +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +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; +}; exports.__esModule = true; function f1() { var c1 = "hello"; // Widening type "hello" @@ -233,3 +260,8 @@ exports.keys = keys; var langCodeSet = Set('fr', 'en', 'es', 'it', 'nl'); exports.langCodes = keys(langCodeSet); var arr = exports.langCodes.map(function (code) { return ({ code: code }); }); +// Repro from #29081 +function test(obj) { + var a = obj.a, rest = __rest(obj, ["a"]); + return __assign({ a: 'hello' }, rest); +} diff --git a/tests/baselines/reference/literalTypeWidening.symbols b/tests/baselines/reference/literalTypeWidening.symbols index 09b9164c199..4ce9c9a9468 100644 --- a/tests/baselines/reference/literalTypeWidening.symbols +++ b/tests/baselines/reference/literalTypeWidening.symbols @@ -400,3 +400,25 @@ const arr: Obj[] = langCodes.map(code => ({ code })) >code : Symbol(code, Decl(literalTypeWidening.ts, 128, 33)) >code : Symbol(code, Decl(literalTypeWidening.ts, 128, 43)) +// Repro from #29081 + +function test(obj: T): T { +>test : Symbol(test, Decl(literalTypeWidening.ts, 128, 52)) +>T : Symbol(T, Decl(literalTypeWidening.ts, 132, 14)) +>a : Symbol(a, Decl(literalTypeWidening.ts, 132, 25)) +>b : Symbol(b, Decl(literalTypeWidening.ts, 132, 36)) +>obj : Symbol(obj, Decl(literalTypeWidening.ts, 132, 50)) +>T : Symbol(T, Decl(literalTypeWidening.ts, 132, 14)) +>T : Symbol(T, Decl(literalTypeWidening.ts, 132, 14)) + + let { a, ...rest } = obj; +>a : Symbol(a, Decl(literalTypeWidening.ts, 133, 9)) +>rest : Symbol(rest, Decl(literalTypeWidening.ts, 133, 12)) +>obj : Symbol(obj, Decl(literalTypeWidening.ts, 132, 50)) + + return { a: 'hello', ...rest } as T; +>a : Symbol(a, Decl(literalTypeWidening.ts, 134, 12)) +>rest : Symbol(rest, Decl(literalTypeWidening.ts, 133, 12)) +>T : Symbol(T, Decl(literalTypeWidening.ts, 132, 14)) +} + diff --git a/tests/baselines/reference/literalTypeWidening.types b/tests/baselines/reference/literalTypeWidening.types index 51813d726f1..a96ddc8c5da 100644 --- a/tests/baselines/reference/literalTypeWidening.types +++ b/tests/baselines/reference/literalTypeWidening.types @@ -433,3 +433,24 @@ const arr: Obj[] = langCodes.map(code => ({ code })) >{ code } : { code: "fr" | "en" | "es" | "it" | "nl"; } >code : "fr" | "en" | "es" | "it" | "nl" +// Repro from #29081 + +function test(obj: T): T { +>test : (obj: T) => T +>a : string +>b : string +>obj : T + + let { a, ...rest } = obj; +>a : string +>rest : Pick> +>obj : T + + return { a: 'hello', ...rest } as T; +>{ a: 'hello', ...rest } as T : T +>{ a: 'hello', ...rest } : { a: string; } & Pick> +>a : string +>'hello' : "hello" +>rest : Pick> +} + diff --git a/tests/cases/conformance/types/literal/literalTypeWidening.ts b/tests/cases/conformance/types/literal/literalTypeWidening.ts index 4c818793142..17daedb3b0e 100644 --- a/tests/cases/conformance/types/literal/literalTypeWidening.ts +++ b/tests/cases/conformance/types/literal/literalTypeWidening.ts @@ -127,3 +127,10 @@ export type LangCode = keyof typeof langCodeSet export const langCodes = keys(langCodeSet) const arr: Obj[] = langCodes.map(code => ({ code })) + +// Repro from #29081 + +function test(obj: T): T { + let { a, ...rest } = obj; + return { a: 'hello', ...rest } as T; +}