mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-04-17 01:49:41 -05:00
Disable constraint reduction in intersections created by constraint hoisting (#58403)
This commit is contained in:
@@ -446,6 +446,7 @@ import {
|
||||
InterfaceType,
|
||||
InterfaceTypeWithDeclaredMembers,
|
||||
InternalSymbolName,
|
||||
IntersectionFlags,
|
||||
IntersectionType,
|
||||
IntersectionTypeNode,
|
||||
intrinsicTagNameToString,
|
||||
@@ -14196,7 +14197,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
}
|
||||
}
|
||||
// The source types were normalized; ensure the result is normalized too.
|
||||
return getNormalizedType(getIntersectionType(constraints), /*writing*/ false);
|
||||
return getNormalizedType(getIntersectionType(constraints, IntersectionFlags.NoConstraintReduction), /*writing*/ false);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
@@ -17459,7 +17460,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
// a type alias of the form "type List<T> = T & { next: List<T> }" cannot be reduced during its declaration.
|
||||
// Also, unlike union types, the order of the constituent types is preserved in order that overload resolution
|
||||
// for intersections of types with signatures can be deterministic.
|
||||
function getIntersectionType(types: readonly Type[], aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[], noSupertypeReduction?: boolean): Type {
|
||||
function getIntersectionType(types: readonly Type[], flags = IntersectionFlags.None, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[]): Type {
|
||||
const typeMembershipMap = new Map<string, Type>();
|
||||
const includes = addTypesToIntersection(typeMembershipMap, 0 as TypeFlags, types);
|
||||
const typeSet: Type[] = arrayFrom(typeMembershipMap.values());
|
||||
@@ -17504,7 +17505,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
includes & TypeFlags.Void && includes & TypeFlags.Undefined ||
|
||||
includes & TypeFlags.IncludesEmptyObject && includes & TypeFlags.DefinitelyNonNullable
|
||||
) {
|
||||
if (!noSupertypeReduction) removeRedundantSupertypes(typeSet, includes);
|
||||
if (!(flags & IntersectionFlags.NoSupertypeReduction)) removeRedundantSupertypes(typeSet, includes);
|
||||
}
|
||||
if (includes & TypeFlags.IncludesMissingType) {
|
||||
typeSet[typeSet.indexOf(undefinedType)] = missingType;
|
||||
@@ -17515,7 +17516,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
if (typeSet.length === 1) {
|
||||
return typeSet[0];
|
||||
}
|
||||
if (typeSet.length === 2) {
|
||||
if (typeSet.length === 2 && !(flags & IntersectionFlags.NoConstraintReduction)) {
|
||||
const typeVarIndex = typeSet[0].flags & TypeFlags.TypeVariable ? 0 : 1;
|
||||
const typeVariable = typeSet[typeVarIndex];
|
||||
const primitiveType = typeSet[1 - typeVarIndex];
|
||||
@@ -17548,7 +17549,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
}
|
||||
}
|
||||
}
|
||||
const id = getTypeListId(typeSet) + getAliasId(aliasSymbol, aliasTypeArguments);
|
||||
const id = getTypeListId(typeSet) + (flags & IntersectionFlags.NoConstraintReduction ? "*" : getAliasId(aliasSymbol, aliasTypeArguments));
|
||||
let result = intersectionTypes.get(id);
|
||||
if (!result) {
|
||||
if (includes & TypeFlags.Union) {
|
||||
@@ -17556,16 +17557,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
// When the intersection creates a reduced set (which might mean that *all* union types have
|
||||
// disappeared), we restart the operation to get a new set of combined flags. Once we have
|
||||
// reduced we'll never reduce again, so this occurs at most once.
|
||||
result = getIntersectionType(typeSet, aliasSymbol, aliasTypeArguments);
|
||||
result = getIntersectionType(typeSet, flags, aliasSymbol, aliasTypeArguments);
|
||||
}
|
||||
else if (every(typeSet, t => !!(t.flags & TypeFlags.Union && (t as UnionType).types[0].flags & TypeFlags.Undefined))) {
|
||||
const containedUndefinedType = some(typeSet, containsMissingType) ? missingType : undefinedType;
|
||||
removeFromEach(typeSet, TypeFlags.Undefined);
|
||||
result = getUnionType([getIntersectionType(typeSet), containedUndefinedType], UnionReduction.Literal, aliasSymbol, aliasTypeArguments);
|
||||
result = getUnionType([getIntersectionType(typeSet, flags), containedUndefinedType], UnionReduction.Literal, aliasSymbol, aliasTypeArguments);
|
||||
}
|
||||
else if (every(typeSet, t => !!(t.flags & TypeFlags.Union && ((t as UnionType).types[0].flags & TypeFlags.Null || (t as UnionType).types[1].flags & TypeFlags.Null)))) {
|
||||
removeFromEach(typeSet, TypeFlags.Null);
|
||||
result = getUnionType([getIntersectionType(typeSet), nullType], UnionReduction.Literal, aliasSymbol, aliasTypeArguments);
|
||||
result = getUnionType([getIntersectionType(typeSet, flags), nullType], UnionReduction.Literal, aliasSymbol, aliasTypeArguments);
|
||||
}
|
||||
else if (typeSet.length >= 4) {
|
||||
// When we have four or more constituents, some of which are unions, we employ a "divide and conquer" strategy
|
||||
@@ -17573,7 +17574,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
// unions of intersections than the full cartesian product (due to some intersections becoming `never`), this can
|
||||
// dramatically reduce the overall work.
|
||||
const middle = Math.floor(typeSet.length / 2);
|
||||
result = getIntersectionType([getIntersectionType(typeSet.slice(0, middle)), getIntersectionType(typeSet.slice(middle))], aliasSymbol, aliasTypeArguments);
|
||||
result = getIntersectionType([getIntersectionType(typeSet.slice(0, middle), flags), getIntersectionType(typeSet.slice(middle), flags)], flags, aliasSymbol, aliasTypeArguments);
|
||||
}
|
||||
else {
|
||||
// We are attempting to construct a type of the form X & (A | B) & (C | D). Transform this into a type of
|
||||
@@ -17582,7 +17583,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
if (!checkCrossProductUnion(typeSet)) {
|
||||
return errorType;
|
||||
}
|
||||
const constituents = getCrossProductIntersections(typeSet);
|
||||
const constituents = getCrossProductIntersections(typeSet, flags);
|
||||
// We attach a denormalized origin type when at least one constituent of the cross-product union is an
|
||||
// intersection (i.e. when the intersection didn't just reduce one or more unions to smaller unions) and
|
||||
// the denormalized origin has fewer constituents than the union itself.
|
||||
@@ -17612,7 +17613,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
return true;
|
||||
}
|
||||
|
||||
function getCrossProductIntersections(types: readonly Type[]) {
|
||||
function getCrossProductIntersections(types: readonly Type[], flags: IntersectionFlags) {
|
||||
const count = getCrossProductUnionSize(types);
|
||||
const intersections: Type[] = [];
|
||||
for (let i = 0; i < count; i++) {
|
||||
@@ -17626,7 +17627,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
n = Math.floor(n / length);
|
||||
}
|
||||
}
|
||||
const t = getIntersectionType(constituents);
|
||||
const t = getIntersectionType(constituents, flags);
|
||||
if (!(t.flags & TypeFlags.Never)) intersections.push(t);
|
||||
}
|
||||
return intersections;
|
||||
@@ -17653,7 +17654,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
const emptyIndex = types.length === 2 ? types.indexOf(emptyTypeLiteralType) : -1;
|
||||
const t = emptyIndex >= 0 ? types[1 - emptyIndex] : unknownType;
|
||||
const noSupertypeReduction = !!(t.flags & (TypeFlags.String | TypeFlags.Number | TypeFlags.BigInt) || t.flags & TypeFlags.TemplateLiteral && isPatternLiteralType(t));
|
||||
links.resolvedType = getIntersectionType(types, aliasSymbol, getTypeArgumentsForAliasSymbol(aliasSymbol), noSupertypeReduction);
|
||||
links.resolvedType = getIntersectionType(types, noSupertypeReduction ? IntersectionFlags.NoSupertypeReduction : 0, aliasSymbol, getTypeArgumentsForAliasSymbol(aliasSymbol));
|
||||
}
|
||||
return links.resolvedType;
|
||||
}
|
||||
@@ -18533,7 +18534,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
return undefined;
|
||||
}
|
||||
return accessFlags & AccessFlags.Writing
|
||||
? getIntersectionType(propTypes, aliasSymbol, aliasTypeArguments)
|
||||
? getIntersectionType(propTypes, IntersectionFlags.None, aliasSymbol, aliasTypeArguments)
|
||||
: getUnionType(propTypes, UnionReduction.Literal, aliasSymbol, aliasTypeArguments);
|
||||
}
|
||||
return getPropertyTypeForIndexType(objectType, apparentObjectType, indexType, indexType, accessNode, accessFlags | AccessFlags.CacheSymbol | AccessFlags.ReportDeprecated);
|
||||
@@ -19884,7 +19885,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
const newAliasSymbol = aliasSymbol || type.aliasSymbol;
|
||||
const newAliasTypeArguments = aliasSymbol ? aliasTypeArguments : instantiateTypes(type.aliasTypeArguments, mapper);
|
||||
return flags & TypeFlags.Intersection || origin && origin.flags & TypeFlags.Intersection ?
|
||||
getIntersectionType(newTypes, newAliasSymbol, newAliasTypeArguments) :
|
||||
getIntersectionType(newTypes, IntersectionFlags.None, newAliasSymbol, newAliasTypeArguments) :
|
||||
getUnionType(newTypes, UnionReduction.Literal, newAliasSymbol, newAliasTypeArguments);
|
||||
}
|
||||
if (flags & TypeFlags.Index) {
|
||||
|
||||
@@ -5379,6 +5379,13 @@ export const enum UnionReduction {
|
||||
Subtype,
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export const enum IntersectionFlags {
|
||||
None = 0,
|
||||
NoSupertypeReduction = 1 << 0,
|
||||
NoConstraintReduction = 1 << 1,
|
||||
}
|
||||
|
||||
// dprint-ignore
|
||||
/** @internal */
|
||||
export const enum ContextFlags {
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
//// [tests/cases/compiler/intersectionConstraintReduction.ts] ////
|
||||
|
||||
=== intersectionConstraintReduction.ts ===
|
||||
type Test1<K1 extends keyof any, K2 extends keyof any> =
|
||||
>Test1 : Symbol(Test1, Decl(intersectionConstraintReduction.ts, 0, 0))
|
||||
>K1 : Symbol(K1, Decl(intersectionConstraintReduction.ts, 0, 11))
|
||||
>K2 : Symbol(K2, Decl(intersectionConstraintReduction.ts, 0, 32))
|
||||
|
||||
MustBeKey<Extract<K1, keyof any> & K1 & K2>;
|
||||
>MustBeKey : Symbol(MustBeKey, Decl(intersectionConstraintReduction.ts, 4, 48))
|
||||
>Extract : Symbol(Extract, Decl(lib.es5.d.ts, --, --))
|
||||
>K1 : Symbol(K1, Decl(intersectionConstraintReduction.ts, 0, 11))
|
||||
>K1 : Symbol(K1, Decl(intersectionConstraintReduction.ts, 0, 11))
|
||||
>K2 : Symbol(K2, Decl(intersectionConstraintReduction.ts, 0, 32))
|
||||
|
||||
type Test2<K1 extends keyof any, K2 extends keyof any> =
|
||||
>Test2 : Symbol(Test2, Decl(intersectionConstraintReduction.ts, 1, 48))
|
||||
>K1 : Symbol(K1, Decl(intersectionConstraintReduction.ts, 3, 11))
|
||||
>K2 : Symbol(K2, Decl(intersectionConstraintReduction.ts, 3, 32))
|
||||
|
||||
MustBeKey<K1 & K2 & Extract<K1, keyof any>>;
|
||||
>MustBeKey : Symbol(MustBeKey, Decl(intersectionConstraintReduction.ts, 4, 48))
|
||||
>K1 : Symbol(K1, Decl(intersectionConstraintReduction.ts, 3, 11))
|
||||
>K2 : Symbol(K2, Decl(intersectionConstraintReduction.ts, 3, 32))
|
||||
>Extract : Symbol(Extract, Decl(lib.es5.d.ts, --, --))
|
||||
>K1 : Symbol(K1, Decl(intersectionConstraintReduction.ts, 3, 11))
|
||||
|
||||
type MustBeKey<K extends keyof any> = K;
|
||||
>MustBeKey : Symbol(MustBeKey, Decl(intersectionConstraintReduction.ts, 4, 48))
|
||||
>K : Symbol(K, Decl(intersectionConstraintReduction.ts, 6, 15))
|
||||
>K : Symbol(K, Decl(intersectionConstraintReduction.ts, 6, 15))
|
||||
|
||||
// https://github.com/microsoft/TypeScript/issues/58370
|
||||
|
||||
type AnyKey = number | string | symbol;
|
||||
>AnyKey : Symbol(AnyKey, Decl(intersectionConstraintReduction.ts, 6, 40))
|
||||
|
||||
type ReturnTypeKeyof<Obj extends object> = Obj extends object
|
||||
>ReturnTypeKeyof : Symbol(ReturnTypeKeyof, Decl(intersectionConstraintReduction.ts, 10, 39))
|
||||
>Obj : Symbol(Obj, Decl(intersectionConstraintReduction.ts, 12, 21))
|
||||
>Obj : Symbol(Obj, Decl(intersectionConstraintReduction.ts, 12, 21))
|
||||
|
||||
? [keyof Obj] extends [never]
|
||||
>Obj : Symbol(Obj, Decl(intersectionConstraintReduction.ts, 12, 21))
|
||||
|
||||
? never
|
||||
: { [Key in keyof Obj as string]-?: () => Key }[string]
|
||||
>Key : Symbol(Key, Decl(intersectionConstraintReduction.ts, 15, 13))
|
||||
>Obj : Symbol(Obj, Decl(intersectionConstraintReduction.ts, 12, 21))
|
||||
>Key : Symbol(Key, Decl(intersectionConstraintReduction.ts, 15, 13))
|
||||
|
||||
: never;
|
||||
|
||||
type KeyIfSignatureOfObject<
|
||||
>KeyIfSignatureOfObject : Symbol(KeyIfSignatureOfObject, Decl(intersectionConstraintReduction.ts, 16, 12))
|
||||
|
||||
Obj extends object,
|
||||
>Obj : Symbol(Obj, Decl(intersectionConstraintReduction.ts, 18, 28))
|
||||
|
||||
Key extends AnyKey,
|
||||
>Key : Symbol(Key, Decl(intersectionConstraintReduction.ts, 19, 23))
|
||||
>AnyKey : Symbol(AnyKey, Decl(intersectionConstraintReduction.ts, 6, 40))
|
||||
|
||||
ReturnTypeKeys = ReturnTypeKeyof<Obj>,
|
||||
>ReturnTypeKeys : Symbol(ReturnTypeKeys, Decl(intersectionConstraintReduction.ts, 20, 23))
|
||||
>ReturnTypeKeyof : Symbol(ReturnTypeKeyof, Decl(intersectionConstraintReduction.ts, 10, 39))
|
||||
>Obj : Symbol(Obj, Decl(intersectionConstraintReduction.ts, 18, 28))
|
||||
|
||||
> = ReturnTypeKeys extends () => Key ? ((() => Key) extends ReturnTypeKeys ? Key : never) : never;
|
||||
>ReturnTypeKeys : Symbol(ReturnTypeKeys, Decl(intersectionConstraintReduction.ts, 20, 23))
|
||||
>Key : Symbol(Key, Decl(intersectionConstraintReduction.ts, 19, 23))
|
||||
>Key : Symbol(Key, Decl(intersectionConstraintReduction.ts, 19, 23))
|
||||
>ReturnTypeKeys : Symbol(ReturnTypeKeys, Decl(intersectionConstraintReduction.ts, 20, 23))
|
||||
>Key : Symbol(Key, Decl(intersectionConstraintReduction.ts, 19, 23))
|
||||
|
||||
export type Reduced1<Obj extends object, Key extends AnyKey, Value, ObjKeys extends keyof Obj = keyof Obj> =
|
||||
>Reduced1 : Symbol(Reduced1, Decl(intersectionConstraintReduction.ts, 22, 98))
|
||||
>Obj : Symbol(Obj, Decl(intersectionConstraintReduction.ts, 24, 21))
|
||||
>Key : Symbol(Key, Decl(intersectionConstraintReduction.ts, 24, 40))
|
||||
>AnyKey : Symbol(AnyKey, Decl(intersectionConstraintReduction.ts, 6, 40))
|
||||
>Value : Symbol(Value, Decl(intersectionConstraintReduction.ts, 24, 60))
|
||||
>ObjKeys : Symbol(ObjKeys, Decl(intersectionConstraintReduction.ts, 24, 67))
|
||||
>Obj : Symbol(Obj, Decl(intersectionConstraintReduction.ts, 24, 21))
|
||||
>Obj : Symbol(Obj, Decl(intersectionConstraintReduction.ts, 24, 21))
|
||||
|
||||
Key extends KeyIfSignatureOfObject<Obj, Key>
|
||||
>Key : Symbol(Key, Decl(intersectionConstraintReduction.ts, 24, 40))
|
||||
>KeyIfSignatureOfObject : Symbol(KeyIfSignatureOfObject, Decl(intersectionConstraintReduction.ts, 16, 12))
|
||||
>Obj : Symbol(Obj, Decl(intersectionConstraintReduction.ts, 24, 21))
|
||||
>Key : Symbol(Key, Decl(intersectionConstraintReduction.ts, 24, 40))
|
||||
|
||||
? Key extends ObjKeys
|
||||
>Key : Symbol(Key, Decl(intersectionConstraintReduction.ts, 24, 40))
|
||||
>ObjKeys : Symbol(ObjKeys, Decl(intersectionConstraintReduction.ts, 24, 67))
|
||||
|
||||
? { [K in Key]: Value }
|
||||
>K : Symbol(K, Decl(intersectionConstraintReduction.ts, 27, 17))
|
||||
>Key : Symbol(Key, Decl(intersectionConstraintReduction.ts, 24, 40))
|
||||
>Value : Symbol(Value, Decl(intersectionConstraintReduction.ts, 24, 60))
|
||||
|
||||
: never
|
||||
: never;
|
||||
|
||||
export type Reduced2<Obj extends object, Key extends AnyKey, Value, ObjKeys extends keyof Obj = keyof Obj> =
|
||||
>Reduced2 : Symbol(Reduced2, Decl(intersectionConstraintReduction.ts, 29, 16))
|
||||
>Obj : Symbol(Obj, Decl(intersectionConstraintReduction.ts, 31, 21))
|
||||
>Key : Symbol(Key, Decl(intersectionConstraintReduction.ts, 31, 40))
|
||||
>AnyKey : Symbol(AnyKey, Decl(intersectionConstraintReduction.ts, 6, 40))
|
||||
>Value : Symbol(Value, Decl(intersectionConstraintReduction.ts, 31, 60))
|
||||
>ObjKeys : Symbol(ObjKeys, Decl(intersectionConstraintReduction.ts, 31, 67))
|
||||
>Obj : Symbol(Obj, Decl(intersectionConstraintReduction.ts, 31, 21))
|
||||
>Obj : Symbol(Obj, Decl(intersectionConstraintReduction.ts, 31, 21))
|
||||
|
||||
Key extends AnyKey
|
||||
>Key : Symbol(Key, Decl(intersectionConstraintReduction.ts, 31, 40))
|
||||
>AnyKey : Symbol(AnyKey, Decl(intersectionConstraintReduction.ts, 6, 40))
|
||||
|
||||
? Key extends KeyIfSignatureOfObject<Obj, Key>
|
||||
>Key : Symbol(Key, Decl(intersectionConstraintReduction.ts, 31, 40))
|
||||
>KeyIfSignatureOfObject : Symbol(KeyIfSignatureOfObject, Decl(intersectionConstraintReduction.ts, 16, 12))
|
||||
>Obj : Symbol(Obj, Decl(intersectionConstraintReduction.ts, 31, 21))
|
||||
>Key : Symbol(Key, Decl(intersectionConstraintReduction.ts, 31, 40))
|
||||
|
||||
? Key extends ObjKeys
|
||||
>Key : Symbol(Key, Decl(intersectionConstraintReduction.ts, 31, 40))
|
||||
>ObjKeys : Symbol(ObjKeys, Decl(intersectionConstraintReduction.ts, 31, 67))
|
||||
|
||||
? { [K in Key]: Value }
|
||||
>K : Symbol(K, Decl(intersectionConstraintReduction.ts, 35, 20))
|
||||
>Key : Symbol(Key, Decl(intersectionConstraintReduction.ts, 31, 40))
|
||||
>Value : Symbol(Value, Decl(intersectionConstraintReduction.ts, 31, 60))
|
||||
|
||||
: never
|
||||
: never
|
||||
: never;
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
//// [tests/cases/compiler/intersectionConstraintReduction.ts] ////
|
||||
|
||||
=== intersectionConstraintReduction.ts ===
|
||||
type Test1<K1 extends keyof any, K2 extends keyof any> =
|
||||
>Test1 : Extract<K1, string | number | symbol> & K1 & K2
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
MustBeKey<Extract<K1, keyof any> & K1 & K2>;
|
||||
|
||||
type Test2<K1 extends keyof any, K2 extends keyof any> =
|
||||
>Test2 : K1 & K2 & Extract<K1, string | number | symbol>
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
MustBeKey<K1 & K2 & Extract<K1, keyof any>>;
|
||||
|
||||
type MustBeKey<K extends keyof any> = K;
|
||||
>MustBeKey : K
|
||||
> : ^
|
||||
|
||||
// https://github.com/microsoft/TypeScript/issues/58370
|
||||
|
||||
type AnyKey = number | string | symbol;
|
||||
>AnyKey : AnyKey
|
||||
> : ^^^^^^
|
||||
|
||||
type ReturnTypeKeyof<Obj extends object> = Obj extends object
|
||||
>ReturnTypeKeyof : ReturnTypeKeyof<Obj>
|
||||
> : ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
? [keyof Obj] extends [never]
|
||||
? never
|
||||
: { [Key in keyof Obj as string]-?: () => Key }[string]
|
||||
: never;
|
||||
|
||||
type KeyIfSignatureOfObject<
|
||||
>KeyIfSignatureOfObject : KeyIfSignatureOfObject<Obj, Key, ReturnTypeKeys>
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Obj extends object,
|
||||
Key extends AnyKey,
|
||||
ReturnTypeKeys = ReturnTypeKeyof<Obj>,
|
||||
> = ReturnTypeKeys extends () => Key ? ((() => Key) extends ReturnTypeKeys ? Key : never) : never;
|
||||
|
||||
export type Reduced1<Obj extends object, Key extends AnyKey, Value, ObjKeys extends keyof Obj = keyof Obj> =
|
||||
>Reduced1 : Reduced1<Obj, Key, Value, ObjKeys>
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Key extends KeyIfSignatureOfObject<Obj, Key>
|
||||
? Key extends ObjKeys
|
||||
? { [K in Key]: Value }
|
||||
: never
|
||||
: never;
|
||||
|
||||
export type Reduced2<Obj extends object, Key extends AnyKey, Value, ObjKeys extends keyof Obj = keyof Obj> =
|
||||
>Reduced2 : Reduced2<Obj, Key, Value, ObjKeys>
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Key extends AnyKey
|
||||
? Key extends KeyIfSignatureOfObject<Obj, Key>
|
||||
? Key extends ObjKeys
|
||||
? { [K in Key]: Value }
|
||||
: never
|
||||
: never
|
||||
: never;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
//// [tests/cases/compiler/intersectionsOfLargeUnions.ts] ////
|
||||
|
||||
=== Performance Stats ===
|
||||
Strict subtype cache: 1,000
|
||||
Assignability cache: 1,000
|
||||
Type Count: 2,500
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
//// [tests/cases/compiler/intersectionsOfLargeUnions2.ts] ////
|
||||
|
||||
=== Performance Stats ===
|
||||
Strict subtype cache: 1,000
|
||||
Assignability cache: 1,000
|
||||
Type Count: 2,500
|
||||
|
||||
|
||||
42
tests/cases/compiler/intersectionConstraintReduction.ts
Normal file
42
tests/cases/compiler/intersectionConstraintReduction.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
// @strict: true
|
||||
// @noEmit: true
|
||||
|
||||
type Test1<K1 extends keyof any, K2 extends keyof any> =
|
||||
MustBeKey<Extract<K1, keyof any> & K1 & K2>;
|
||||
|
||||
type Test2<K1 extends keyof any, K2 extends keyof any> =
|
||||
MustBeKey<K1 & K2 & Extract<K1, keyof any>>;
|
||||
|
||||
type MustBeKey<K extends keyof any> = K;
|
||||
|
||||
// https://github.com/microsoft/TypeScript/issues/58370
|
||||
|
||||
type AnyKey = number | string | symbol;
|
||||
|
||||
type ReturnTypeKeyof<Obj extends object> = Obj extends object
|
||||
? [keyof Obj] extends [never]
|
||||
? never
|
||||
: { [Key in keyof Obj as string]-?: () => Key }[string]
|
||||
: never;
|
||||
|
||||
type KeyIfSignatureOfObject<
|
||||
Obj extends object,
|
||||
Key extends AnyKey,
|
||||
ReturnTypeKeys = ReturnTypeKeyof<Obj>,
|
||||
> = ReturnTypeKeys extends () => Key ? ((() => Key) extends ReturnTypeKeys ? Key : never) : never;
|
||||
|
||||
export type Reduced1<Obj extends object, Key extends AnyKey, Value, ObjKeys extends keyof Obj = keyof Obj> =
|
||||
Key extends KeyIfSignatureOfObject<Obj, Key>
|
||||
? Key extends ObjKeys
|
||||
? { [K in Key]: Value }
|
||||
: never
|
||||
: never;
|
||||
|
||||
export type Reduced2<Obj extends object, Key extends AnyKey, Value, ObjKeys extends keyof Obj = keyof Obj> =
|
||||
Key extends AnyKey
|
||||
? Key extends KeyIfSignatureOfObject<Obj, Key>
|
||||
? Key extends ObjKeys
|
||||
? { [K in Key]: Value }
|
||||
: never
|
||||
: never
|
||||
: never;
|
||||
Reference in New Issue
Block a user