Skip to content

Commit

Permalink
🤖 Pick PR #57751 (Exclude generic string-like types f...) into releas…
Browse files Browse the repository at this point in the history
…e-5.4 (#57753)

Co-authored-by: Anders Hejlsberg <andersh@microsoft.com>
  • Loading branch information
TypeScript Bot and ahejlsberg authored Mar 13, 2024
1 parent 42bb138 commit 7f11456
Show file tree
Hide file tree
Showing 4 changed files with 161 additions and 2 deletions.
11 changes: 9 additions & 2 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17624,7 +17624,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 {}.
Expand Down Expand Up @@ -18374,6 +18377,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);
}
Expand Down Expand Up @@ -18402,7 +18409,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 {
Expand Down
Original file line number Diff line number Diff line change
@@ -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))

Original file line number Diff line number Diff line change
@@ -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

31 changes: 31 additions & 0 deletions tests/cases/compiler/intersectionReductionGenericStringLikeType.ts
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 7f11456

Please sign in to comment.