Skip to content

Commit 952dfc5

Browse files
authored
Exclude generic string-like types from intersection reduction (#57751)
1 parent f9ef943 commit 952dfc5

File tree

4 files changed

+161
-2
lines changed

4 files changed

+161
-2
lines changed

Diff for: src/compiler/checker.ts

+9-2
Original file line numberDiff line numberDiff line change
@@ -17642,7 +17642,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1764217642
const typeVarIndex = typeSet[0].flags & TypeFlags.TypeVariable ? 0 : 1;
1764317643
const typeVariable = typeSet[typeVarIndex];
1764417644
const primitiveType = typeSet[1 - typeVarIndex];
17645-
if (typeVariable.flags & TypeFlags.TypeVariable && (primitiveType.flags & (TypeFlags.Primitive | TypeFlags.NonPrimitive) || includes & TypeFlags.IncludesEmptyObject)) {
17645+
if (
17646+
typeVariable.flags & TypeFlags.TypeVariable &&
17647+
(primitiveType.flags & (TypeFlags.Primitive | TypeFlags.NonPrimitive) && !isGenericStringLikeType(primitiveType) || includes & TypeFlags.IncludesEmptyObject)
17648+
) {
1764617649
// We have an intersection T & P or P & T, where T is a type variable and P is a primitive type, the object type, or {}.
1764717650
const constraint = getBaseConstraintOfType(typeVariable);
1764817651
// Check that T's constraint is similarly composed of primitive types, the object type, or {}.
@@ -18389,6 +18392,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1838918392
!!(type.flags & TypeFlags.StringMapping) && isPatternLiteralPlaceholderType((type as StringMappingType).type);
1839018393
}
1839118394

18395+
function isGenericStringLikeType(type: Type) {
18396+
return !!(type.flags & (TypeFlags.TemplateLiteral | TypeFlags.StringMapping)) && !isPatternLiteralType(type);
18397+
}
18398+
1839218399
function isGenericType(type: Type): boolean {
1839318400
return !!getGenericObjectFlags(type);
1839418401
}
@@ -18417,7 +18424,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1841718424
return (type as SubstitutionType).objectFlags & ObjectFlags.IsGenericType;
1841818425
}
1841918426
return (type.flags & TypeFlags.InstantiableNonPrimitive || isGenericMappedType(type) || isGenericTupleType(type) ? ObjectFlags.IsGenericObjectType : 0) |
18420-
(type.flags & (TypeFlags.InstantiableNonPrimitive | TypeFlags.Index | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) && !isPatternLiteralType(type) ? ObjectFlags.IsGenericIndexType : 0);
18427+
(type.flags & (TypeFlags.InstantiableNonPrimitive | TypeFlags.Index) || isGenericStringLikeType(type) ? ObjectFlags.IsGenericIndexType : 0);
1842118428
}
1842218429

1842318430
function getSimplifiedType(type: Type, writing: boolean): Type {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
//// [tests/cases/compiler/intersectionReductionGenericStringLikeType.ts] ////
2+
3+
=== intersectionReductionGenericStringLikeType.ts ===
4+
// https://github.com/microsoft/TypeScript/issues/57736
5+
6+
type obj = {
7+
>obj : Symbol(obj, Decl(intersectionReductionGenericStringLikeType.ts, 0, 0))
8+
9+
foo: 1;
10+
>foo : Symbol(foo, Decl(intersectionReductionGenericStringLikeType.ts, 2, 12))
11+
12+
bar: 2;
13+
>bar : Symbol(bar, Decl(intersectionReductionGenericStringLikeType.ts, 3, 11))
14+
15+
};
16+
17+
type keyContaining1<
18+
>keyContaining1 : Symbol(keyContaining1, Decl(intersectionReductionGenericStringLikeType.ts, 5, 2))
19+
20+
str extends string,
21+
>str : Symbol(str, Decl(intersectionReductionGenericStringLikeType.ts, 7, 20))
22+
23+
keys extends keyof obj = keyof obj,
24+
>keys : Symbol(keys, Decl(intersectionReductionGenericStringLikeType.ts, 8, 23))
25+
>obj : Symbol(obj, Decl(intersectionReductionGenericStringLikeType.ts, 0, 0))
26+
>obj : Symbol(obj, Decl(intersectionReductionGenericStringLikeType.ts, 0, 0))
27+
28+
> = keys extends infer key extends keyof obj
29+
>keys : Symbol(keys, Decl(intersectionReductionGenericStringLikeType.ts, 8, 23))
30+
>key : Symbol(key, Decl(intersectionReductionGenericStringLikeType.ts, 10, 22))
31+
>obj : Symbol(obj, Decl(intersectionReductionGenericStringLikeType.ts, 0, 0))
32+
33+
? key extends `${string}${str}${string}`
34+
>key : Symbol(key, Decl(intersectionReductionGenericStringLikeType.ts, 10, 22))
35+
>str : Symbol(str, Decl(intersectionReductionGenericStringLikeType.ts, 7, 20))
36+
37+
? obj[key]
38+
>obj : Symbol(obj, Decl(intersectionReductionGenericStringLikeType.ts, 0, 0))
39+
>key : Symbol(key, Decl(intersectionReductionGenericStringLikeType.ts, 10, 22))
40+
41+
: never
42+
: never;
43+
44+
type _1 = keyContaining1<"foo">; // 1
45+
>_1 : Symbol(_1, Decl(intersectionReductionGenericStringLikeType.ts, 14, 12))
46+
>keyContaining1 : Symbol(keyContaining1, Decl(intersectionReductionGenericStringLikeType.ts, 5, 2))
47+
48+
type keyContaining2<
49+
>keyContaining2 : Symbol(keyContaining2, Decl(intersectionReductionGenericStringLikeType.ts, 16, 32))
50+
51+
str extends string,
52+
>str : Symbol(str, Decl(intersectionReductionGenericStringLikeType.ts, 18, 20))
53+
54+
keys extends keyof obj = keyof obj,
55+
>keys : Symbol(keys, Decl(intersectionReductionGenericStringLikeType.ts, 19, 23))
56+
>obj : Symbol(obj, Decl(intersectionReductionGenericStringLikeType.ts, 0, 0))
57+
>obj : Symbol(obj, Decl(intersectionReductionGenericStringLikeType.ts, 0, 0))
58+
59+
> = keys extends keys
60+
>keys : Symbol(keys, Decl(intersectionReductionGenericStringLikeType.ts, 19, 23))
61+
>keys : Symbol(keys, Decl(intersectionReductionGenericStringLikeType.ts, 19, 23))
62+
63+
? keys extends `${string}${str}${string}`
64+
>keys : Symbol(keys, Decl(intersectionReductionGenericStringLikeType.ts, 19, 23))
65+
>str : Symbol(str, Decl(intersectionReductionGenericStringLikeType.ts, 18, 20))
66+
67+
? obj[keys]
68+
>obj : Symbol(obj, Decl(intersectionReductionGenericStringLikeType.ts, 0, 0))
69+
>keys : Symbol(keys, Decl(intersectionReductionGenericStringLikeType.ts, 19, 23))
70+
71+
: never
72+
: never;
73+
74+
type _2 = keyContaining2<"foo">; // 1
75+
>_2 : Symbol(_2, Decl(intersectionReductionGenericStringLikeType.ts, 25, 12))
76+
>keyContaining2 : Symbol(keyContaining2, Decl(intersectionReductionGenericStringLikeType.ts, 16, 32))
77+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
//// [tests/cases/compiler/intersectionReductionGenericStringLikeType.ts] ////
2+
3+
=== intersectionReductionGenericStringLikeType.ts ===
4+
// https://github.com/microsoft/TypeScript/issues/57736
5+
6+
type obj = {
7+
>obj : { foo: 1; bar: 2; }
8+
9+
foo: 1;
10+
>foo : 1
11+
12+
bar: 2;
13+
>bar : 2
14+
15+
};
16+
17+
type keyContaining1<
18+
>keyContaining1 : keyContaining1<str, keys>
19+
20+
str extends string,
21+
keys extends keyof obj = keyof obj,
22+
> = keys extends infer key extends keyof obj
23+
? key extends `${string}${str}${string}`
24+
? obj[key]
25+
: never
26+
: never;
27+
28+
type _1 = keyContaining1<"foo">; // 1
29+
>_1 : 1
30+
31+
type keyContaining2<
32+
>keyContaining2 : keyContaining2<str, keys>
33+
34+
str extends string,
35+
keys extends keyof obj = keyof obj,
36+
> = keys extends keys
37+
? keys extends `${string}${str}${string}`
38+
? obj[keys]
39+
: never
40+
: never;
41+
42+
type _2 = keyContaining2<"foo">; // 1
43+
>_2 : 1
44+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// @strict: true
2+
// @noEmit: true
3+
4+
// https://github.com/microsoft/TypeScript/issues/57736
5+
6+
type obj = {
7+
foo: 1;
8+
bar: 2;
9+
};
10+
11+
type keyContaining1<
12+
str extends string,
13+
keys extends keyof obj = keyof obj,
14+
> = keys extends infer key extends keyof obj
15+
? key extends `${string}${str}${string}`
16+
? obj[key]
17+
: never
18+
: never;
19+
20+
type _1 = keyContaining1<"foo">; // 1
21+
22+
type keyContaining2<
23+
str extends string,
24+
keys extends keyof obj = keyof obj,
25+
> = keys extends keys
26+
? keys extends `${string}${str}${string}`
27+
? obj[keys]
28+
: never
29+
: never;
30+
31+
type _2 = keyContaining2<"foo">; // 1

0 commit comments

Comments
 (0)