diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index f828fb02c0c..8d949d6ac79 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4753,15 +4753,15 @@ namespace ts { getPropertiesOfObjectType(type); } - function getConstraintOfTypeVariable(type: TypeVariable): Type { - return type.flags & TypeFlags.TypeParameter ? getConstraintOfTypeParameter(type) : getBaseConstraintOfTypeVariable(type); + function getConstraintOfType(type: TypeVariable | UnionOrIntersectionType): Type { + return type.flags & TypeFlags.TypeParameter ? getConstraintOfTypeParameter(type) : getBaseConstraintOfType(type); } function getConstraintOfTypeParameter(typeParameter: TypeParameter): Type { return hasNonCircularBaseConstraint(typeParameter) ? getConstraintFromTypeParameter(typeParameter) : undefined; } - function getBaseConstraintOfTypeVariable(type: TypeVariable): Type { + function getBaseConstraintOfType(type: TypeVariable | UnionOrIntersectionType): Type { const constraint = getResolvedBaseConstraint(type); return constraint !== noConstraintType && constraint !== circularConstraintType ? constraint : undefined; } @@ -4775,15 +4775,15 @@ namespace ts { * type variable has no constraint, and the circularConstraintType singleton is returned if the constraint * circularly references the type variable. */ - function getResolvedBaseConstraint(type: TypeVariable): Type { + function getResolvedBaseConstraint(type: TypeVariable | UnionOrIntersectionType): Type { let typeStack: Type[]; let circular: boolean; - if (!type.resolvedApparentType) { + if (!type.resolvedBaseConstraint) { typeStack = []; const constraint = getBaseConstraint(type); - type.resolvedApparentType = circular ? circularConstraintType : getTypeWithThisArgument(constraint || noConstraintType, type); + type.resolvedBaseConstraint = circular ? circularConstraintType : getTypeWithThisArgument(constraint || noConstraintType, type); } - return type.resolvedApparentType; + return type.resolvedBaseConstraint; function getBaseConstraint(t: Type): Type { if (contains(typeStack, t)) { @@ -4834,7 +4834,7 @@ namespace ts { * type itself. Note that the apparent type of a union type is the union type itself. */ function getApparentType(type: Type): Type { - const t = type.flags & TypeFlags.TypeVariable ? getBaseConstraintOfTypeVariable(type) || emptyObjectType : type; + const t = type.flags & TypeFlags.TypeVariable ? getBaseConstraintOfType(type) || emptyObjectType : type; return t.flags & TypeFlags.StringLike ? globalStringType : t.flags & TypeFlags.NumberLike ? globalNumberType : t.flags & TypeFlags.BooleanLike ? globalBooleanType : @@ -7427,14 +7427,12 @@ namespace ts { return result; } } - // Given a type variable T with a constraint C, a type S is assignable to - // keyof T if S is assignable to keyof C. - if ((target).type.flags & TypeFlags.TypeVariable) { - const constraint = getConstraintOfTypeVariable((target).type); - if (constraint) { - if (result = isRelatedTo(source, getIndexType(constraint), reportErrors)) { - return result; - } + // A type S is assignable to keyof T if S is assignable to keyof C, where C is the + // constraint of T. + const constraint = getConstraintOfType((target).type); + if (constraint) { + if (result = isRelatedTo(source, getIndexType(constraint), reportErrors)) { + return result; } } } @@ -7448,7 +7446,7 @@ namespace ts { } // A type S is related to a type T[K] if S is related to A[K], where K is string-like and // A is the apparent type of S. - const constraint = getBaseConstraintOfTypeVariable(target); + const constraint = getBaseConstraintOfType(target); if (constraint) { if (result = isRelatedTo(source, constraint, reportErrors)) { errorInfo = saveErrorInfo; @@ -7488,7 +7486,7 @@ namespace ts { else if (source.flags & TypeFlags.IndexedAccess) { // A type S[K] is related to a type T if A[K] is related to T, where K is string-like and // A is the apparent type of S. - const constraint = getBaseConstraintOfTypeVariable(source); + const constraint = getBaseConstraintOfType(source); if (constraint) { if (result = isRelatedTo(constraint, target, reportErrors)) { errorInfo = saveErrorInfo; @@ -15207,7 +15205,7 @@ namespace ts { function isLiteralContextualType(contextualType: Type) { if (contextualType) { if (contextualType.flags & TypeFlags.TypeVariable) { - const constraint = getBaseConstraintOfTypeVariable(contextualType) || emptyObjectType; + const constraint = getBaseConstraintOfType(contextualType) || emptyObjectType; // If the type parameter is constrained to the base primitive type we're checking for, // consider this a literal context. For example, given a type parameter 'T extends string', // this causes us to infer string literal types for T. diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 8827aea633a..954ad21ba29 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2923,6 +2923,8 @@ namespace ts { /* @internal */ resolvedIndexType: IndexType; /* @internal */ + resolvedBaseConstraint: Type; + /* @internal */ couldContainTypeVariables: boolean; } @@ -2982,7 +2984,7 @@ namespace ts { export interface TypeVariable extends Type { /* @internal */ - resolvedApparentType: Type; + resolvedBaseConstraint: Type; /* @internal */ resolvedIndexType: IndexType; }