Skip to content

Commit 8ac18be

Browse files
authored
Merge pull request #29082 from Microsoft/widenIntersectionTypes
Properly widen intersection types
2 parents 4e3bc9e + 7c2f4b3 commit 8ac18be

File tree

5 files changed

+85
-0
lines changed

5 files changed

+85
-0
lines changed

src/compiler/checker.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13597,6 +13597,9 @@ namespace ts {
1359713597
// union includes empty object types (e.g. reducing {} | string to just {}).
1359813598
return getUnionType(widenedTypes, some(widenedTypes, isEmptyObjectType) ? UnionReduction.Subtype : UnionReduction.Literal);
1359913599
}
13600+
if (type.flags & TypeFlags.Intersection) {
13601+
return getIntersectionType(sameMap((<IntersectionType>type).types, getWidenedType));
13602+
}
1360013603
if (isArrayType(type) || isTupleType(type)) {
1360113604
return createTypeReference((<TypeReference>type).target, sameMap((<TypeReference>type).typeArguments, getWidenedType));
1360213605
}

tests/baselines/reference/literalTypeWidening.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,11 +128,38 @@ export type LangCode = keyof typeof langCodeSet
128128
export const langCodes = keys(langCodeSet)
129129

130130
const arr: Obj[] = langCodes.map(code => ({ code }))
131+
132+
// Repro from #29081
133+
134+
function test<T extends { a: string, b: string }>(obj: T): T {
135+
let { a, ...rest } = obj;
136+
return { a: 'hello', ...rest } as T;
137+
}
131138

132139

133140
//// [literalTypeWidening.js]
134141
"use strict";
135142
// Widening vs. non-widening literal types
143+
var __assign = (this && this.__assign) || function () {
144+
__assign = Object.assign || function(t) {
145+
for (var s, i = 1, n = arguments.length; i < n; i++) {
146+
s = arguments[i];
147+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
148+
t[p] = s[p];
149+
}
150+
return t;
151+
};
152+
return __assign.apply(this, arguments);
153+
};
154+
var __rest = (this && this.__rest) || function (s, e) {
155+
var t = {};
156+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
157+
t[p] = s[p];
158+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
159+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0)
160+
t[p[i]] = s[p[i]];
161+
return t;
162+
};
136163
exports.__esModule = true;
137164
function f1() {
138165
var c1 = "hello"; // Widening type "hello"
@@ -233,3 +260,8 @@ exports.keys = keys;
233260
var langCodeSet = Set('fr', 'en', 'es', 'it', 'nl');
234261
exports.langCodes = keys(langCodeSet);
235262
var arr = exports.langCodes.map(function (code) { return ({ code: code }); });
263+
// Repro from #29081
264+
function test(obj) {
265+
var a = obj.a, rest = __rest(obj, ["a"]);
266+
return __assign({ a: 'hello' }, rest);
267+
}

tests/baselines/reference/literalTypeWidening.symbols

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,3 +400,25 @@ const arr: Obj[] = langCodes.map(code => ({ code }))
400400
>code : Symbol(code, Decl(literalTypeWidening.ts, 128, 33))
401401
>code : Symbol(code, Decl(literalTypeWidening.ts, 128, 43))
402402

403+
// Repro from #29081
404+
405+
function test<T extends { a: string, b: string }>(obj: T): T {
406+
>test : Symbol(test, Decl(literalTypeWidening.ts, 128, 52))
407+
>T : Symbol(T, Decl(literalTypeWidening.ts, 132, 14))
408+
>a : Symbol(a, Decl(literalTypeWidening.ts, 132, 25))
409+
>b : Symbol(b, Decl(literalTypeWidening.ts, 132, 36))
410+
>obj : Symbol(obj, Decl(literalTypeWidening.ts, 132, 50))
411+
>T : Symbol(T, Decl(literalTypeWidening.ts, 132, 14))
412+
>T : Symbol(T, Decl(literalTypeWidening.ts, 132, 14))
413+
414+
let { a, ...rest } = obj;
415+
>a : Symbol(a, Decl(literalTypeWidening.ts, 133, 9))
416+
>rest : Symbol(rest, Decl(literalTypeWidening.ts, 133, 12))
417+
>obj : Symbol(obj, Decl(literalTypeWidening.ts, 132, 50))
418+
419+
return { a: 'hello', ...rest } as T;
420+
>a : Symbol(a, Decl(literalTypeWidening.ts, 134, 12))
421+
>rest : Symbol(rest, Decl(literalTypeWidening.ts, 133, 12))
422+
>T : Symbol(T, Decl(literalTypeWidening.ts, 132, 14))
423+
}
424+

tests/baselines/reference/literalTypeWidening.types

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,3 +433,24 @@ const arr: Obj[] = langCodes.map(code => ({ code }))
433433
>{ code } : { code: "fr" | "en" | "es" | "it" | "nl"; }
434434
>code : "fr" | "en" | "es" | "it" | "nl"
435435

436+
// Repro from #29081
437+
438+
function test<T extends { a: string, b: string }>(obj: T): T {
439+
>test : <T extends { a: string; b: string; }>(obj: T) => T
440+
>a : string
441+
>b : string
442+
>obj : T
443+
444+
let { a, ...rest } = obj;
445+
>a : string
446+
>rest : Pick<T, Exclude<keyof T, "a">>
447+
>obj : T
448+
449+
return { a: 'hello', ...rest } as T;
450+
>{ a: 'hello', ...rest } as T : T
451+
>{ a: 'hello', ...rest } : { a: string; } & Pick<T, Exclude<keyof T, "a">>
452+
>a : string
453+
>'hello' : "hello"
454+
>rest : Pick<T, Exclude<keyof T, "a">>
455+
}
456+

tests/cases/conformance/types/literal/literalTypeWidening.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,3 +127,10 @@ export type LangCode = keyof typeof langCodeSet
127127
export const langCodes = keys(langCodeSet)
128128

129129
const arr: Obj[] = langCodes.map(code => ({ code }))
130+
131+
// Repro from #29081
132+
133+
function test<T extends { a: string, b: string }>(obj: T): T {
134+
let { a, ...rest } = obj;
135+
return { a: 'hello', ...rest } as T;
136+
}

0 commit comments

Comments
 (0)