Exclude generic string-like types from intersection reduction (#57751)

This commit is contained in:
Anders Hejlsberg 2024-03-13 16:13:31 -07:00 committed by GitHub
parent f9ef9439bd
commit 952dfc5082
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 161 additions and 2 deletions

View File

@ -17642,7 +17642,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
const typeVarIndex = typeSet[0].flags & TypeFlags.TypeVariable ? 0 : 1;
const typeVariable = typeSet[typeVarIndex];
const primitiveType = typeSet[1 - typeVarIndex];
if (typeVariable.flags & TypeFlags.TypeVariable && (primitiveType.flags & (TypeFlags.Primitive | TypeFlags.NonPrimitive) || includes & TypeFlags.IncludesEmptyObject)) {
if (
typeVariable.flags & TypeFlags.TypeVariable &&
(primitiveType.flags & (TypeFlags.Primitive | TypeFlags.NonPrimitive) && !isGenericStringLikeType(primitiveType) || includes & TypeFlags.IncludesEmptyObject)
) {
// 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 {}.
const constraint = getBaseConstraintOfType(typeVariable);
// 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 {
!!(type.flags & TypeFlags.StringMapping) && isPatternLiteralPlaceholderType((type as StringMappingType).type);
}
function isGenericStringLikeType(type: Type) {
return !!(type.flags & (TypeFlags.TemplateLiteral | TypeFlags.StringMapping)) && !isPatternLiteralType(type);
}
function isGenericType(type: Type): boolean {
return !!getGenericObjectFlags(type);
}
@ -18417,7 +18424,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
return (type as SubstitutionType).objectFlags & ObjectFlags.IsGenericType;
}
return (type.flags & TypeFlags.InstantiableNonPrimitive || isGenericMappedType(type) || isGenericTupleType(type) ? ObjectFlags.IsGenericObjectType : 0) |
(type.flags & (TypeFlags.InstantiableNonPrimitive | TypeFlags.Index | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) && !isPatternLiteralType(type) ? ObjectFlags.IsGenericIndexType : 0);
(type.flags & (TypeFlags.InstantiableNonPrimitive | TypeFlags.Index) || isGenericStringLikeType(type) ? ObjectFlags.IsGenericIndexType : 0);
}
function getSimplifiedType(type: Type, writing: boolean): Type {

View File

@ -0,0 +1,77 @@
//// [tests/cases/compiler/intersectionReductionGenericStringLikeType.ts] ////
=== intersectionReductionGenericStringLikeType.ts ===
// https://github.com/microsoft/TypeScript/issues/57736
type obj = {
>obj : Symbol(obj, Decl(intersectionReductionGenericStringLikeType.ts, 0, 0))
foo: 1;
>foo : Symbol(foo, Decl(intersectionReductionGenericStringLikeType.ts, 2, 12))
bar: 2;
>bar : Symbol(bar, Decl(intersectionReductionGenericStringLikeType.ts, 3, 11))
};
type keyContaining1<
>keyContaining1 : Symbol(keyContaining1, Decl(intersectionReductionGenericStringLikeType.ts, 5, 2))
str extends string,
>str : Symbol(str, Decl(intersectionReductionGenericStringLikeType.ts, 7, 20))
keys extends keyof obj = keyof obj,
>keys : Symbol(keys, Decl(intersectionReductionGenericStringLikeType.ts, 8, 23))
>obj : Symbol(obj, Decl(intersectionReductionGenericStringLikeType.ts, 0, 0))
>obj : Symbol(obj, Decl(intersectionReductionGenericStringLikeType.ts, 0, 0))
> = keys extends infer key extends keyof obj
>keys : Symbol(keys, Decl(intersectionReductionGenericStringLikeType.ts, 8, 23))
>key : Symbol(key, Decl(intersectionReductionGenericStringLikeType.ts, 10, 22))
>obj : Symbol(obj, Decl(intersectionReductionGenericStringLikeType.ts, 0, 0))
? key extends `${string}${str}${string}`
>key : Symbol(key, Decl(intersectionReductionGenericStringLikeType.ts, 10, 22))
>str : Symbol(str, Decl(intersectionReductionGenericStringLikeType.ts, 7, 20))
? obj[key]
>obj : Symbol(obj, Decl(intersectionReductionGenericStringLikeType.ts, 0, 0))
>key : Symbol(key, Decl(intersectionReductionGenericStringLikeType.ts, 10, 22))
: never
: never;
type _1 = keyContaining1<"foo">; // 1
>_1 : Symbol(_1, Decl(intersectionReductionGenericStringLikeType.ts, 14, 12))
>keyContaining1 : Symbol(keyContaining1, Decl(intersectionReductionGenericStringLikeType.ts, 5, 2))
type keyContaining2<
>keyContaining2 : Symbol(keyContaining2, Decl(intersectionReductionGenericStringLikeType.ts, 16, 32))
str extends string,
>str : Symbol(str, Decl(intersectionReductionGenericStringLikeType.ts, 18, 20))
keys extends keyof obj = keyof obj,
>keys : Symbol(keys, Decl(intersectionReductionGenericStringLikeType.ts, 19, 23))
>obj : Symbol(obj, Decl(intersectionReductionGenericStringLikeType.ts, 0, 0))
>obj : Symbol(obj, Decl(intersectionReductionGenericStringLikeType.ts, 0, 0))
> = keys extends keys
>keys : Symbol(keys, Decl(intersectionReductionGenericStringLikeType.ts, 19, 23))
>keys : Symbol(keys, Decl(intersectionReductionGenericStringLikeType.ts, 19, 23))
? keys extends `${string}${str}${string}`
>keys : Symbol(keys, Decl(intersectionReductionGenericStringLikeType.ts, 19, 23))
>str : Symbol(str, Decl(intersectionReductionGenericStringLikeType.ts, 18, 20))
? obj[keys]
>obj : Symbol(obj, Decl(intersectionReductionGenericStringLikeType.ts, 0, 0))
>keys : Symbol(keys, Decl(intersectionReductionGenericStringLikeType.ts, 19, 23))
: never
: never;
type _2 = keyContaining2<"foo">; // 1
>_2 : Symbol(_2, Decl(intersectionReductionGenericStringLikeType.ts, 25, 12))
>keyContaining2 : Symbol(keyContaining2, Decl(intersectionReductionGenericStringLikeType.ts, 16, 32))

View File

@ -0,0 +1,44 @@
//// [tests/cases/compiler/intersectionReductionGenericStringLikeType.ts] ////
=== intersectionReductionGenericStringLikeType.ts ===
// https://github.com/microsoft/TypeScript/issues/57736
type obj = {
>obj : { foo: 1; bar: 2; }
foo: 1;
>foo : 1
bar: 2;
>bar : 2
};
type keyContaining1<
>keyContaining1 : keyContaining1<str, keys>
str extends string,
keys extends keyof obj = keyof obj,
> = keys extends infer key extends keyof obj
? key extends `${string}${str}${string}`
? obj[key]
: never
: never;
type _1 = keyContaining1<"foo">; // 1
>_1 : 1
type keyContaining2<
>keyContaining2 : keyContaining2<str, keys>
str extends string,
keys extends keyof obj = keyof obj,
> = keys extends keys
? keys extends `${string}${str}${string}`
? obj[keys]
: never
: never;
type _2 = keyContaining2<"foo">; // 1
>_2 : 1

View File

@ -0,0 +1,31 @@
// @strict: true
// @noEmit: true
// https://github.com/microsoft/TypeScript/issues/57736
type obj = {
foo: 1;
bar: 2;
};
type keyContaining1<
str extends string,
keys extends keyof obj = keyof obj,
> = keys extends infer key extends keyof obj
? key extends `${string}${str}${string}`
? obj[key]
: never
: never;
type _1 = keyContaining1<"foo">; // 1
type keyContaining2<
str extends string,
keys extends keyof obj = keyof obj,
> = keys extends keys
? keys extends `${string}${str}${string}`
? obj[keys]
: never
: never;
type _2 = keyContaining2<"foo">; // 1