mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-18 07:29:16 -05:00
Don't eagerly simplify reducible generic union index types (#46812)
This commit is contained in:
@@ -814,6 +814,8 @@ namespace ts {
|
||||
|
||||
const restrictiveMapper: TypeMapper = makeFunctionTypeMapper(t => t.flags & TypeFlags.TypeParameter ? getRestrictiveTypeParameter(t as TypeParameter) : t);
|
||||
const permissiveMapper: TypeMapper = makeFunctionTypeMapper(t => t.flags & TypeFlags.TypeParameter ? wildcardType : t);
|
||||
const uniqueLiteralType = createIntrinsicType(TypeFlags.Never, "never"); // `uniqueLiteralType` is a special `never` flagged by union reduction to behave as a literal
|
||||
const uniqueLiteralMapper: TypeMapper = makeFunctionTypeMapper(t => t.flags & TypeFlags.TypeParameter ? uniqueLiteralType : t); // replace all type parameters with the unique literal type (disregarding constraints)
|
||||
|
||||
const emptyObjectType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, emptyArray);
|
||||
const emptyJsxObjectType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, emptyArray);
|
||||
@@ -12367,10 +12369,10 @@ namespace ts {
|
||||
else if (type !== firstType) {
|
||||
checkFlags |= CheckFlags.HasNonUniformType;
|
||||
}
|
||||
if (isLiteralType(type) || isPatternLiteralType(type)) {
|
||||
if (isLiteralType(type) || isPatternLiteralType(type) || type === uniqueLiteralType) {
|
||||
checkFlags |= CheckFlags.HasLiteralType;
|
||||
}
|
||||
if (type.flags & TypeFlags.Never) {
|
||||
if (type.flags & TypeFlags.Never && type !== uniqueLiteralType) {
|
||||
checkFlags |= CheckFlags.HasNeverType;
|
||||
}
|
||||
propTypes.push(type);
|
||||
@@ -15124,9 +15126,24 @@ namespace ts {
|
||||
/*aliasSymbol*/ undefined, /*aliasTypeArguments*/ undefined, origin);
|
||||
}
|
||||
|
||||
/**
|
||||
* A union type which is reducible upon instantiation (meaning some members are removed under certain instantiations)
|
||||
* must be kept generic, as that instantiation information needs to flow through the type system. By replacing all
|
||||
* type parameters in the union with a special never type that is treated as a literal in `getReducedType`, we can cause the `getReducedType` logic
|
||||
* to reduce the resulting type if possible (since only intersections with conflicting literal-typed properties are reducible).
|
||||
*/
|
||||
function isPossiblyReducibleByInstantiation(type: UnionType): boolean {
|
||||
return some(type.types, t => {
|
||||
const uniqueFilled = getUniqueLiteralFilledInstantiation(t);
|
||||
return getReducedType(uniqueFilled) !== uniqueFilled;
|
||||
});
|
||||
}
|
||||
|
||||
function getIndexType(type: Type, stringsOnly = keyofStringsOnly, noIndexSignatures?: boolean): Type {
|
||||
type = getReducedType(type);
|
||||
return type.flags & TypeFlags.Union ? getIntersectionType(map((type as UnionType).types, t => getIndexType(t, stringsOnly, noIndexSignatures))) :
|
||||
return type.flags & TypeFlags.Union ? isPossiblyReducibleByInstantiation(type as UnionType)
|
||||
? getIndexTypeForGenericType(type as InstantiableType | UnionOrIntersectionType, stringsOnly)
|
||||
: getIntersectionType(map((type as UnionType).types, t => getIndexType(t, stringsOnly, noIndexSignatures))) :
|
||||
type.flags & TypeFlags.Intersection ? getUnionType(map((type as IntersectionType).types, t => getIndexType(t, stringsOnly, noIndexSignatures))) :
|
||||
type.flags & TypeFlags.InstantiableNonPrimitive || isGenericTupleType(type) || isGenericMappedType(type) && !hasDistributiveNameType(type) ? getIndexTypeForGenericType(type as InstantiableType | UnionOrIntersectionType, stringsOnly) :
|
||||
getObjectFlags(type) & ObjectFlags.Mapped ? getIndexTypeForMappedType(type as MappedType, stringsOnly, noIndexSignatures) :
|
||||
@@ -17070,6 +17087,11 @@ namespace ts {
|
||||
return type; // Nested invocation of `inferTypeForHomomorphicMappedType` or the `source` instantiated into something unmappable
|
||||
}
|
||||
|
||||
function getUniqueLiteralFilledInstantiation(type: Type) {
|
||||
return type.flags & (TypeFlags.Primitive | TypeFlags.AnyOrUnknown | TypeFlags.Never) ? type :
|
||||
type.uniqueLiteralFilledInstantiation || (type.uniqueLiteralFilledInstantiation = instantiateType(type, uniqueLiteralMapper));
|
||||
}
|
||||
|
||||
function getPermissiveInstantiation(type: Type) {
|
||||
return type.flags & (TypeFlags.Primitive | TypeFlags.AnyOrUnknown | TypeFlags.Never) ? type :
|
||||
type.permissiveInstantiation || (type.permissiveInstantiation = instantiateType(type, permissiveMapper));
|
||||
|
||||
@@ -5244,6 +5244,8 @@ namespace ts {
|
||||
/* @internal */
|
||||
restrictiveInstantiation?: Type; // Instantiation with type parameters mapped to unconstrained form
|
||||
/* @internal */
|
||||
uniqueLiteralFilledInstantiation?: Type; // Instantiation with type parameters mapped to never type
|
||||
/* @internal */
|
||||
immediateBaseConstraint?: Type; // Immediate base constraint cache
|
||||
/* @internal */
|
||||
widened?: Type; // Cached widened form of the type
|
||||
|
||||
Reference in New Issue
Block a user