From fabe4d36a2780b744185cc661be4cd43cba43d6f Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Fri, 22 Jul 2022 15:36:41 -0400 Subject: [PATCH 1/7] Added some Type type predicates internally --- src/compiler/checker.ts | 598 +++++++++++++++++++------------------- src/compiler/utilities.ts | 50 +++- 2 files changed, 348 insertions(+), 300 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 4dd1b7baa4431..b67213f575585 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5103,11 +5103,11 @@ namespace ts { (type === markerSubTypeForCheck ? "sub-" : "super-") + symbolName(varianceTypeParameter.symbol) : "?"; return factory.createTypeReferenceNode(factory.createIdentifier(name), /*typeArguments*/ undefined); } - if (type.flags & TypeFlags.Union && (type as UnionType).origin) { - type = (type as UnionType).origin!; + if (isUnionType(type) && type.origin) { + type = type.origin; } - if (type.flags & (TypeFlags.Union | TypeFlags.Intersection)) { - const types = type.flags & TypeFlags.Union ? formatUnionTypes((type as UnionType).types) : (type as IntersectionType).types; + if (isUnionOrIntersectionType(type)) { + const types = isUnionType(type) ? formatUnionTypes(type.types) : type.types; if (length(types) === 1) { return typeToTypeNodeHelper(types[0], context); } @@ -5123,19 +5123,19 @@ namespace ts { } } if (objectFlags & (ObjectFlags.Anonymous | ObjectFlags.Mapped)) { - Debug.assert(!!(type.flags & TypeFlags.Object)); + Debug.assert(isObjectType(type)); // The type is an object literal type. - return createAnonymousTypeNode(type as ObjectType); + return createAnonymousTypeNode(type); } - if (type.flags & TypeFlags.Index) { - const indexedType = (type as IndexType).type; + if (isIndexType(type)) { + const indexedType = type.type; context.approximateLength += 6; const indexTypeNode = typeToTypeNodeHelper(indexedType, context); return factory.createTypeOperatorNode(SyntaxKind.KeyOfKeyword, indexTypeNode); } - if (type.flags & TypeFlags.TemplateLiteral) { - const texts = (type as TemplateLiteralType).texts; - const types = (type as TemplateLiteralType).types; + if (isTemplateLiteralType(type)) { + const texts = type.texts; + const types = type.types; const templateHead = factory.createTemplateHead(texts[0]); const templateSpans = factory.createNodeArray( map(types, (t, i) => factory.createTemplateLiteralTypeSpan( @@ -5144,21 +5144,21 @@ namespace ts { context.approximateLength += 2; return factory.createTemplateLiteralType(templateHead, templateSpans); } - if (type.flags & TypeFlags.StringMapping) { - const typeNode = typeToTypeNodeHelper((type as StringMappingType).type, context); - return symbolToTypeNode((type as StringMappingType).symbol, context, SymbolFlags.Type, [typeNode]); + if (isStringMappingType(type)) { + const typeNode = typeToTypeNodeHelper(type.type, context); + return symbolToTypeNode(type.symbol, context, SymbolFlags.Type, [typeNode]); } - if (type.flags & TypeFlags.IndexedAccess) { - const objectTypeNode = typeToTypeNodeHelper((type as IndexedAccessType).objectType, context); - const indexTypeNode = typeToTypeNodeHelper((type as IndexedAccessType).indexType, context); + if (isIndexedAccessType(type)) { + const objectTypeNode = typeToTypeNodeHelper(type.objectType, context); + const indexTypeNode = typeToTypeNodeHelper(type.indexType, context); context.approximateLength += 2; return factory.createIndexedAccessTypeNode(objectTypeNode, indexTypeNode); } - if (type.flags & TypeFlags.Conditional) { + if (isConditionalType(type)) { return visitAndTransformType(type, type => conditionalTypeToTypeNode(type as ConditionalType)); } - if (type.flags & TypeFlags.Substitution) { - return typeToTypeNodeHelper((type as SubstitutionType).baseType, context); + if (isSubstitutionType(type)) { + return typeToTypeNodeHelper(type.baseType, context); } return Debug.fail("Should be unreachable."); @@ -5326,7 +5326,7 @@ namespace ts { const typeId = type.id; const isConstructorObject = getObjectFlags(type) & ObjectFlags.Anonymous && type.symbol && type.symbol.flags & SymbolFlags.Class; const id = getObjectFlags(type) & ObjectFlags.Reference && (type as TypeReference).node ? "N" + getNodeId((type as TypeReference).node!) : - type.flags & TypeFlags.Conditional ? "N" + getNodeId((type as ConditionalType).root.node) : + isConditionalType(type) ? "N" + getNodeId(type.root.node) : type.symbol ? (isConstructorObject ? "+" : "") + getSymbolId(type.symbol) : undefined; // Since instantiations of the same anonymous type have the same symbol, tracking symbols instead @@ -9816,7 +9816,7 @@ namespace ts { function getBaseTypeVariableOfClass(symbol: Symbol) { const baseConstructorType = getBaseConstructorTypeOfClass(getDeclaredTypeOfClassOrInterface(symbol)); return baseConstructorType.flags & TypeFlags.TypeVariable ? baseConstructorType : - baseConstructorType.flags & TypeFlags.Intersection ? find((baseConstructorType as IntersectionType).types, t => !!(t.flags & TypeFlags.TypeVariable)) : + isIntersectionType(baseConstructorType) ? find(baseConstructorType.types, t => !!(t.flags & TypeFlags.TypeVariable)) : undefined; } @@ -10022,8 +10022,8 @@ namespace ts { const target = getTargetType(type) as InterfaceType; return target === checkBase || some(getBaseTypes(target), check); } - else if (type.flags & TypeFlags.Intersection) { - return some((type as IntersectionType).types, check); + else if (isIntersectionType(type)) { + return some(type.types, check); } return false; } @@ -10377,7 +10377,7 @@ namespace ts { // TODO: Given that we allow type parmeters here now, is this `!isGenericMappedType(type)` check really needed? // There's no reason a `T` should be allowed while a `Readonly` should not. return !!(type.flags & (TypeFlags.Object | TypeFlags.NonPrimitive | TypeFlags.Any) && !isGenericMappedType(type) || - type.flags & TypeFlags.Intersection && every((type as IntersectionType).types, isValidBaseType)); + isIntersectionType(type) && every(type.types, isValidBaseType)); } function resolveBaseTypesOfInterface(type: InterfaceType): void { @@ -11028,9 +11028,9 @@ namespace ts { return needApparentType ? getApparentType(ref) : ref; } } - else if (type.flags & TypeFlags.Intersection) { - const types = sameMap((type as IntersectionType).types, t => getTypeWithThisArgument(t, thisArgument, needApparentType)); - return types !== (type as IntersectionType).types ? getIntersectionType(types) : type; + else if (isIntersectionType(type)) { + const types = sameMap(type.types, t => getTypeWithThisArgument(t, thisArgument, needApparentType)); + return types !== type.types ? getIntersectionType(types) : type; } return needApparentType ? getApparentType(type) : type; } @@ -11632,13 +11632,13 @@ namespace ts { inferredProp.declarations = prop.declarations; inferredProp.nameType = getSymbolLinks(prop).nameType; inferredProp.propertyType = getTypeOfSymbol(prop); - if (type.constraintType.type.flags & TypeFlags.IndexedAccess - && (type.constraintType.type as IndexedAccessType).objectType.flags & TypeFlags.TypeParameter - && (type.constraintType.type as IndexedAccessType).indexType.flags & TypeFlags.TypeParameter) { + if (isIndexedAccessType(type.constraintType.type) + && type.constraintType.type.objectType.flags & TypeFlags.TypeParameter + && type.constraintType.type.indexType.flags & TypeFlags.TypeParameter) { // A reverse mapping of `{[K in keyof T[K_1]]: T[K_1]}` is the same as that of `{[K in keyof T]: T}`, since all we care about is // inferring to the "type parameter" (or indexed access) shared by the constraint and template. So, to reduce the number of // type identities produced, we simplify such indexed access occurences - const newTypeParam = (type.constraintType.type as IndexedAccessType).objectType; + const newTypeParam = type.constraintType.type.objectType; const newMappedType = replaceIndexedAccess(type.mappedType, type.constraintType.type as ReplaceableIndexedAccessType, newTypeParam); inferredProp.mappedType = newMappedType as MappedType; inferredProp.constraintType = getIndexType(newTypeParam) as IndexType; @@ -11656,25 +11656,25 @@ namespace ts { // bound includes those keys that are known to always be present, for example because // because of constraints on type parameters (e.g. 'keyof T' for a constrained T). function getLowerBoundOfKeyType(type: Type): Type { - if (type.flags & TypeFlags.Index) { - const t = getApparentType((type as IndexType).type); + if (isIndexType(type)) { + const t = getApparentType(type.type); return isGenericTupleType(t) ? getKnownKeysOfTupleType(t) : getIndexType(t); } - if (type.flags & TypeFlags.Conditional) { - if ((type as ConditionalType).root.isDistributive) { - const checkType = (type as ConditionalType).checkType; + if (isConditionalType(type)) { + if (type.root.isDistributive) { + const { checkType } = type; const constraint = getLowerBoundOfKeyType(checkType); if (constraint !== checkType) { - return getConditionalTypeInstantiation(type as ConditionalType, prependTypeMapping((type as ConditionalType).root.checkType, constraint, (type as ConditionalType).mapper)); + return getConditionalTypeInstantiation(type, prependTypeMapping(type.root.checkType, constraint, type.mapper)); } } return type; } - if (type.flags & TypeFlags.Union) { - return mapType(type as UnionType, getLowerBoundOfKeyType); + if (isUnionType(type)) { + return mapType(type, getLowerBoundOfKeyType); } - if (type.flags & TypeFlags.Intersection) { - return getIntersectionType(sameMap((type as UnionType).types, getLowerBoundOfKeyType)); + if (isIntersectionType(type)) { + return getIntersectionType(sameMap(type.types, getLowerBoundOfKeyType)); } return type; } @@ -11847,7 +11847,7 @@ namespace ts { const declaredType = getTypeFromMappedTypeNode(type.declaration) as MappedType; const constraint = getConstraintTypeFromMappedType(declaredType); const extendedConstraint = constraint && constraint.flags & TypeFlags.TypeParameter ? getConstraintOfTypeParameter(constraint as TypeParameter) : constraint; - type.modifiersType = extendedConstraint && extendedConstraint.flags & TypeFlags.Index ? instantiateType((extendedConstraint as IndexType).type, type.mapper) : unknownType; + type.modifiersType = extendedConstraint && isIndexType(extendedConstraint) ? instantiateType(extendedConstraint.type, type.mapper) : unknownType; } } return type.modifiersType; @@ -11880,17 +11880,17 @@ namespace ts { function resolveStructuredTypeMembers(type: StructuredType): ResolvedType { if (!(type as ResolvedType).members) { - if (type.flags & TypeFlags.Object) { - if ((type as ObjectType).objectFlags & ObjectFlags.Reference) { + if (isObjectType(type)) { + if (type.objectFlags & ObjectFlags.Reference) { resolveTypeReferenceMembers(type as TypeReference); } - else if ((type as ObjectType).objectFlags & ObjectFlags.ClassOrInterface) { + else if (type.objectFlags & ObjectFlags.ClassOrInterface) { resolveClassOrInterfaceMembers(type as InterfaceType); } - else if ((type as ReverseMappedType).objectFlags & ObjectFlags.ReverseMapped) { + else if (type.objectFlags & ObjectFlags.ReverseMapped) { resolveReverseMappedTypeMembers(type as ReverseMappedType); } - else if ((type as ObjectType).objectFlags & ObjectFlags.Anonymous) { + else if (type.objectFlags & ObjectFlags.Anonymous) { resolveAnonymousTypeMembers(type as AnonymousType); } else if ((type as MappedType).objectFlags & ObjectFlags.Mapped) { @@ -11900,14 +11900,14 @@ namespace ts { Debug.fail("Unhandled object type " + Debug.formatObjectFlags(type.objectFlags)); } } - else if (type.flags & TypeFlags.Union) { - resolveUnionTypeMembers(type as UnionType); + else if (isUnionType(type)) { + resolveUnionTypeMembers(type); } - else if (type.flags & TypeFlags.Intersection) { - resolveIntersectionTypeMembers(type as IntersectionType); + else if (isIntersectionType(type)) { + resolveIntersectionTypeMembers(type); } else { - Debug.fail("Unhandled type " + Debug.formatTypeFlags(type.flags)); + Debug.fail("Unhandled type " + Debug.formatTypeFlags((type as unknown as Type).flags)); } } return type as ResolvedType; @@ -12005,9 +12005,9 @@ namespace ts { } function getConstraintOfType(type: InstantiableType | UnionOrIntersectionType): Type | undefined { - return type.flags & TypeFlags.TypeParameter ? getConstraintOfTypeParameter(type as TypeParameter) : - type.flags & TypeFlags.IndexedAccess ? getConstraintOfIndexedAccess(type as IndexedAccessType) : - type.flags & TypeFlags.Conditional ? getConstraintOfConditionalType(type as ConditionalType) : + return isTypeParameterType(type) ? getConstraintOfTypeParameter(type) : + isIndexedAccessType(type) ? getConstraintOfIndexedAccess(type) : + isConditionalType(type) ? getConstraintOfConditionalType(type) : getBaseConstraintOfType(type); } @@ -12239,27 +12239,27 @@ namespace ts { const constraints = mapDefined(types, getBaseConstraint); return constraints.length === types.length ? getTemplateLiteralType((t as TemplateLiteralType).texts, constraints) : stringType; } - if (t.flags & TypeFlags.StringMapping) { - const constraint = getBaseConstraint((t as StringMappingType).type); - return constraint && constraint !== (t as StringMappingType).type ? getStringMappingType((t as StringMappingType).symbol, constraint) : stringType; + if (isStringMappingType(t)) { + const constraint = getBaseConstraint(t.type); + return constraint && constraint !== t.type ? getStringMappingType(t.symbol, constraint) : stringType; } - if (t.flags & TypeFlags.IndexedAccess) { + if (isIndexedAccessType(t)) { if (isMappedTypeGenericIndexedAccess(t)) { // For indexed access types of the form { [P in K]: E }[X], where K is non-generic and X is generic, // we substitute an instantiation of E where P is replaced with X. - return getBaseConstraint(substituteIndexedMappedType((t as IndexedAccessType).objectType as MappedType, (t as IndexedAccessType).indexType)); + return getBaseConstraint(substituteIndexedMappedType(t.objectType, t.indexType)); } - const baseObjectType = getBaseConstraint((t as IndexedAccessType).objectType); - const baseIndexType = getBaseConstraint((t as IndexedAccessType).indexType); - const baseIndexedAccess = baseObjectType && baseIndexType && getIndexedAccessTypeOrUndefined(baseObjectType, baseIndexType, (t as IndexedAccessType).accessFlags); + const baseObjectType = getBaseConstraint(t.objectType); + const baseIndexType = getBaseConstraint(t.indexType); + const baseIndexedAccess = baseObjectType && baseIndexType && getIndexedAccessTypeOrUndefined(baseObjectType, baseIndexType, t.accessFlags); return baseIndexedAccess && getBaseConstraint(baseIndexedAccess); } - if (t.flags & TypeFlags.Conditional) { - const constraint = getConstraintFromConditionalType(t as ConditionalType); + if (isConditionalType(t)) { + const constraint = getConstraintFromConditionalType(t); return constraint && getBaseConstraint(constraint); } - if (t.flags & TypeFlags.Substitution) { - return getBaseConstraint((t as SubstitutionType).substitute); + if (isSubstitutionType(t)) { + return getBaseConstraint(t.substitute); } return t; } @@ -12331,10 +12331,14 @@ namespace ts { return type; } - function isMappedTypeGenericIndexedAccess(type: Type) { + interface TypeWithMappedObjectType extends IndexedAccessType { + objectType: MappedType; + }; + + function isMappedTypeGenericIndexedAccess(type: Type): type is TypeWithMappedObjectType { let objectType; - return !!(type.flags & TypeFlags.IndexedAccess && getObjectFlags(objectType = (type as IndexedAccessType).objectType) & ObjectFlags.Mapped && - !isGenericMappedType(objectType) && isGenericIndexType((type as IndexedAccessType).indexType) && + return !!(isIndexedAccessType(type) && getObjectFlags(objectType = type.objectType) & ObjectFlags.Mapped && + !isGenericMappedType(objectType) && isGenericIndexType(type.indexType) && !(getMappedTypeModifiers(objectType as MappedType) & MappedTypeModifiers.ExcludeOptional) && !(objectType as MappedType).declaration.nameType); } @@ -12346,7 +12350,7 @@ namespace ts { function getApparentType(type: Type): Type { const t = !(type.flags & TypeFlags.Instantiable) ? type : getBaseConstraintOfType(type) || unknownType; return getObjectFlags(t) & ObjectFlags.Mapped ? getApparentTypeOfMappedType(t as MappedType) : - t.flags & TypeFlags.Intersection ? getApparentTypeOfIntersectionType(t as IntersectionType) : + isIntersectionType(t) ? getApparentTypeOfIntersectionType(t) : t.flags & TypeFlags.StringLike ? globalStringType : t.flags & TypeFlags.NumberLike ? globalNumberType : t.flags & TypeFlags.BigIntLike ? getGlobalBigIntType() : @@ -12562,15 +12566,15 @@ namespace ts { * no constituent property has type 'never', but the intersection of the constituent property types is 'never'. */ function getReducedType(type: Type): Type { - if (type.flags & TypeFlags.Union && (type as UnionType).objectFlags & ObjectFlags.ContainsIntersections) { - return (type as UnionType).resolvedReducedType || ((type as UnionType).resolvedReducedType = getReducedUnionType(type as UnionType)); + if (isUnionType(type) && type.objectFlags & ObjectFlags.ContainsIntersections) { + return type.resolvedReducedType || (type.resolvedReducedType = getReducedUnionType(type)); } - else if (type.flags & TypeFlags.Intersection) { - if (!((type as IntersectionType).objectFlags & ObjectFlags.IsNeverIntersectionComputed)) { - (type as IntersectionType).objectFlags |= ObjectFlags.IsNeverIntersectionComputed | - (some(getPropertiesOfUnionOrIntersectionType(type as IntersectionType), isNeverReducedProperty) ? ObjectFlags.IsNeverIntersection : 0); + else if (isIntersectionType(type)) { + if (!(type.objectFlags & ObjectFlags.IsNeverIntersectionComputed)) { + type.objectFlags |= ObjectFlags.IsNeverIntersectionComputed | + (some(getPropertiesOfUnionOrIntersectionType(type), isNeverReducedProperty) ? ObjectFlags.IsNeverIntersection : 0); } - return (type as IntersectionType).objectFlags & ObjectFlags.IsNeverIntersection ? neverType : type; + return type.objectFlags & ObjectFlags.IsNeverIntersection ? neverType : type; } return type; } @@ -12605,13 +12609,13 @@ namespace ts { } function elaborateNeverIntersection(errorInfo: DiagnosticMessageChain | undefined, type: Type) { - if (type.flags & TypeFlags.Intersection && getObjectFlags(type) & ObjectFlags.IsNeverIntersection) { - const neverProp = find(getPropertiesOfUnionOrIntersectionType(type as IntersectionType), isDiscriminantWithNeverType); + if (isIntersectionType(type) && getObjectFlags(type) & ObjectFlags.IsNeverIntersection) { + const neverProp = find(getPropertiesOfUnionOrIntersectionType(type), isDiscriminantWithNeverType); if (neverProp) { return chainDiagnosticMessages(errorInfo, Diagnostics.The_intersection_0_was_reduced_to_never_because_property_1_has_conflicting_types_in_some_constituents, typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.NoTypeReduction), symbolToString(neverProp)); } - const privateProp = find(getPropertiesOfUnionOrIntersectionType(type as IntersectionType), isConflictingPrivateProperty); + const privateProp = find(getPropertiesOfUnionOrIntersectionType(type), isConflictingPrivateProperty); if (privateProp) { return chainDiagnosticMessages(errorInfo, Diagnostics.The_intersection_0_was_reduced_to_never_because_property_1_exists_in_multiple_constituents_and_is_private_in_some, typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.NoTypeReduction), symbolToString(privateProp)); @@ -12630,8 +12634,8 @@ namespace ts { */ function getPropertyOfType(type: Type, name: __String, skipObjectFunctionPropertyAugment?: boolean, includeTypeOnlyMembers?: boolean): Symbol | undefined { type = getReducedApparentType(type); - if (type.flags & TypeFlags.Object) { - const resolved = resolveStructuredTypeMembers(type as ObjectType); + if (isObjectType(type)) { + const resolved = resolveStructuredTypeMembers(type); const symbol = resolved.members.get(name); if (symbol && symbolIsValue(symbol, includeTypeOnlyMembers)) { return symbol; @@ -12649,8 +12653,8 @@ namespace ts { } return getPropertyOfObjectType(globalObjectType, name); } - if (type.flags & TypeFlags.UnionOrIntersection) { - return getPropertyOfUnionOrIntersectionType(type as UnionOrIntersectionType, name, skipObjectFunctionPropertyAugment); + if (isUnionOrIntersectionType(type)) { + return getPropertyOfUnionOrIntersectionType(type, name, skipObjectFunctionPropertyAugment); } return undefined; } @@ -13361,7 +13365,7 @@ namespace ts { function isValidIndexKeyType(type: Type): boolean { return !!(type.flags & (TypeFlags.String | TypeFlags.Number | TypeFlags.ESSymbol)) || isPatternLiteralType(type) || - !!(type.flags & TypeFlags.Intersection) && !isGenericType(type) && some((type as IntersectionType).types, isValidIndexKeyType); + !!(isIntersectionType(type)) && !isGenericType(type) && some(type.types, isValidIndexKeyType); } function getConstraintDeclaration(type: TypeParameter): TypeNode | undefined { @@ -14806,8 +14810,8 @@ namespace ts { return types[0]; } const typeKey = !origin ? getTypeListId(types) : - origin.flags & TypeFlags.Union ? `|${getTypeListId((origin as UnionType).types)}` : - origin.flags & TypeFlags.Intersection ? `&${getTypeListId((origin as IntersectionType).types)}` : + isUnionType(origin) ? `|${getTypeListId(origin.types)}` : + isIntersectionType(origin) ? `&${getTypeListId(origin.types)}` : `#${(origin as IndexType).type.id}|${getTypeListId(types)}`; // origin type id alone is insufficient, as `keyof x` may resolve to multiple WIP values while `x` is still resolving const id = typeKey + getAliasId(aliasSymbol, aliasTypeArguments); let type = unionTypes.get(id); @@ -14839,8 +14843,8 @@ namespace ts { function addTypeToIntersection(typeSet: ESMap, includes: TypeFlags, type: Type) { const flags = type.flags; - if (flags & TypeFlags.Intersection) { - return addTypesToIntersection(typeSet, includes, (type as IntersectionType).types); + if (isIntersectionType(type)) { + return addTypesToIntersection(typeSet, includes, type.types); } if (isEmptyAnonymousObjectType(type)) { if (!(includes & TypeFlags.IncludesEmptyObject)) { @@ -15246,11 +15250,11 @@ namespace ts { return isDistributive(getNameTypeFromMappedType(mappedType) || typeVariable); function isDistributive(type: Type): boolean { return type.flags & (TypeFlags.AnyOrUnknown | TypeFlags.Primitive | TypeFlags.Never | TypeFlags.TypeParameter | TypeFlags.Object | TypeFlags.NonPrimitive) ? true : - type.flags & TypeFlags.Conditional ? (type as ConditionalType).root.isDistributive && (type as ConditionalType).checkType === typeVariable : + isConditionalType(type) ? type.root.isDistributive && type.checkType === typeVariable : type.flags & (TypeFlags.UnionOrIntersection | TypeFlags.TemplateLiteral) ? every((type as UnionOrIntersectionType | TemplateLiteralType).types, isDistributive) : - type.flags & TypeFlags.IndexedAccess ? isDistributive((type as IndexedAccessType).objectType) && isDistributive((type as IndexedAccessType).indexType) : - type.flags & TypeFlags.Substitution ? isDistributive((type as SubstitutionType).substitute) : - type.flags & TypeFlags.StringMapping ? isDistributive((type as StringMappingType).type) : + isIndexedAccessType(type) ? isDistributive(type.objectType) && isDistributive(type.indexType) : + isSubstitutionType(type) ? isDistributive(type.substitute) : + isStringMappingType(type) ? isDistributive(type.type) : false; } } @@ -15279,7 +15283,7 @@ namespace ts { } function isKeyTypeIncluded(keyType: Type, include: TypeFlags): boolean { - return !!(keyType.flags & include || keyType.flags & TypeFlags.Intersection && some((keyType as IntersectionType).types, t => isKeyTypeIncluded(t, include))); + return !!(keyType.flags & include || isIntersectionType(keyType) && some(keyType.types, t => isKeyTypeIncluded(t, include))); } function getLiteralTypeFromProperties(type: Type, include: TypeFlags, includeOrigin: boolean) { @@ -15306,15 +15310,15 @@ namespace ts { return !!(type.flags & TypeFlags.InstantiableNonPrimitive || isGenericTupleType(type) || isGenericMappedType(type) && !hasDistributiveNameType(type) || - type.flags & TypeFlags.Union && some((type as UnionType).types, isPossiblyReducibleByInstantiation) || - type.flags & TypeFlags.Intersection && maybeTypeOfKind(type, TypeFlags.Instantiable) && some((type as IntersectionType).types, isEmptyAnonymousObjectType)); + isUnionType(type) && some(type.types, isPossiblyReducibleByInstantiation) || + isIntersectionType(type) && maybeTypeOfKind(type, TypeFlags.Instantiable) && some(type.types, isEmptyAnonymousObjectType)); } function getIndexType(type: Type, stringsOnly = keyofStringsOnly, noIndexSignatures?: boolean): Type { type = getReducedType(type); return shouldDeferIndexType(type) ? getIndexTypeForGenericType(type as InstantiableType | UnionOrIntersectionType, stringsOnly) : - type.flags & TypeFlags.Union ? 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))) : + isUnionType(type) ? getIntersectionType(map(type.types, t => getIndexType(t, stringsOnly, noIndexSignatures))) : + isIntersectionType(type) ? getUnionType(map(type.types, t => getIndexType(t, stringsOnly, noIndexSignatures))) : getObjectFlags(type) & ObjectFlags.Mapped ? getIndexTypeForMappedType(type as MappedType, stringsOnly, noIndexSignatures) : type === wildcardType ? wildcardType : type.flags & TypeFlags.Unknown ? neverType : @@ -15419,8 +15423,8 @@ namespace ts { newTexts.push(text); text = addText; } - else if (t.flags & TypeFlags.Intersection) { - const added = addSpans(texts[i + 1], (t as IntersectionType).types); + else if (isIntersectionType(t)) { + const added = addSpans(texts[i + 1], t.types); if (!added) return false; } else if (isTextsArray) { @@ -15518,11 +15522,11 @@ namespace ts { if (getObjectFlags(type) & ObjectFlags.JSLiteral) { return true; } - if (type.flags & TypeFlags.Union) { - return every((type as UnionType).types, isJSLiteralType); + if (isUnionType(type)) { + return every(type.types, isJSLiteralType); } - if (type.flags & TypeFlags.Intersection) { - return some((type as IntersectionType).types, isJSLiteralType); + if (isIntersectionType(type)) { + return some(type.types, isJSLiteralType); } if (type.flags & TypeFlags.Instantiable) { const constraint = getResolvedBaseConstraint(type); @@ -15771,8 +15775,8 @@ namespace ts { } function getSimplifiedType(type: Type, writing: boolean): Type { - return type.flags & TypeFlags.IndexedAccess ? getSimplifiedIndexedAccessType(type as IndexedAccessType, writing) : - type.flags & TypeFlags.Conditional ? getSimplifiedConditionalType(type as ConditionalType, writing) : + return isIndexedAccessType(type) ? getSimplifiedIndexedAccessType(type, writing) : + isConditionalType(type) ? getSimplifiedConditionalType(type, writing) : type; } @@ -15780,8 +15784,8 @@ namespace ts { // (T | U)[K] -> T[K] | U[K] (reading) // (T | U)[K] -> T[K] & U[K] (writing) // (T & U)[K] -> T[K] & U[K] - if (objectType.flags & TypeFlags.UnionOrIntersection) { - const types = map((objectType as UnionOrIntersectionType).types, t => getSimplifiedType(getIndexedAccessType(t, indexType), writing)); + if (isUnionOrIntersectionType(objectType)) { + const types = map(objectType.types, t => getSimplifiedType(getIndexedAccessType(t, indexType), writing)); return objectType.flags & TypeFlags.Intersection || writing ? getIntersectionType(types) : getUnionType(types); } } @@ -15975,9 +15979,9 @@ namespace ts { const indexType = getTypeFromTypeNode(node.indexType); const potentialAlias = getAliasSymbolForTypeNode(node); const resolved = getIndexedAccessType(objectType, indexType, AccessFlags.None, node, potentialAlias, getTypeArgumentsForAliasSymbol(potentialAlias)); - links.resolvedType = resolved.flags & TypeFlags.IndexedAccess && - (resolved as IndexedAccessType).objectType === objectType && - (resolved as IndexedAccessType).indexType === indexType ? + links.resolvedType = isIndexedAccessType(resolved) && + resolved.objectType === objectType && + resolved.indexType === indexType ? getConditionalFlowTypeOfType(resolved, node) : resolved; } return links.resolvedType; @@ -15999,13 +16003,13 @@ namespace ts { } function getActualTypeVariable(type: Type): Type { - if (type.flags & TypeFlags.Substitution) { - return (type as SubstitutionType).baseType; + if (isSubstitutionType(type)) { + return type.baseType; } - if (type.flags & TypeFlags.IndexedAccess && ( - (type as IndexedAccessType).objectType.flags & TypeFlags.Substitution || - (type as IndexedAccessType).indexType.flags & TypeFlags.Substitution)) { - return getIndexedAccessType(getActualTypeVariable((type as IndexedAccessType).objectType), getActualTypeVariable((type as IndexedAccessType).indexType)); + if (isIndexedAccessType(type) && ( + type.objectType.flags & TypeFlags.Substitution || + type.indexType.flags & TypeFlags.Substitution)) { + return getIndexedAccessType(getActualTypeVariable(type.objectType), getActualTypeVariable(type.indexType)); } return type; } @@ -16120,8 +16124,8 @@ namespace ts { // If falseType is an immediately nested conditional type that isn't distributive or has an // identical checkType, switch to that type and loop. const falseType = getTypeFromTypeNode(root.node.falseType); - if (falseType.flags & TypeFlags.Conditional) { - const newRoot = (falseType as ConditionalType).root; + if (isConditionalType(falseType)) { + const newRoot = falseType.root; if (newRoot.node.parent === root.node && (!newRoot.isDistributive || newRoot.checkType === root.checkType)) { root = newRoot; continue; @@ -16165,10 +16169,10 @@ namespace ts { // type. Note that recursion is possible only through aliased conditional types, so we only increment the tail // recursion counter for those. function canTailRecurse(newType: Type, newMapper: TypeMapper | undefined) { - if (newType.flags & TypeFlags.Conditional && newMapper) { - const newRoot = (newType as ConditionalType).root; + if (isConditionalType(newType) && newMapper) { + const newRoot = newType.root; if (newRoot.outerTypeParameters) { - const typeParamMapper = combineTypeMappers((newType as ConditionalType).mapper, newMapper); + const typeParamMapper = combineTypeMappers(newType.mapper, newMapper); const typeArguments = map(newRoot.outerTypeParameters, t => getMappedType(t, typeParamMapper)); const newRootMapper = createTypeMapper(newRoot.outerTypeParameters, typeArguments); const newCheckType = newRoot.isDistributive ? getMappedType(newRoot.checkType, newRootMapper) : undefined; @@ -16460,8 +16464,8 @@ namespace ts { // When the left type is an intersection, we may need to merge the last constituent of the // intersection with the right type. For example when the left type is 'T & { a: string }' // and the right type is '{ b: string }' we produce 'T & { a: string, b: string }'. - if (left.flags & TypeFlags.Intersection) { - const types = (left as IntersectionType).types; + if (isIntersectionType(left)) { + const types = left.types; const lastLeft = types[types.length - 1]; if (isNonGenericObjectType(lastLeft) && isNonGenericObjectType(right)) { return getIntersectionType(concatenate(types.slice(0, types.length - 1), [getSpreadType(lastLeft, right, symbol, objectFlags, readonly)])); @@ -17082,10 +17086,10 @@ namespace ts { function getHomomorphicTypeVariable(type: MappedType) { const constraintType = getConstraintTypeFromMappedType(type); - if (constraintType.flags & TypeFlags.Index) { - const typeVariable = getActualTypeVariable((constraintType as IndexType).type); - if (typeVariable.flags & TypeFlags.TypeParameter) { - return typeVariable as TypeParameter; + if (isIndexType(constraintType)) { + const typeVariable = getActualTypeVariable(constraintType.type); + if (isTypeParameterType(typeVariable)) { + return typeVariable; } } return undefined; @@ -17287,30 +17291,30 @@ namespace ts { getIntersectionType(newTypes, newAliasSymbol, newAliasTypeArguments) : getUnionType(newTypes, UnionReduction.Literal, newAliasSymbol, newAliasTypeArguments); } - if (flags & TypeFlags.Index) { - return getIndexType(instantiateType((type as IndexType).type, mapper)); + if (isIndexType(type)) { + return getIndexType(instantiateType(type.type, mapper)); } - if (flags & TypeFlags.TemplateLiteral) { - return getTemplateLiteralType((type as TemplateLiteralType).texts, instantiateTypes((type as TemplateLiteralType).types, mapper)); + if (isTemplateLiteralType(type)) { + return getTemplateLiteralType(type.texts, instantiateTypes(type.types, mapper)); } - if (flags & TypeFlags.StringMapping) { - return getStringMappingType((type as StringMappingType).symbol, instantiateType((type as StringMappingType).type, mapper)); + if (isStringMappingType(type)) { + return getStringMappingType(type.symbol, instantiateType(type.type, mapper)); } - if (flags & TypeFlags.IndexedAccess) { + if (isIndexedAccessType(type)) { const newAliasSymbol = aliasSymbol || type.aliasSymbol; const newAliasTypeArguments = aliasSymbol ? aliasTypeArguments : instantiateTypes(type.aliasTypeArguments, mapper); - return getIndexedAccessType(instantiateType((type as IndexedAccessType).objectType, mapper), instantiateType((type as IndexedAccessType).indexType, mapper), (type as IndexedAccessType).accessFlags, /*accessNode*/ undefined, newAliasSymbol, newAliasTypeArguments); + return getIndexedAccessType(instantiateType(type.objectType, mapper), instantiateType(type.indexType, mapper), type.accessFlags, /*accessNode*/ undefined, newAliasSymbol, newAliasTypeArguments); } - if (flags & TypeFlags.Conditional) { - return getConditionalTypeInstantiation(type as ConditionalType, combineTypeMappers((type as ConditionalType).mapper, mapper), aliasSymbol, aliasTypeArguments); + if (isConditionalType(type)) { + return getConditionalTypeInstantiation(type, combineTypeMappers(type.mapper, mapper), aliasSymbol, aliasTypeArguments); } - if (flags & TypeFlags.Substitution) { - const maybeVariable = instantiateType((type as SubstitutionType).baseType, mapper); - if (maybeVariable.flags & TypeFlags.TypeVariable) { - return getSubstitutionType(maybeVariable as TypeVariable, instantiateType((type as SubstitutionType).substitute, mapper)); + if (isSubstitutionType(type)) { + const maybeVariable = instantiateType(type.baseType, mapper); + if (isTypeVariableType(maybeVariable)) { + return getSubstitutionType(maybeVariable, instantiateType(type.substitute, mapper)); } else { - const sub = instantiateType((type as SubstitutionType).substitute, mapper); + const sub = instantiateType(type.substitute, mapper); if (sub.flags & TypeFlags.AnyOrUnknown || isTypeAssignableTo(getRestrictiveInstantiation(maybeVariable), getRestrictiveInstantiation(sub))) { return maybeVariable; } @@ -17440,8 +17444,8 @@ namespace ts { return result; } } - else if (type.flags & TypeFlags.Intersection) { - return getIntersectionType(map((type as IntersectionType).types, getTypeWithoutSignatures)); + else if (isIntersectionType(type)) { + return getIntersectionType(map(type.types, getTypeWithoutSignatures)); } return type; } @@ -17537,7 +17541,7 @@ namespace ts { } function isOrHasGenericConditional(type: Type): boolean { - return !!(type.flags & TypeFlags.Conditional || (type.flags & TypeFlags.Intersection && some((type as IntersectionType).types, isOrHasGenericConditional))); + return !!(type.flags & TypeFlags.Conditional || (isIntersectionType(type) && some(type.types, isOrHasGenericConditional))); } function elaborateError( @@ -18206,8 +18210,8 @@ namespace ts { function isEmptyObjectType(type: Type): boolean { return type.flags & TypeFlags.Object ? !isGenericMappedType(type) && isEmptyResolvedType(resolveStructuredTypeMembers(type as ObjectType)) : type.flags & TypeFlags.NonPrimitive ? true : - type.flags & TypeFlags.Union ? some((type as UnionType).types, isEmptyObjectType) : - type.flags & TypeFlags.Intersection ? every((type as UnionType).types, isEmptyObjectType) : + isUnionType(type.flags) ? some(type.types, isEmptyObjectType) : + isIntersectionType(type.flags) ? every(type.types, isEmptyObjectType) : false; } @@ -18218,13 +18222,13 @@ namespace ts { } function isUnknownLikeUnionType(type: Type) { - if (strictNullChecks && type.flags & TypeFlags.Union) { - if (!((type as UnionType).objectFlags & ObjectFlags.IsUnknownLikeUnionComputed)) { - const types = (type as UnionType).types; - (type as UnionType).objectFlags |= ObjectFlags.IsUnknownLikeUnionComputed | (types.length >= 3 && types[0].flags & TypeFlags.Undefined && + if (strictNullChecks && isUnionType(type)) { + if (!(type.objectFlags & ObjectFlags.IsUnknownLikeUnionComputed)) { + const types = type.types; + type.objectFlags |= ObjectFlags.IsUnknownLikeUnionComputed | (types.length >= 3 && types[0].flags & TypeFlags.Undefined && types[1].flags & TypeFlags.Null && some(types, isEmptyAnonymousObjectType) ? ObjectFlags.IsUnknownLikeUnion : 0); } - return !!((type as UnionType).objectFlags & ObjectFlags.IsUnknownLikeUnion); + return !!(type.objectFlags & ObjectFlags.IsUnknownLikeUnion); } return false; } @@ -18846,7 +18850,7 @@ namespace ts { // recursive intersections that are structurally similar but not exactly identical. See #37854. if (result && !inPropertyCheck && ( target.flags & TypeFlags.Intersection && (isPerformingExcessPropertyChecks || isPerformingCommonPropertyChecks) || - isNonGenericObjectType(target) && !isArrayOrTupleType(target) && source.flags & TypeFlags.Intersection && getApparentType(source).flags & TypeFlags.StructuredType && !some((source as IntersectionType).types, t => !!(getObjectFlags(t) & ObjectFlags.NonInferrableType)))) { + isNonGenericObjectType(target) && !isArrayOrTupleType(target) && isIntersectionType(source) && getApparentType(source).flags & TypeFlags.StructuredType && !some(source.types, t => !!(getObjectFlags(t) & ObjectFlags.NonInferrableType)))) { inPropertyCheck = true; result &= recursiveTypeRelatedTo(source, target, reportErrors, IntersectionState.PropertyCheck, recursionFlags); inPropertyCheck = false; @@ -18884,8 +18888,8 @@ namespace ts { else if (source.symbol && source.flags & TypeFlags.Object && globalObjectType === source) { reportError(Diagnostics.The_Object_type_is_assignable_to_very_few_other_types_Did_you_mean_to_use_the_any_type_instead); } - else if (getObjectFlags(source) & ObjectFlags.JsxAttributes && target.flags & TypeFlags.Intersection) { - const targetTypes = (target as IntersectionType).types; + else if (getObjectFlags(source) & ObjectFlags.JsxAttributes && isIntersectionType(target)) { + const targetTypes = target.types; const intrinsicAttributes = getJsxType(JsxNames.IntrinsicAttributes, errorNode); const intrinsicClassAttributes = getJsxType(JsxNames.IntrinsicClassAttributes, errorNode); if (!isErrorType(intrinsicAttributes) && !isErrorType(intrinsicClassAttributes) && @@ -19047,11 +19051,11 @@ namespace ts { someTypeRelatedToType(source as UnionType, target, reportErrors && !(source.flags & TypeFlags.Primitive), intersectionState) : eachTypeRelatedToType(source as UnionType, target, reportErrors && !(source.flags & TypeFlags.Primitive), intersectionState); } - if (target.flags & TypeFlags.Union) { - return typeRelatedToSomeType(getRegularTypeOfObjectLiteral(source), target as UnionType, reportErrors && !(source.flags & TypeFlags.Primitive) && !(target.flags & TypeFlags.Primitive)); + if (isUnionType(target)) { + return typeRelatedToSomeType(getRegularTypeOfObjectLiteral(source), target, reportErrors && !(source.flags & TypeFlags.Primitive) && !(target.flags & TypeFlags.Primitive)); } - if (target.flags & TypeFlags.Intersection) { - return typeRelatedToEachType(source, target as IntersectionType, reportErrors, IntersectionState.Target); + if (isIntersectionType(target)) { + return typeRelatedToEachType(source, target, reportErrors, IntersectionState.Target); } // Source is an intersection. For the comparable relation, if the target is a primitive type we hoist the // constraints of all non-primitive types in the source into a new intersection. We do this because the @@ -19393,22 +19397,22 @@ namespace ts { } return result; } - if (sourceFlags & TypeFlags.Index) { - return isRelatedTo((source as IndexType).type, (target as IndexType).type, RecursionFlags.Both, /*reportErrors*/ false); + if (isIndexType(source)) { + return isRelatedTo(source.type, (target as IndexType).type, RecursionFlags.Both, /*reportErrors*/ false); } - if (sourceFlags & TypeFlags.IndexedAccess) { - if (result = isRelatedTo((source as IndexedAccessType).objectType, (target as IndexedAccessType).objectType, RecursionFlags.Both, /*reportErrors*/ false)) { - if (result &= isRelatedTo((source as IndexedAccessType).indexType, (target as IndexedAccessType).indexType, RecursionFlags.Both, /*reportErrors*/ false)) { + if (isIndexedAccessType(source)) { + if (result = isRelatedTo(source.objectType, (target as IndexedAccessType).objectType, RecursionFlags.Both, /*reportErrors*/ false)) { + if (result &= isRelatedTo(source.indexType, (target as IndexedAccessType).indexType, RecursionFlags.Both, /*reportErrors*/ false)) { return result; } } } - if (sourceFlags & TypeFlags.Conditional) { - if ((source as ConditionalType).root.isDistributive === (target as ConditionalType).root.isDistributive) { - if (result = isRelatedTo((source as ConditionalType).checkType, (target as ConditionalType).checkType, RecursionFlags.Both, /*reportErrors*/ false)) { - if (result &= isRelatedTo((source as ConditionalType).extendsType, (target as ConditionalType).extendsType, RecursionFlags.Both, /*reportErrors*/ false)) { - if (result &= isRelatedTo(getTrueTypeFromConditionalType(source as ConditionalType), getTrueTypeFromConditionalType(target as ConditionalType), RecursionFlags.Both, /*reportErrors*/ false)) { - if (result &= isRelatedTo(getFalseTypeFromConditionalType(source as ConditionalType), getFalseTypeFromConditionalType(target as ConditionalType), RecursionFlags.Both, /*reportErrors*/ false)) { + if (isConditionalType(source)) { + if (source.root.isDistributive === (target as ConditionalType).root.isDistributive) { + if (result = isRelatedTo(source.checkType, (target as ConditionalType).checkType, RecursionFlags.Both, /*reportErrors*/ false)) { + if (result &= isRelatedTo(source.extendsType, (target as ConditionalType).extendsType, RecursionFlags.Both, /*reportErrors*/ false)) { + if (result &= isRelatedTo(getTrueTypeFromConditionalType(source), getTrueTypeFromConditionalType(target as ConditionalType), RecursionFlags.Both, /*reportErrors*/ false)) { + if (result &= isRelatedTo(getFalseTypeFromConditionalType(source), getFalseTypeFromConditionalType(target as ConditionalType), RecursionFlags.Both, /*reportErrors*/ false)) { return result; } } @@ -19416,8 +19420,8 @@ namespace ts { } } } - if (sourceFlags & TypeFlags.Substitution) { - return isRelatedTo((source as SubstitutionType).substitute, (target as SubstitutionType).substitute, RecursionFlags.Both, /*reportErrors*/ false); + if (isSubstitutionType(source)) { + return isRelatedTo(source.substitute, (target as SubstitutionType).substitute, RecursionFlags.Both, /*reportErrors*/ false); } if (!(sourceFlags & TypeFlags.Object)) { return Ternary.False; @@ -19441,7 +19445,7 @@ namespace ts { // needs to have its constraint hoisted into an intersection with said type parameter, this way // the type param can be compared with itself in the target (with the influence of its constraint to match other parts) // For example, if `T extends 1 | 2` and `U extends 2 | 3` and we compare `T & U` to `T & U & (1 | 2 | 3)` - const constraint = getEffectiveConstraintOfIntersection(source.flags & TypeFlags.Intersection ? (source as IntersectionType).types: [source], !!(target.flags & TypeFlags.Union)); + const constraint = getEffectiveConstraintOfIntersection(isIntersectionType(source) ? source.types : [source], !!(target.flags & TypeFlags.Union)); if (constraint && everyType(constraint, c => c !== source)) { // Skip comparison if expansion contains the source itself // TODO: Stack errors so we get a pyramid for the "normal" comparison above, _and_ a second for this if (result = isRelatedTo(constraint, target, RecursionFlags.Source, /*reportErrors*/ false, /*headMessage*/ undefined, intersectionState)) { @@ -19511,11 +19515,11 @@ namespace ts { return Ternary.False; } } - else if (targetFlags & TypeFlags.Index) { - const targetType = (target as IndexType).type; + else if (isIndexType(target)) { + const targetType = target.type; // A keyof S is related to a keyof T if T is related to S. - if (sourceFlags & TypeFlags.Index) { - if (result = isRelatedTo(targetType, (source as IndexType).type, RecursionFlags.Both, /*reportErrors*/ false)) { + if (isIndexType(source)) { + if (result = isRelatedTo(targetType, source.type, RecursionFlags.Both, /*reportErrors*/ false)) { return result; } } @@ -19535,7 +19539,7 @@ namespace ts { // false positives. For example, given 'T extends { [K in keyof T]: string }', // 'keyof T' has itself as its constraint and produces a Ternary.Maybe when // related to other types. - if (isRelatedTo(source, getIndexType(constraint, (target as IndexType).stringsOnly), RecursionFlags.Target, reportErrors) === Ternary.True) { + if (isRelatedTo(source, getIndexType(constraint, target.stringsOnly), RecursionFlags.Target, reportErrors) === Ternary.True) { return Ternary.True; } } @@ -19570,12 +19574,12 @@ namespace ts { } } } - else if (targetFlags & TypeFlags.IndexedAccess) { - if (sourceFlags & TypeFlags.IndexedAccess) { + else if (isIndexedAccessType(target)) { + if (isIndexedAccessType(source)) { // Relate components directly before falling back to constraint relationships // A type S[K] is related to a type T[J] if S is related to T and K is related to J. - if (result = isRelatedTo((source as IndexedAccessType).objectType, (target as IndexedAccessType).objectType, RecursionFlags.Both, reportErrors)) { - result &= isRelatedTo((source as IndexedAccessType).indexType, (target as IndexedAccessType).indexType, RecursionFlags.Both, reportErrors); + if (result = isRelatedTo(source.objectType, target.objectType, RecursionFlags.Both, reportErrors)) { + result &= isRelatedTo(source.indexType, target.indexType, RecursionFlags.Both, reportErrors); } if (result) { return result; @@ -19587,8 +19591,8 @@ namespace ts { // A type S is related to a type T[K] if S is related to C, where C is the base // constraint of T[K] for writing. if (relation === assignableRelation || relation === comparableRelation) { - const objectType = (target as IndexedAccessType).objectType; - const indexType = (target as IndexedAccessType).indexType; + const objectType = target.objectType; + const indexType = target.indexType; const baseObjectType = getBaseConstraintOfType(objectType) || objectType; const baseIndexType = getBaseConstraintOfType(indexType) || indexType; if (!isGenericObjectType(baseObjectType) && !isGenericIndexType(baseIndexType)) { @@ -19621,8 +19625,8 @@ namespace ts { if (!(modifiers & MappedTypeModifiers.ExcludeOptional)) { // If the mapped type has shape `{ [P in Q]: T[P] }`, // source `S` is related to target if `T` = `S`, i.e. `S` is related to `{ [P in Q]: S[P] }`. - if (!keysRemapped && templateType.flags & TypeFlags.IndexedAccess && (templateType as IndexedAccessType).objectType === source && - (templateType as IndexedAccessType).indexType === getTypeParameterFromMappedType(target)) { + if (!keysRemapped && isIndexedAccessType(templateType) && templateType.objectType === source && + templateType.indexType === getTypeParameterFromMappedType(target)) { return Ternary.True; } if (!isGenericMappedType(source)) { @@ -19646,8 +19650,8 @@ namespace ts { // Fastpath: When the template type has the form `Obj[P]` where `P` is the mapped type parameter, directly compare source `S` with `Obj` // to avoid creating the (potentially very large) number of new intermediate types made by manufacturing `S[P]`. const nonNullComponent = extractTypesOfKind(templateType, ~TypeFlags.Nullable); - if (!keysRemapped && nonNullComponent.flags & TypeFlags.IndexedAccess && (nonNullComponent as IndexedAccessType).indexType === typeParameter) { - if (result = isRelatedTo(source, (nonNullComponent as IndexedAccessType).objectType, RecursionFlags.Target, reportErrors)) { + if (!keysRemapped && isIndexedAccessType(nonNullComponent) && nonNullComponent.indexType === typeParameter) { + if (result = isRelatedTo(source, nonNullComponent.objectType, RecursionFlags.Target, reportErrors)) { return result; } } @@ -19678,39 +19682,38 @@ namespace ts { } } } - else if (targetFlags & TypeFlags.Conditional) { + else if (isConditionalType(target)) { // If we reach 10 levels of nesting for the same conditional type, assume it is an infinitely expanding recursive // conditional type and bail out with a Ternary.Maybe result. if (isDeeplyNestedType(target, targetStack, targetDepth, 10)) { return Ternary.Maybe; } - const c = target as ConditionalType; // We check for a relationship to a conditional type target only when the conditional type has no // 'infer' positions and is not distributive or is distributive but doesn't reference the check type // parameter in either of the result types. - if (!c.root.inferTypeParameters && !isDistributionDependent(c.root)) { + if (!target.root.inferTypeParameters && !isDistributionDependent(target.root)) { // Check if the conditional is always true or always false but still deferred for distribution purposes. - const skipTrue = !isTypeAssignableTo(getPermissiveInstantiation(c.checkType), getPermissiveInstantiation(c.extendsType)); - const skipFalse = !skipTrue && isTypeAssignableTo(getRestrictiveInstantiation(c.checkType), getRestrictiveInstantiation(c.extendsType)); + const skipTrue = !isTypeAssignableTo(getPermissiveInstantiation(target.checkType), getPermissiveInstantiation(target.extendsType)); + const skipFalse = !skipTrue && isTypeAssignableTo(getRestrictiveInstantiation(target.checkType), getRestrictiveInstantiation(target.extendsType)); // TODO: Find a nice way to include potential conditional type breakdowns in error output, if they seem good (they usually don't) - if (result = skipTrue ? Ternary.True : isRelatedTo(source, getTrueTypeFromConditionalType(c), RecursionFlags.Target, /*reportErrors*/ false)) { - result &= skipFalse ? Ternary.True : isRelatedTo(source, getFalseTypeFromConditionalType(c), RecursionFlags.Target, /*reportErrors*/ false); + if (result = skipTrue ? Ternary.True : isRelatedTo(source, getTrueTypeFromConditionalType(target), RecursionFlags.Target, /*reportErrors*/ false)) { + result &= skipFalse ? Ternary.True : isRelatedTo(source, getFalseTypeFromConditionalType(target), RecursionFlags.Target, /*reportErrors*/ false); if (result) { return result; } } } } - else if (targetFlags & TypeFlags.TemplateLiteral) { - if (sourceFlags & TypeFlags.TemplateLiteral) { + else if (isTemplateLiteralType(target)) { + if (isTemplateLiteralType(source)) { if (relation === comparableRelation) { - return templateLiteralTypesDefinitelyUnrelated(source as TemplateLiteralType, target as TemplateLiteralType) ? Ternary.False : Ternary.True; + return templateLiteralTypesDefinitelyUnrelated(source, target) ? Ternary.False : Ternary.True; } // Report unreliable variance for type variables referenced in template literal type placeholders. // For example, `foo-${number}` is related to `foo-${string}` even though number isn't related to string. instantiateType(source, reportUnreliableMapper); } - if (isTypeMatchedByTemplateLiteralType(source, target as TemplateLiteralType)) { + if (isTypeMatchedByTemplateLiteralType(source, target)) { return Ternary.True; } } @@ -19724,7 +19727,7 @@ namespace ts { if (sourceFlags & TypeFlags.TypeVariable) { // IndexedAccess comparisons are handled above in the `targetFlags & TypeFlage.IndexedAccess` branch - if (!(sourceFlags & TypeFlags.IndexedAccess && targetFlags & TypeFlags.IndexedAccess)) { + if (!(isIndexedAccessType(source) && isIndexedAccessType(target))) { const constraint = getConstraintOfType(source as TypeVariable) || unknownType; // hi-speed no-this-instantiation check (less accurate, but avoids costly `this`-instantiation when the constraint will suffice), see #28231 for report on why this is needed if (result = isRelatedTo(constraint, target, RecursionFlags.Source, /*reportErrors*/ false, /*headMessage*/ undefined, intersectionState)) { @@ -19737,9 +19740,9 @@ namespace ts { if (isMappedTypeGenericIndexedAccess(source)) { // For an indexed access type { [P in K]: E}[X], above we have already explored an instantiation of E with X // substituted for P. We also want to explore type { [P in K]: E }[C], where C is the constraint of X. - const indexConstraint = getConstraintOfType((source as IndexedAccessType).indexType); + const indexConstraint = getConstraintOfType(source.indexType); if (indexConstraint) { - if (result = isRelatedTo(getIndexedAccessType((source as IndexedAccessType).objectType, indexConstraint), target, RecursionFlags.Source, reportErrors)) { + if (result = isRelatedTo(getIndexedAccessType(source.objectType, indexConstraint), target, RecursionFlags.Source, reportErrors)) { return result; } } @@ -19775,30 +19778,30 @@ namespace ts { } } } - else if (sourceFlags & TypeFlags.Conditional) { + else if (isConditionalType(source)) { // If we reach 10 levels of nesting for the same conditional type, assume it is an infinitely expanding recursive // conditional type and bail out with a Ternary.Maybe result. if (isDeeplyNestedType(source, sourceStack, sourceDepth, 10)) { return Ternary.Maybe; } - if (targetFlags & TypeFlags.Conditional) { + if (isConditionalType(target)) { // Two conditional types 'T1 extends U1 ? X1 : Y1' and 'T2 extends U2 ? X2 : Y2' are related if // one of T1 and T2 is related to the other, U1 and U2 are identical types, X1 is related to X2, // and Y1 is related to Y2. - const sourceParams = (source as ConditionalType).root.inferTypeParameters; - let sourceExtends = (source as ConditionalType).extendsType; + const sourceParams = source.root.inferTypeParameters; + let sourceExtends = source.extendsType; let mapper: TypeMapper | undefined; if (sourceParams) { // If the source has infer type parameters, we instantiate them in the context of the target const ctx = createInferenceContext(sourceParams, /*signature*/ undefined, InferenceFlags.None, isRelatedToWorker); - inferTypes(ctx.inferences, (target as ConditionalType).extendsType, sourceExtends, InferencePriority.NoConstraints | InferencePriority.AlwaysStrict); + inferTypes(ctx.inferences, target.extendsType, sourceExtends, InferencePriority.NoConstraints | InferencePriority.AlwaysStrict); sourceExtends = instantiateType(sourceExtends, ctx.mapper); mapper = ctx.mapper; } - if (isTypeIdenticalTo(sourceExtends, (target as ConditionalType).extendsType) && - (isRelatedTo((source as ConditionalType).checkType, (target as ConditionalType).checkType, RecursionFlags.Both) || isRelatedTo((target as ConditionalType).checkType, (source as ConditionalType).checkType, RecursionFlags.Both))) { - if (result = isRelatedTo(instantiateType(getTrueTypeFromConditionalType(source as ConditionalType), mapper), getTrueTypeFromConditionalType(target as ConditionalType), RecursionFlags.Both, reportErrors)) { - result &= isRelatedTo(getFalseTypeFromConditionalType(source as ConditionalType), getFalseTypeFromConditionalType(target as ConditionalType), RecursionFlags.Both, reportErrors); + if (isTypeIdenticalTo(sourceExtends, target.extendsType) && + (isRelatedTo(source.checkType, target.checkType, RecursionFlags.Both) || isRelatedTo(target.checkType, source.checkType, RecursionFlags.Both))) { + if (result = isRelatedTo(instantiateType(getTrueTypeFromConditionalType(source), mapper), getTrueTypeFromConditionalType(target), RecursionFlags.Both, reportErrors)) { + result &= isRelatedTo(getFalseTypeFromConditionalType(source), getFalseTypeFromConditionalType(target), RecursionFlags.Both, reportErrors); } if (result) { return result; @@ -19808,7 +19811,7 @@ namespace ts { else { // conditionals aren't related to one another via distributive constraint as it is much too inaccurate and allows way // more assignments than are desirable (since it maps the source check type to its constraint, it loses information) - const distributiveConstraint = hasNonCircularBaseConstraint(source) ? getConstraintOfDistributiveConditionalType(source as ConditionalType) : undefined; + const distributiveConstraint = hasNonCircularBaseConstraint(source) ? getConstraintOfDistributiveConditionalType(source) : undefined; if (distributiveConstraint) { if (result = isRelatedTo(distributiveConstraint, target, RecursionFlags.Source, reportErrors)) { return result; @@ -19818,7 +19821,7 @@ namespace ts { // conditionals _can_ be related to one another via normal constraint, as, eg, `A extends B ? O : never` should be assignable to `O` // when `O` is a conditional (`never` is trivially assignable to `O`, as is `O`!). - const defaultConstraint = getDefaultConstraintOfConditionalType(source as ConditionalType); + const defaultConstraint = getDefaultConstraintOfConditionalType(source); if (defaultConstraint) { if (result = isRelatedTo(defaultConstraint, target, RecursionFlags.Source, reportErrors)) { return result; @@ -20551,7 +20554,7 @@ namespace ts { function membersRelatedToIndexInfo(source: Type, targetInfo: IndexInfo, reportErrors: boolean): Ternary { let result = Ternary.True; const keyType = targetInfo.keyType; - const props = source.flags & TypeFlags.Intersection ? getPropertiesOfUnionOrIntersectionType(source as IntersectionType) : getPropertiesOfObjectType(source); + const props = isIntersectionType(source) ? getPropertiesOfUnionOrIntersectionType(source) : getPropertiesOfObjectType(source); for (const prop of props) { // Skip over ignored JSX and symbol-named members if (isIgnoredJsxProperty(source, prop)) { @@ -20769,8 +20772,8 @@ namespace ts { return resolved.callSignatures.length === 0 && resolved.constructSignatures.length === 0 && resolved.indexInfos.length === 0 && resolved.properties.length > 0 && every(resolved.properties, p => !!(p.flags & SymbolFlags.Optional)); } - if (type.flags & TypeFlags.Intersection) { - return every((type as IntersectionType).types, isWeakType); + if (isIntersectionType(type)) { + return every(type.types, isWeakType); } return false; } @@ -21057,16 +21060,16 @@ namespace ts { if (type.flags & TypeFlags.TypeParameter) { return type.symbol; } - if (type.flags & TypeFlags.IndexedAccess) { + if (isIndexedAccessType(type)) { // Identity is the leftmost object type in a chain of indexed accesses, eg, in A[P][Q] it is A do { - type = (type as IndexedAccessType).objectType; - } while (type.flags & TypeFlags.IndexedAccess); + type = type.objectType; + } while (isIndexedAccessType(type)); return type; } - if (type.flags & TypeFlags.Conditional) { + if (isConditionalType(type)) { // The root object represents the origin of the conditional type - return (type as ConditionalType).root; + return type.root; } return type; } @@ -21333,17 +21336,17 @@ namespace ts { } function isUnitLikeType(type: Type): boolean { - return type.flags & TypeFlags.Intersection ? some((type as IntersectionType).types, isUnitType) : + return isIntersectionType(type) ? some(type.types, isUnitType) : !!(type.flags & TypeFlags.Unit); } function extractUnitType(type: Type) { - return type.flags & TypeFlags.Intersection ? find((type as IntersectionType).types, isUnitType) || type : type; + return isIntersectionType(type) ? find(type.types, isUnitType) || type : type; } function isLiteralType(type: Type): boolean { return type.flags & TypeFlags.Boolean ? true : - type.flags & TypeFlags.Union ? type.flags & TypeFlags.EnumLiteral ? true : every((type as UnionType).types, isUnitType) : + isUnionType(type) ? type.flags & TypeFlags.EnumLiteral ? true : every(type.types, isUnitType) : isUnitType(type); } @@ -21353,7 +21356,7 @@ namespace ts { type.flags & TypeFlags.NumberLiteral ? numberType : type.flags & TypeFlags.BigIntLiteral ? bigintType : type.flags & TypeFlags.BooleanLiteral ? booleanType : - type.flags & TypeFlags.Union ? getBaseTypeOfLiteralTypeUnion(type as UnionType) : + isUnionType(type) ? getBaseTypeOfLiteralTypeUnion(type) : type; } @@ -21565,8 +21568,8 @@ namespace ts { */ function isObjectTypeWithInferableIndex(type: Type): boolean { const objectFlags = getObjectFlags(type); - return type.flags & TypeFlags.Intersection - ? every((type as IntersectionType).types, isObjectTypeWithInferableIndex) + return isIntersectionType(type) + ? every(type.types, isObjectTypeWithInferableIndex) : !!( type.symbol && (type.symbol.flags & (SymbolFlags.ObjectLiteral | SymbolFlags.TypeLiteral | SymbolFlags.Enum | SymbolFlags.ValueModule)) !== 0 @@ -21728,8 +21731,8 @@ namespace ts { // union includes empty object types (e.g. reducing {} | string to just {}). result = getUnionType(widenedTypes, some(widenedTypes, isEmptyObjectType) ? UnionReduction.Subtype : UnionReduction.Literal); } - else if (type.flags & TypeFlags.Intersection) { - result = getIntersectionType(sameMap((type as IntersectionType).types, getWidenedType)); + else if (isIntersectionType(type)) { + result = getIntersectionType(sameMap(type.types, getWidenedType)); } else if (isArrayOrTupleType(type)) { result = createTypeReference(type.target, sameMap(getTypeArguments(type), getWidenedType)); @@ -22051,8 +22054,8 @@ namespace ts { function isTypeParameterAtTopLevel(type: Type, typeParameter: TypeParameter): boolean { return !!(type === typeParameter || - type.flags & TypeFlags.UnionOrIntersection && some((type as UnionOrIntersectionType).types, t => isTypeParameterAtTopLevel(t, typeParameter)) || - type.flags & TypeFlags.Conditional && (getTrueTypeFromConditionalType(type as ConditionalType) === typeParameter || getFalseTypeFromConditionalType(type as ConditionalType) === typeParameter)); + isUnionOrIntersectionType(type) && some(type.types, t => isTypeParameterAtTopLevel(t, typeParameter)) || + isConditionalType(type) && (getTrueTypeFromConditionalType(type) === typeParameter || getFalseTypeFromConditionalType(type) === typeParameter)); } /** Create an object with properties named in the string literal type. Every property has type `any` */ @@ -22465,7 +22468,7 @@ namespace ts { } source = getUnionType(sources); } - else if (target.flags & TypeFlags.Intersection && some((target as IntersectionType).types, + else if (isIntersectionType(target) && some(target.types, t => !!getInferenceInfoForType(t) || (isGenericMappedType(t) && !!getInferenceInfoForType(getHomomorphicTypeVariable(t) || neverType)))) { // We reduce intersection types only when they contain naked type parameters. For example, when // inferring from 'string[] & { extra: any }' to 'string[] & T' we want to remove string[] and @@ -22475,7 +22478,7 @@ namespace ts { // in such scenarios. if (!(source.flags & TypeFlags.Union)) { // Infer between identically matching source and target constituents and remove the matching types. - const [sources, targets] = inferFromMatchingTypes(source.flags & TypeFlags.Intersection ? (source as IntersectionType).types : [source], (target as IntersectionType).types, isTypeIdenticalTo); + const [sources, targets] = inferFromMatchingTypes(isIntersectionType(source) ? source.types : [source], target.types, isTypeIdenticalTo); if (sources.length === 0 || targets.length === 0) { return; } @@ -22545,12 +22548,12 @@ namespace ts { if (simplified !== target) { inferFromTypes(source, simplified); } - else if (target.flags & TypeFlags.IndexedAccess) { - const indexType = getSimplifiedType((target as IndexedAccessType).indexType, /*writing*/ false); + else if (isIndexedAccessType(target)) { + const indexType = getSimplifiedType(target.indexType, /*writing*/ false); // Generally simplifications of instantiable indexes are avoided to keep relationship checking correct, however if our target is an access, we can consider // that key of that access to be "instantiated", since we're looking to find the infernce goal in any way we can. if (indexType.flags & TypeFlags.Instantiable) { - const simplified = distributeIndexOverObjectType(getSimplifiedType((target as IndexedAccessType).objectType, /*writing*/ false), indexType, /*writing*/ false); + const simplified = distributeIndexOverObjectType(getSimplifiedType(target.objectType, /*writing*/ false), indexType, /*writing*/ false); if (simplified && simplified !== target) { inferFromTypes(source, simplified); } @@ -22563,41 +22566,40 @@ namespace ts { // If source and target are references to the same generic type, infer from type arguments inferFromTypeArguments(getTypeArguments(source as TypeReference), getTypeArguments(target as TypeReference), getVariances((source as TypeReference).target)); } - else if (source.flags & TypeFlags.Index && target.flags & TypeFlags.Index) { - inferFromContravariantTypes((source as IndexType).type, (target as IndexType).type); + else if (isIndexType(source) && isIndexType(target)) { + inferFromContravariantTypes(source.type, target.type); } - else if ((isLiteralType(source) || source.flags & TypeFlags.String) && target.flags & TypeFlags.Index) { + else if ((isLiteralType(source) || source.flags & TypeFlags.String) && isIndexType(target)) { const empty = createEmptyObjectTypeFromStringLiteral(source); - inferFromContravariantTypesWithPriority(empty, (target as IndexType).type, InferencePriority.LiteralKeyof); + inferFromContravariantTypesWithPriority(empty, target.type, InferencePriority.LiteralKeyof); } - else if (source.flags & TypeFlags.IndexedAccess && target.flags & TypeFlags.IndexedAccess) { - inferFromTypes((source as IndexedAccessType).objectType, (target as IndexedAccessType).objectType); - inferFromTypes((source as IndexedAccessType).indexType, (target as IndexedAccessType).indexType); + else if (isIndexedAccessType(source) && isIndexedAccessType(target)) { + inferFromTypes(source.objectType, target.objectType); + inferFromTypes(source.indexType, target.indexType); } - else if (source.flags & TypeFlags.StringMapping && target.flags & TypeFlags.StringMapping) { - if ((source as StringMappingType).symbol === (target as StringMappingType).symbol) { - inferFromTypes((source as StringMappingType).type, (target as StringMappingType).type); + else if (isStringMappingType(source) && isStringMappingType(target)) { + if (source.symbol === target.symbol) { + inferFromTypes(source.type, target.type); } } - else if (source.flags & TypeFlags.Substitution) { - inferFromTypes((source as SubstitutionType).baseType, target); - inferWithPriority((source as SubstitutionType).substitute, target, InferencePriority.SubstituteSource); // Make substitute inference at a lower priority + else if (isSubstitutionType(source)) { + inferFromTypes(source.baseType, target); + inferWithPriority(source.substitute, target, InferencePriority.SubstituteSource); // Make substitute inference at a lower priority } else if (target.flags & TypeFlags.Conditional) { invokeOnce(source, target, inferToConditionalType); } - else if (target.flags & TypeFlags.UnionOrIntersection) { - inferToMultipleTypes(source, (target as UnionOrIntersectionType).types, target.flags); + else if (isUnionOrIntersectionType(target)) { + inferToMultipleTypes(source, target.types, target.flags); } - else if (source.flags & TypeFlags.Union) { + else if (isUnionType(source)) { // Source is a union or intersection type, infer from each constituent type - const sourceTypes = (source as UnionOrIntersectionType).types; - for (const sourceType of sourceTypes) { + for (const sourceType of source.types) { inferFromTypes(sourceType, target); } } - else if (target.flags & TypeFlags.TemplateLiteral) { - inferToTemplateLiteralType(source, target as TemplateLiteralType); + else if (isTemplateLiteralType(target)) { + inferToTemplateLiteralType(source, target); } else { source = getReducedType(source); @@ -22737,7 +22739,7 @@ namespace ts { function getSingleTypeVariableFromIntersectionTypes(types: Type[]) { let typeVariable: Type | undefined; for (const type of types) { - const t = type.flags & TypeFlags.Intersection && find((type as IntersectionType).types, t => !!getInferenceInfoForType(t)); + const t = isIntersectionType(type) && find(type.types, t => !!getInferenceInfoForType(t)); if (!t || typeVariable && t !== typeVariable) { return undefined; } @@ -22822,21 +22824,21 @@ namespace ts { } function inferToMappedType(source: Type, target: MappedType, constraintType: Type): boolean { - if (constraintType.flags & TypeFlags.Union) { + if (isUnionType(constraintType)) { let result = false; - for (const type of (constraintType as UnionType).types) { + for (const type of constraintType.types) { result = inferToMappedType(source, target, type) || result; } return result; } - if (constraintType.flags & TypeFlags.Index) { + if (isIndexType(constraintType)) { // We're inferring from some source type S to a homomorphic mapped type { [P in keyof T]: X }, // where T is a type variable. Use inferTypeForHomomorphicMappedType to infer a suitable source // type and then make a secondary inference from that type to T. We make a secondary inference // such that direct inferences to T get priority over inferences to Partial, for example. - const inference = getInferenceInfoForType((constraintType as IndexType).type); + const inference = getInferenceInfoForType(constraintType.type); if (inference && !inference.isFixed && !isFromInferenceBlockedSource(source)) { - const inferredType = inferTypeForHomomorphicMappedType(source, target, constraintType as IndexType); + const inferredType = inferTypeForHomomorphicMappedType(source, target, constraintType); if (inferredType) { // We assign a lower priority to inferences made from types containing non-inferrable // types because we may only have a partial result (i.e. we may have failed to make @@ -22872,11 +22874,11 @@ namespace ts { } function inferToConditionalType(source: Type, target: ConditionalType) { - if (source.flags & TypeFlags.Conditional) { - inferFromTypes((source as ConditionalType).checkType, target.checkType); - inferFromTypes((source as ConditionalType).extendsType, target.extendsType); - inferFromTypes(getTrueTypeFromConditionalType(source as ConditionalType), getTrueTypeFromConditionalType(target)); - inferFromTypes(getFalseTypeFromConditionalType(source as ConditionalType), getFalseTypeFromConditionalType(target)); + if (isConditionalType(source)) { + inferFromTypes(source.checkType, target.checkType); + inferFromTypes(source.extendsType, target.extendsType); + inferFromTypes(getTrueTypeFromConditionalType(source), getTrueTypeFromConditionalType(target)); + inferFromTypes(getFalseTypeFromConditionalType(source), getFalseTypeFromConditionalType(target)); } else { const targetTypes = [getTrueTypeFromConditionalType(target), getFalseTypeFromConditionalType(target)]; @@ -23716,11 +23718,11 @@ namespace ts { if (flags & TypeFlags.Never) { return TypeFacts.None; } - if (flags & TypeFlags.Union) { - return reduceLeft((type as UnionType).types, (facts, t) => facts | getTypeFacts(t), TypeFacts.None); + if (isUnionType(type)) { + return reduceLeft(type.types, (facts, t) => facts | getTypeFacts(t), TypeFacts.None); } - if (flags & TypeFlags.Intersection) { - return getIntersectionTypeFacts(type as IntersectionType); + if (isIntersectionType(type)) { + return getIntersectionTypeFacts(type); } return TypeFacts.UnknownFacts; } @@ -25028,7 +25030,7 @@ namespace ts { if (type.flags & TypeFlags.Union || type.flags & TypeFlags.Object && declaredType !== type || isThisTypeParameter(type) - || type.flags & TypeFlags.Intersection && every((type as IntersectionType).types, t => t.symbol !== globalThisSymbol)) { + || isIntersectionType(type) && every(type.types, t => t.symbol !== globalThisSymbol)) { return filterType(type, t => isTypePresencePossible(t, name, assumeTrue)); } return type; @@ -25656,8 +25658,8 @@ namespace ts { } function isGenericTypeWithUnionConstraint(type: Type): boolean { - return type.flags & TypeFlags.Intersection ? - some((type as IntersectionType).types, isGenericTypeWithUnionConstraint) : + return isIntersectionType(type) ? + some(type.types, isGenericTypeWithUnionConstraint) : !!(type.flags & TypeFlags.Instantiable && getBaseConstraintOrType(type).flags & (TypeFlags.Nullable | TypeFlags.Union)); } @@ -26599,7 +26601,7 @@ namespace ts { function getThisTypeFromContextualType(type: Type): Type | undefined { return mapType(type, t => { - return t.flags & TypeFlags.Intersection ? forEach((t as IntersectionType).types, getThisTypeArgument) : getThisTypeArgument(t); + return isIntersectionType(t) ? forEach(t.types, getThisTypeArgument) : getThisTypeArgument(t); }); } @@ -27063,13 +27065,12 @@ namespace ts { function getTypeOfPropertyOfContextualType(type: Type, name: __String, nameType?: Type) { return mapType(type, (t): Type | undefined => { - if (t.flags & TypeFlags.Intersection) { - const intersection = t as IntersectionType; - let newTypes = mapDefined(intersection.types, getTypeOfConcretePropertyOfContextualType); + if (isIntersectionType(t)) { + let newTypes = mapDefined(t.types, getTypeOfConcretePropertyOfContextualType); if (newTypes.length > 0) { return getIntersectionType(newTypes); } - newTypes = mapDefined(intersection.types, getTypeOfApplicableIndexInfoOfContextualType); + newTypes = mapDefined(t.types, getTypeOfApplicableIndexInfoOfContextualType); if (newTypes.length > 0) { return getIntersectionType(newTypes); } @@ -27320,11 +27321,11 @@ namespace ts { if (type.flags & TypeFlags.Instantiable) { return instantiateType(type, mapper); } - if (type.flags & TypeFlags.Union) { - return getUnionType(map((type as UnionType).types, t => instantiateInstantiableTypes(t, mapper)), UnionReduction.None); + if (isUnionType(type)) { + return getUnionType(map(type.types, t => instantiateInstantiableTypes(t, mapper)), UnionReduction.None); } - if (type.flags & TypeFlags.Intersection) { - return getIntersectionType(map((type as IntersectionType).types, t => instantiateInstantiableTypes(t, mapper))); + if (isIntersectionType(type)) { + return getIntersectionType(map(type.types, t => instantiateInstantiableTypes(t, mapper))); } return type; } @@ -28776,8 +28777,8 @@ namespace ts { function isExcessPropertyCheckTarget(type: Type): boolean { return !!(type.flags & TypeFlags.Object && !(getObjectFlags(type) & ObjectFlags.ObjectLiteralPatternWithComputedProperties) || type.flags & TypeFlags.NonPrimitive || - type.flags & TypeFlags.Union && some((type as UnionType).types, isExcessPropertyCheckTarget) || - type.flags & TypeFlags.Intersection && every((type as IntersectionType).types, isExcessPropertyCheckTarget)); + isUnionType(type) && some(type.types, isExcessPropertyCheckTarget) || + isIntersectionType(type) && every(type.types, isExcessPropertyCheckTarget)); } function checkJsxExpression(node: JsxExpression, checkMode?: CheckMode) { @@ -31424,11 +31425,10 @@ namespace ts { return false; } const firstBase = baseTypes[0]; - if (firstBase.flags & TypeFlags.Intersection) { - const types = (firstBase as IntersectionType).types; - const mixinFlags = findMixins(types); + if (isIntersectionType(firstBase)) { + const mixinFlags = findMixins(firstBase.types); let i = 0; - for (const intersectionMember of (firstBase as IntersectionType).types) { + for (const intersectionMember of firstBase.types) { // We want to ignore mixin ctors if (!mixinFlags[i]) { if (getObjectFlags(intersectionMember) & (ObjectFlags.Class | ObjectFlags.Interface)) { @@ -32300,8 +32300,8 @@ namespace ts { else if (type.flags & TypeFlags.Union) { return mapType(type, getInstantiatedType); } - else if (type.flags & TypeFlags.Intersection) { - return getIntersectionType(sameMap((type as IntersectionType).types, getInstantiatedTypePart)); + else if (isIntersectionType(type)) { + return getIntersectionType(sameMap(type.types, getInstantiatedTypePart)); } return type; } @@ -35999,12 +35999,12 @@ namespace ts { } function checkIndexedAccessIndexType(type: Type, accessNode: IndexedAccessTypeNode | ElementAccessExpression) { - if (!(type.flags & TypeFlags.IndexedAccess)) { + if (!isIndexedAccessType(type)) { return type; } // Check if the index type is assignable to 'keyof T' for the object type. - const objectType = (type as IndexedAccessType).objectType; - const indexType = (type as IndexedAccessType).indexType; + const objectType = type.objectType; + const indexType = type.indexType; if (isTypeAssignableTo(indexType, getIndexType(objectType, /*stringsOnly*/ false))) { if (accessNode.kind === SyntaxKind.ElementAccessExpression && isAssignmentTarget(accessNode) && getObjectFlags(objectType) & ObjectFlags.Mapped && getMappedTypeModifiers(objectType as MappedType) & MappedTypeModifiers.IncludeReadonly) { @@ -45567,11 +45567,11 @@ namespace ts { // perfect overlap of keys return target; } - else if (isUnitType(overlap) || overlap.flags & TypeFlags.Union) { + else if (isUnitType(overlap) || isUnionType(overlap)) { // We only want to account for literal types otherwise. // If we have a union of index types, it seems likely that we // needed to elaborate between two generic mapped types anyway. - const len = overlap.flags & TypeFlags.Union ? countWhere((overlap as UnionType).types, isUnitType) : 1; + const len = isUnionType(overlap) ? countWhere(overlap.types, isUnitType) : 1; if (len >= matchingCount) { bestMatch = target; matchingCount = len; diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 4ec193839e680..911e788d039c8 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -7674,8 +7674,56 @@ namespace ts { factory.createStringLiteral(name, !!singleQuote); } + export function isConditionalType(type: Type): type is ConditionalType { + return !!(type.flags & TypeFlags.Conditional); + } + + export function isIndexType(type: Type): type is IndexType { + return !!(type.flags & TypeFlags.Index); + } + + export function isIndexedAccessType(type: Type): type is IndexedAccessType { + return !!(type.flags & TypeFlags.IndexedAccess); + } + + export function isIntersectionType(type: Type): type is IntersectionType { + return !!(type.flags & TypeFlags.Intersection); + } + + export function isObjectType(type: Type): type is ObjectType { + return !!(type.flags & TypeFlags.Object); + } + + export function isStringMappingType(type: Type): type is StringMappingType { + return !!(type.flags & TypeFlags.StringMapping); + } + + export function isSubstitutionType(type: Type): type is SubstitutionType { + return !!(type.flags & TypeFlags.Substitution); + } + + export function isTemplateLiteralType(type: Type): type is TemplateLiteralType { + return !!(type.flags & TypeFlags.TemplateLiteral); + } + + export function isTypeParameterType(type: Type): type is TypeParameter { + return !!(type.flags & TypeFlags.TypeParameter); + } + export function isThisTypeParameter(type: Type): boolean { - return !!(type.flags & TypeFlags.TypeParameter && (type as TypeParameter).isThisType); + return isTypeParameterType(type) && !!type.isThisType; + } + + export function isTypeVariableType(type: Type): type is TypeVariable { + return !!(type.flags & TypeFlags.TypeVariable); + } + + export function isUnionType(type: Type): type is UnionType { + return !!(type.flags & TypeFlags.Union); + } + + export function isUnionOrIntersectionType(type: Type): type is IntersectionType | UnionType { + return !!(type.flags & TypeFlags.Union | TypeFlags.Intersection); } export interface NodeModulePathParts { From 96b0faa88371fd03d6adc9c17b6eaf9f7c2e0dd5 Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Fri, 22 Jul 2022 18:32:19 -0400 Subject: [PATCH 2/7] Fix .flags typo --- src/compiler/checker.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index b67213f575585..e40de788b1d8c 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -12028,7 +12028,7 @@ namespace ts { if (isMappedTypeGenericIndexedAccess(type)) { // For indexed access types of the form { [P in K]: E }[X], where K is non-generic and X is generic, // we substitute an instantiation of E where P is replaced with X. - return substituteIndexedMappedType(type.objectType as MappedType, type.indexType); + return substituteIndexedMappedType(type.objectType, type.indexType); } const indexConstraint = getSimplifiedTypeOrConstraint(type.indexType); if (indexConstraint && indexConstraint !== type.indexType) { @@ -18210,8 +18210,8 @@ namespace ts { function isEmptyObjectType(type: Type): boolean { return type.flags & TypeFlags.Object ? !isGenericMappedType(type) && isEmptyResolvedType(resolveStructuredTypeMembers(type as ObjectType)) : type.flags & TypeFlags.NonPrimitive ? true : - isUnionType(type.flags) ? some(type.types, isEmptyObjectType) : - isIntersectionType(type.flags) ? every(type.types, isEmptyObjectType) : + isUnionType(type) ? some(type.types, isEmptyObjectType) : + isIntersectionType(type) ? every(type.types, isEmptyObjectType) : false; } From b8cb12a233a72faa100c26bd85dc9367db561886 Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Sat, 23 Jul 2022 10:03:08 -0400 Subject: [PATCH 3/7] fix: isUnionOrIntersectionType --- src/compiler/utilities.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 911e788d039c8..456e02d57d596 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -7723,7 +7723,7 @@ namespace ts { } export function isUnionOrIntersectionType(type: Type): type is IntersectionType | UnionType { - return !!(type.flags & TypeFlags.Union | TypeFlags.Intersection); + return !!(type.flags & TypeFlags.UnionOrIntersection); } export interface NodeModulePathParts { From d1d103e35cac0dc4b8ddf42a5c842e370eac1750 Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Sat, 23 Jul 2022 10:44:04 -0400 Subject: [PATCH 4/7] Converted some more locations --- src/compiler/checker.ts | 186 +++++++++++++++++++------------------- src/compiler/utilities.ts | 12 +++ 2 files changed, 105 insertions(+), 93 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index e40de788b1d8c..76a37c60dc2d2 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4988,18 +4988,18 @@ namespace ts { if (type.flags & TypeFlags.EnumLike) { return symbolToTypeNode(type.symbol, context, SymbolFlags.Type); } - if (type.flags & TypeFlags.StringLiteral) { - context.approximateLength += ((type as StringLiteralType).value.length + 2); - return factory.createLiteralTypeNode(setEmitFlags(factory.createStringLiteral((type as StringLiteralType).value, !!(context.flags & NodeBuilderFlags.UseSingleQuotesForStringLiteralType)), EmitFlags.NoAsciiEscaping)); + if (isStringLiteralType(type)) { + context.approximateLength += (type.value.length + 2); + return factory.createLiteralTypeNode(setEmitFlags(factory.createStringLiteral(type.value, !!(context.flags & NodeBuilderFlags.UseSingleQuotesForStringLiteralType)), EmitFlags.NoAsciiEscaping)); } - if (type.flags & TypeFlags.NumberLiteral) { - const value = (type as NumberLiteralType).value; + if (isNumberLiteralType(type)) { + const value = type.value; context.approximateLength += ("" + value).length; return factory.createLiteralTypeNode(value < 0 ? factory.createPrefixUnaryExpression(SyntaxKind.MinusToken, factory.createNumericLiteral(-value)) : factory.createNumericLiteral(value)); } - if (type.flags & TypeFlags.BigIntLiteral) { - context.approximateLength += (pseudoBigIntToString((type as BigIntLiteralType).value).length) + 1; - return factory.createLiteralTypeNode((factory.createBigIntLiteral((type as BigIntLiteralType).value))); + if (isBigIntLiteralType(type)) { + context.approximateLength += (pseudoBigIntToString(type.value).length) + 1; + return factory.createLiteralTypeNode((factory.createBigIntLiteral(type.value))); } if (type.flags & TypeFlags.BooleanLiteral) { context.approximateLength += (type as IntrinsicType).intrinsicName.length; @@ -11915,8 +11915,8 @@ namespace ts { /** Return properties of an object type or an empty array for other types */ function getPropertiesOfObjectType(type: Type): Symbol[] { - if (type.flags & TypeFlags.Object) { - return resolveStructuredTypeMembers(type as ObjectType).properties; + if (isObjectType(type)) { + return resolveStructuredTypeMembers(type).properties; } return emptyArray; } @@ -11925,8 +11925,8 @@ namespace ts { * return the symbol for that property. Otherwise return undefined. */ function getPropertyOfObjectType(type: Type, name: __String): Symbol | undefined { - if (type.flags & TypeFlags.Object) { - const resolved = resolveStructuredTypeMembers(type as ObjectType); + if (isObjectType(type)) { + const resolved = resolveStructuredTypeMembers(type); const symbol = resolved.members.get(name); if (symbol && symbolIsValue(symbol)) { return symbol; @@ -12208,8 +12208,8 @@ namespace ts { constraint : getBaseConstraint(constraint); } - if (t.flags & TypeFlags.UnionOrIntersection) { - const types = (t as UnionOrIntersectionType).types; + if (isUnionOrIntersectionType(t)) { + const types = t.types; const baseTypes: Type[] = []; let different = false; for (const type of types) { @@ -12234,10 +12234,10 @@ namespace ts { if (t.flags & TypeFlags.Index) { return keyofConstraintType; } - if (t.flags & TypeFlags.TemplateLiteral) { - const types = (t as TemplateLiteralType).types; + if (isTemplateLiteralType(t)) { + const types = t.types; const constraints = mapDefined(types, getBaseConstraint); - return constraints.length === types.length ? getTemplateLiteralType((t as TemplateLiteralType).texts, constraints) : stringType; + return constraints.length === types.length ? getTemplateLiteralType(t.texts, constraints) : stringType; } if (isStringMappingType(t)) { const constraint = getBaseConstraint(t.type); @@ -15412,9 +15412,9 @@ namespace ts { text += addText; if (!isTextsArray) return true; } - else if (t.flags & TypeFlags.TemplateLiteral) { - text += (t as TemplateLiteralType).texts[0]; - if (!addSpans((t as TemplateLiteralType).texts, (t as TemplateLiteralType).types)) return false; + else if (isTemplateLiteralType(t)) { + text += t.texts[0]; + if (!addSpans(t.texts, t.types)) return false; text += addText; if (!isTextsArray) return true; } @@ -15437,8 +15437,8 @@ namespace ts { function getTemplateStringForType(type: Type) { return type.flags & TypeFlags.StringLiteral ? (type as StringLiteralType).value : - type.flags & TypeFlags.NumberLiteral ? "" + (type as NumberLiteralType).value : - type.flags & TypeFlags.BigIntLiteral ? pseudoBigIntToString((type as BigIntLiteralType).value) : + isNumberLiteralType(type) ? "" + type.value : + isBigIntLiteralType(type) ? pseudoBigIntToString(type.value) : type.flags & (TypeFlags.BooleanLiteral | TypeFlags.Nullable) ? (type as IntrinsicType).intrinsicName : undefined; } @@ -15455,8 +15455,8 @@ namespace ts { // Mapping> === Mapping type.flags & TypeFlags.StringMapping && symbol === type.symbol ? type : isGenericIndexType(type) || isPatternLiteralPlaceholderType(type) ? getStringMappingTypeForGenericType(symbol, isPatternLiteralPlaceholderType(type) && !(type.flags & TypeFlags.StringMapping) ? getTemplateLiteralType(["", ""], [type]) : type) : - type.flags & TypeFlags.StringLiteral ? getStringLiteralType(applyStringMapping(symbol, (type as StringLiteralType).value)) : - type.flags & TypeFlags.TemplateLiteral ? getTemplateLiteralType(...applyTemplateStringMapping(symbol, (type as TemplateLiteralType).texts, (type as TemplateLiteralType).types)) : + isStringLiteralType(type) ? getStringLiteralType(applyStringMapping(symbol, type.value)) : + isTemplateLiteralType(type) ? getTemplateLiteralType(...applyTemplateStringMapping(symbol, type.texts, type.types)) : type; } @@ -15679,11 +15679,11 @@ namespace ts { const symbolName = getFullyQualifiedName((indexType as UniqueESSymbolType).symbol, accessExpression); errorInfo = chainDiagnosticMessages(/* details */ undefined, Diagnostics.Property_0_does_not_exist_on_type_1, "[" + symbolName + "]", typeToString(objectType)); } - else if (indexType.flags & TypeFlags.StringLiteral) { - errorInfo = chainDiagnosticMessages(/* details */ undefined, Diagnostics.Property_0_does_not_exist_on_type_1, (indexType as StringLiteralType).value, typeToString(objectType)); + else if (isStringLiteralType(indexType)) { + errorInfo = chainDiagnosticMessages(/* details */ undefined, Diagnostics.Property_0_does_not_exist_on_type_1, indexType.value, typeToString(objectType)); } - else if (indexType.flags & TypeFlags.NumberLiteral) { - errorInfo = chainDiagnosticMessages(/* details */ undefined, Diagnostics.Property_0_does_not_exist_on_type_1, (indexType as NumberLiteralType).value, typeToString(objectType)); + else if (isNumberLiteralType(indexType)) { + errorInfo = chainDiagnosticMessages(/* details */ undefined, Diagnostics.Property_0_does_not_exist_on_type_1, indexType.value, typeToString(objectType)); } else if (indexType.flags & (TypeFlags.Number | TypeFlags.String)) { errorInfo = chainDiagnosticMessages(/* details */ undefined, Diagnostics.No_index_signature_with_a_parameter_of_type_0_was_found_on_type_1, typeToString(indexType), typeToString(objectType)); @@ -17485,11 +17485,11 @@ namespace ts { // Note that this check ignores type parameters and only considers the // inheritance hierarchy. function isTypeDerivedFrom(source: Type, target: Type): boolean { - return source.flags & TypeFlags.Union ? every((source as UnionType).types, t => isTypeDerivedFrom(t, target)) : - target.flags & TypeFlags.Union ? some((target as UnionType).types, t => isTypeDerivedFrom(source, t)) : + return isUnionType(source) ? every(source.types, t => isTypeDerivedFrom(t, target)) : + isUnionType(target) ? some(target.types, t => isTypeDerivedFrom(source, t)) : source.flags & TypeFlags.InstantiableNonPrimitive ? isTypeDerivedFrom(getBaseConstraintOfType(source) || unknownType, target) : target === globalObjectType ? !!(source.flags & (TypeFlags.Object | TypeFlags.NonPrimitive)) : - target === globalFunctionType ? !!(source.flags & TypeFlags.Object) && isFunctionObjectType(source as ObjectType) : + target === globalFunctionType ? isObjectType(source) && isFunctionObjectType(source) : hasBaseType(source, getTargetType(target)) || (isArrayType(target) && !isReadonlyArrayType(target) && isTypeDerivedFrom(source, globalReadonlyArrayType)); } @@ -17673,8 +17673,8 @@ namespace ts { if (idx) { return idx; } - if (target.flags & TypeFlags.Union) { - const best = getBestMatchingType(source, target as UnionType); + if (isUnionType(target)) { + const best = getBestMatchingType(source, target); if (best) { return getIndexedAccessTypeOrUndefined(best, nameType); } @@ -18287,9 +18287,9 @@ namespace ts { t & TypeFlags.StringLiteral && !(t & TypeFlags.EnumLiteral) && (source as StringLiteralType).value === (target as StringLiteralType).value) return true; if (s & TypeFlags.NumberLike && t & TypeFlags.Number) return true; - if (s & TypeFlags.NumberLiteral && s & TypeFlags.EnumLiteral && - t & TypeFlags.NumberLiteral && !(t & TypeFlags.EnumLiteral) && - (source as NumberLiteralType).value === (target as NumberLiteralType).value) return true; + if (isNumberLiteralType(source) && s & TypeFlags.EnumLiteral && + isNumberLiteralType(target) && !(t & TypeFlags.EnumLiteral) && + source.value === target.value) return true; if (s & TypeFlags.BigIntLike && t & TypeFlags.BigInt) return true; if (s & TypeFlags.BooleanLike && t & TypeFlags.Boolean) return true; if (s & TypeFlags.ESSymbolLike && t & TypeFlags.ESSymbol) return true; @@ -18663,8 +18663,8 @@ namespace ts { message = Diagnostics.Type_0_is_not_assignable_to_type_1_with_exactOptionalPropertyTypes_Colon_true_Consider_adding_undefined_to_the_types_of_the_target_s_properties; } else { - if (source.flags & TypeFlags.StringLiteral && target.flags & TypeFlags.Union) { - const suggestedType = getSuggestedTypeForNonexistentStringLiteralType(source as StringLiteralType, target as UnionType); + if (isStringLiteralType(source) && isUnionType(target)) { + const suggestedType = getSuggestedTypeForNonexistentStringLiteralType(source, target); if (suggestedType) { reportError(Diagnostics.Type_0_is_not_assignable_to_type_1_Did_you_mean_2, generalizedSourceType, targetType, typeToString(suggestedType)); return; @@ -18828,8 +18828,8 @@ namespace ts { traceUnionsOrIntersectionsTooLarge(source, target); - const skipCaching = source.flags & TypeFlags.Union && (source as UnionType).types.length < 4 && !(target.flags & TypeFlags.Union) || - target.flags & TypeFlags.Union && (target as UnionType).types.length < 4 && !(source.flags & TypeFlags.StructuredOrInstantiable); + const skipCaching = isUnionType(source) && source.types.length < 4 && !isUnionType(target) || + isUnionType(target) && target.types.length < 4 && !(source.flags & TypeFlags.StructuredOrInstantiable); let result = skipCaching ? unionOrIntersectionRelatedTo(source, target, reportErrors, intersectionState) : recursiveTypeRelatedTo(source, target, reportErrors, intersectionState, recursionFlags); @@ -18907,8 +18907,8 @@ namespace ts { return; } reportRelationError(headMessage, source, target); - if (source.flags & TypeFlags.TypeParameter && source.symbol?.declarations?.[0] && !getConstraintOfType(source as TypeVariable)) { - const syntheticParam = cloneTypeParameter(source as TypeParameter); + if (isTypeParameterType(source) && source.symbol?.declarations?.[0] && !getConstraintOfType(source)) { + const syntheticParam = cloneTypeParameter(source); syntheticParam.constraint = instantiateType(target, makeUnaryTypeMapper(source, syntheticParam)); if (hasNonCircularBaseConstraint(syntheticParam)) { const targetConstraintString = typeToString(target, source.symbol.declarations[0]); @@ -18922,9 +18922,9 @@ namespace ts { return; } - if ((source.flags & TypeFlags.UnionOrIntersection) && (target.flags & TypeFlags.UnionOrIntersection)) { - const sourceUnionOrIntersection = source as UnionOrIntersectionType; - const targetUnionOrIntersection = target as UnionOrIntersectionType; + if (isUnionOrIntersectionType(source) && isUnionOrIntersectionType(target)) { + const sourceUnionOrIntersection = source; + const targetUnionOrIntersection = target; if (sourceUnionOrIntersection.objectFlags & targetUnionOrIntersection.objectFlags & ObjectFlags.PrimitiveUnion) { // There's a fast path for comparing primitive unions @@ -18949,7 +18949,7 @@ namespace ts { function getTypeOfPropertyInTypes(types: Type[], name: __String) { const appendPropType = (propTypes: Type[] | undefined, type: Type) => { type = getApparentType(type); - const prop = type.flags & TypeFlags.UnionOrIntersection ? getPropertyOfUnionOrIntersectionType(type as UnionOrIntersectionType, name) : getPropertyOfObjectType(type, name); + const prop = isUnionOrIntersectionType(type) ? getPropertyOfUnionOrIntersectionType(type, name) : getPropertyOfObjectType(type, name); const propType = prop && getTypeOfSymbol(prop) || getApplicableIndexInfoForName(type, name)?.type || undefinedType; return append(propTypes, propType); }; @@ -18967,9 +18967,9 @@ namespace ts { } let reducedTarget = target; let checkTypes: Type[] | undefined; - if (target.flags & TypeFlags.Union) { - reducedTarget = findMatchingDiscriminantType(source, target as UnionType, isRelatedTo) || filterPrimitivesIfContainsNonPrimitive(target as UnionType); - checkTypes = reducedTarget.flags & TypeFlags.Union ? (reducedTarget as UnionType).types : [reducedTarget]; + if (isUnionType(target)) { + reducedTarget = findMatchingDiscriminantType(source, target, isRelatedTo) || filterPrimitivesIfContainsNonPrimitive(target); + checkTypes = isUnionType(reducedTarget) ? reducedTarget.types : [reducedTarget]; } for (const prop of getPropertiesOfType(source)) { if (shouldCheckAsExcessProperty(prop, source.symbol) && !isIgnoredJsxProperty(source, prop)) { @@ -19046,10 +19046,10 @@ namespace ts { // Note that these checks are specifically ordered to produce correct results. In particular, // we need to deconstruct unions before intersections (because unions are always at the top), // and we need to handle "each" relations before "some" relations for the same kind of type. - if (source.flags & TypeFlags.Union) { + if (isUnionType(source)) { return relation === comparableRelation ? - someTypeRelatedToType(source as UnionType, target, reportErrors && !(source.flags & TypeFlags.Primitive), intersectionState) : - eachTypeRelatedToType(source as UnionType, target, reportErrors && !(source.flags & TypeFlags.Primitive), intersectionState); + someTypeRelatedToType(source, target, reportErrors && !(source.flags & TypeFlags.Primitive), intersectionState) : + eachTypeRelatedToType(source, target, reportErrors && !(source.flags & TypeFlags.Primitive), intersectionState); } if (isUnionType(target)) { return typeRelatedToSomeType(getRegularTypeOfObjectLiteral(source), target, reportErrors && !(source.flags & TypeFlags.Primitive) && !(target.flags & TypeFlags.Primitive)); @@ -19762,12 +19762,12 @@ namespace ts { } } } - else if (sourceFlags & TypeFlags.StringMapping) { - if (targetFlags & TypeFlags.StringMapping) { - if ((source as StringMappingType).symbol !== (target as StringMappingType).symbol) { + else if (isStringMappingType(source)) { + if (isStringMappingType(target)) { + if (source.symbol !== target.symbol) { return Ternary.False; } - if (result = isRelatedTo((source as StringMappingType).type, (target as StringMappingType).type, RecursionFlags.Both, reportErrors)) { + if (result = isRelatedTo(source.type, target.type, RecursionFlags.Both, reportErrors)) { return result; } } @@ -20688,8 +20688,8 @@ namespace ts { return false; } - if (type.flags & TypeFlags.UnionOrIntersection) { - return !!forEach((type as IntersectionType).types, typeCouldHaveTopLevelSingletonTypes); + if (isUnionOrIntersectionType(type)) { + return !!forEach(type.types, typeCouldHaveTopLevelSingletonTypes); } if (type.flags & TypeFlags.Instantiable) { @@ -20699,7 +20699,7 @@ namespace ts { } } - return isUnitType(type) || !!(type.flags & TypeFlags.TemplateLiteral) || !!(type.flags & TypeFlags.StringMapping); + return isUnitType(type) || isTemplateLiteralType(type) || isStringMappingType(type); } function getExactOptionalUnassignableProperties(source: Type, target: Type) { @@ -20767,8 +20767,8 @@ namespace ts { * and no required properties, call/construct signatures or index signatures */ function isWeakType(type: Type): boolean { - if (type.flags & TypeFlags.Object) { - const resolved = resolveStructuredTypeMembers(type as ObjectType); + if (isObjectType(type)) { + const resolved = resolveStructuredTypeMembers(type); return resolved.callSignatures.length === 0 && resolved.constructSignatures.length === 0 && resolved.indexInfos.length === 0 && resolved.properties.length > 0 && every(resolved.properties, p => !!(p.flags & SymbolFlags.Optional)); } @@ -21470,9 +21470,9 @@ namespace ts { type === regularFalseType || type === falseType || type.flags & (TypeFlags.Void | TypeFlags.Undefined | TypeFlags.Null | TypeFlags.AnyOrUnknown) || - type.flags & TypeFlags.StringLiteral && (type as StringLiteralType).value === "" || - type.flags & TypeFlags.NumberLiteral && (type as NumberLiteralType).value === 0 || - type.flags & TypeFlags.BigIntLiteral && isZeroBigInt(type as BigIntLiteralType) ? type : + isStringLiteralType(type) && type.value === "" || + isNumberLiteralType(type) && type.value === 0 || + isBigIntLiteralType(type) && isZeroBigInt(type) ? type : neverType; } @@ -22297,25 +22297,25 @@ namespace ts { if (source === target || target.flags & (TypeFlags.Any | TypeFlags.String)) { return true; } - if (source.flags & TypeFlags.StringLiteral) { - const value = (source as StringLiteralType).value; + if (isStringLiteralType(source)) { + const value = source.value; return !!(target.flags & TypeFlags.Number && isValidNumberString(value, /*roundTripOnly*/ false) || target.flags & TypeFlags.BigInt && isValidBigIntString(value, /*roundTripOnly*/ false) || target.flags & (TypeFlags.BooleanLiteral | TypeFlags.Nullable) && value === (target as IntrinsicType).intrinsicName || target.flags & TypeFlags.StringMapping && isMemberOfStringMapping(getStringLiteralType(value), target)); } - if (source.flags & TypeFlags.TemplateLiteral) { - const texts = (source as TemplateLiteralType).texts; - return texts.length === 2 && texts[0] === "" && texts[1] === "" && isTypeAssignableTo((source as TemplateLiteralType).types[0], target); + if (isTemplateLiteralType(source)) { + const texts = source.texts; + return texts.length === 2 && texts[0] === "" && texts[1] === "" && isTypeAssignableTo(source.types[0], target); } return isTypeAssignableTo(source, target); } function inferTypesFromTemplateLiteralType(source: Type, target: TemplateLiteralType): Type[] | undefined { - return source.flags & TypeFlags.StringLiteral ? inferFromLiteralPartsToTemplateLiteral([(source as StringLiteralType).value], emptyArray, target) : - source.flags & TypeFlags.TemplateLiteral ? - arraysEqual((source as TemplateLiteralType).texts, target.texts) ? map((source as TemplateLiteralType).types, getStringLikeTypeForType) : - inferFromLiteralPartsToTemplateLiteral((source as TemplateLiteralType).texts, (source as TemplateLiteralType).types, target) : + return isStringLiteralType(source) ? inferFromLiteralPartsToTemplateLiteral([source.value], emptyArray, target) : + isTemplateLiteralType(source) ? + arraysEqual(source.texts, target.texts) ? map(source.types, getStringLikeTypeForType) : + inferFromLiteralPartsToTemplateLiteral(source.texts, source.types, target) : undefined; } @@ -22927,14 +22927,14 @@ namespace ts { const matchingType = reduceLeft(constraintTypes, (left, right) => !(right.flags & allTypeFlags) ? left : left.flags & TypeFlags.String ? left : right.flags & TypeFlags.String ? source : - left.flags & TypeFlags.TemplateLiteral ? left : right.flags & TypeFlags.TemplateLiteral && isTypeMatchedByTemplateLiteralType(source, right as TemplateLiteralType) ? source : + left.flags & TypeFlags.TemplateLiteral ? left : isTemplateLiteralType(right) && isTypeMatchedByTemplateLiteralType(source, right) ? source : left.flags & TypeFlags.StringMapping ? left : right.flags & TypeFlags.StringMapping && str === applyStringMapping(right.symbol, str) ? source : - left.flags & TypeFlags.StringLiteral ? left : right.flags & TypeFlags.StringLiteral && (right as StringLiteralType).value === str ? right : + left.flags & TypeFlags.StringLiteral ? left : isStringLiteralType(right) && right.value === str ? right : left.flags & TypeFlags.Number ? left : right.flags & TypeFlags.Number ? getNumberLiteralType(+str) : left.flags & TypeFlags.Enum ? left : right.flags & TypeFlags.Enum ? getNumberLiteralType(+str) : - left.flags & TypeFlags.NumberLiteral ? left : right.flags & TypeFlags.NumberLiteral && (right as NumberLiteralType).value === +str ? right : + left.flags & TypeFlags.NumberLiteral ? left : isNumberLiteralType(right) && right.value === +str ? right : left.flags & TypeFlags.BigInt ? left : right.flags & TypeFlags.BigInt ? parseBigIntLiteralType(str) : - left.flags & TypeFlags.BigIntLiteral ? left : right.flags & TypeFlags.BigIntLiteral && pseudoBigIntToString((right as BigIntLiteralType).value) === str ? right : + left.flags & TypeFlags.BigIntLiteral ? left : isBigIntLiteralType(right) && pseudoBigIntToString(right.value) === str ? right : left.flags & TypeFlags.Boolean ? left : right.flags & TypeFlags.Boolean ? str === "true" ? trueType : str === "false" ? falseType : booleanType : left.flags & TypeFlags.BooleanLiteral ? left : right.flags & TypeFlags.BooleanLiteral && (right as IntrinsicType).intrinsicName === str ? right : left.flags & TypeFlags.Undefined ? left : right.flags & TypeFlags.Undefined && (right as IntrinsicType).intrinsicName === str ? right : @@ -23126,7 +23126,7 @@ namespace ts { function hasPrimitiveConstraint(type: TypeParameter): boolean { const constraint = getConstraintOfTypeParameter(type); - return !!constraint && maybeTypeOfKind(constraint.flags & TypeFlags.Conditional ? getDefaultConstraintOfConditionalType(constraint as ConditionalType) : constraint, TypeFlags.Primitive | TypeFlags.Index | TypeFlags.TemplateLiteral | TypeFlags.StringMapping); + return !!constraint && maybeTypeOfKind(isConditionalType(constraint) ? getDefaultConstraintOfConditionalType(constraint) : constraint, TypeFlags.Primitive | TypeFlags.Index | TypeFlags.TemplateLiteral | TypeFlags.StringMapping); } function isObjectLiteralType(type: Type) { @@ -23670,8 +23670,8 @@ namespace ts { if (flags & (TypeFlags.Number | TypeFlags.Enum)) { return strictNullChecks ? TypeFacts.NumberStrictFacts : TypeFacts.NumberFacts; } - if (flags & TypeFlags.NumberLiteral) { - const isZero = (type as NumberLiteralType).value === 0; + if (isNumberLiteralType(type)) { + const isZero = type.value === 0; return strictNullChecks ? isZero ? TypeFacts.ZeroNumberStrictFacts : TypeFacts.NonZeroNumberStrictFacts : isZero ? TypeFacts.ZeroNumberFacts : TypeFacts.NonZeroNumberFacts; @@ -23679,8 +23679,8 @@ namespace ts { if (flags & TypeFlags.BigInt) { return strictNullChecks ? TypeFacts.BigIntStrictFacts : TypeFacts.BigIntFacts; } - if (flags & TypeFlags.BigIntLiteral) { - const isZero = isZeroBigInt(type as BigIntLiteralType); + if (isBigIntLiteralType(type)) { + const isZero = isZeroBigInt(type); return strictNullChecks ? isZero ? TypeFacts.ZeroBigIntStrictFacts : TypeFacts.NonZeroBigIntStrictFacts : isZero ? TypeFacts.ZeroBigIntFacts : TypeFacts.NonZeroBigIntFacts; @@ -23693,10 +23693,10 @@ namespace ts { (type === falseType || type === regularFalseType) ? TypeFacts.FalseStrictFacts : TypeFacts.TrueStrictFacts : (type === falseType || type === regularFalseType) ? TypeFacts.FalseFacts : TypeFacts.TrueFacts; } - if (flags & TypeFlags.Object) { - return getObjectFlags(type) & ObjectFlags.Anonymous && isEmptyObjectType(type as ObjectType) ? + if (isObjectType(type)) { + return getObjectFlags(type) & ObjectFlags.Anonymous && isEmptyObjectType(type) ? strictNullChecks ? TypeFacts.EmptyObjectStrictFacts : TypeFacts.EmptyObjectFacts : - isFunctionObjectType(type as ObjectType) ? + isFunctionObjectType(type) ? strictNullChecks ? TypeFacts.FunctionStrictFacts : TypeFacts.FunctionFacts : strictNullChecks ? TypeFacts.ObjectStrictFacts : TypeFacts.ObjectFacts; } @@ -29658,7 +29658,7 @@ namespace ts { } function getSuggestedTypeForNonexistentStringLiteralType(source: StringLiteralType, target: UnionType): StringLiteralType | undefined { - const candidates = target.types.filter((type): type is StringLiteralType => !!(type.flags & TypeFlags.StringLiteral)); + const candidates = target.types.filter(isStringLiteralType); return getSpellingSuggestion(source.value, candidates, type => type.value); } @@ -30082,8 +30082,8 @@ namespace ts { } function getSingleSignature(type: Type, kind: SignatureKind, allowMembers: boolean): Signature | undefined { - if (type.flags & TypeFlags.Object) { - const resolved = resolveStructuredTypeMembers(type as ObjectType); + if (isObjectType(type)) { + const resolved = resolveStructuredTypeMembers(type); if (allowMembers || resolved.properties.length === 0 && resolved.indexInfos.length === 0) { if (kind === SignatureKind.Call && resolved.callSignatures.length === 1 && resolved.constructSignatures.length === 0) { return resolved.callSignatures[0]; @@ -32275,8 +32275,8 @@ namespace ts { return result; function getInstantiatedTypePart(type: Type): Type { - if (type.flags & TypeFlags.Object) { - const resolved = resolveStructuredTypeMembers(type as ObjectType); + if (isObjectType(type)) { + const resolved = resolveStructuredTypeMembers(type); const callSignatures = getInstantiatedSignatures(resolved.callSignatures); const constructSignatures = getInstantiatedSignatures(resolved.constructSignatures); hasSignatures ||= resolved.callSignatures.length !== 0 || resolved.constructSignatures.length !== 0; @@ -45595,8 +45595,8 @@ namespace ts { // Keep this up-to-date with the same logic within `getApparentTypeOfContextualType`, since they should behave similarly function findMatchingDiscriminantType(source: Type, target: Type, isRelatedTo: (source: Type, target: Type) => Ternary, skipPartial?: boolean) { - if (target.flags & TypeFlags.Union && source.flags & (TypeFlags.Intersection | TypeFlags.Object)) { - const match = getMatchingUnionConstituentForType(target as UnionType, source); + if (isUnionType(target) && source.flags & (TypeFlags.Intersection | TypeFlags.Object)) { + const match = getMatchingUnionConstituentForType(target, source); if (match) { return match; } @@ -45604,7 +45604,7 @@ namespace ts { if (sourceProperties) { const sourcePropertiesFiltered = findDiscriminantProperties(sourceProperties, target); if (sourcePropertiesFiltered) { - return discriminateTypeByDiscriminableItems(target as UnionType, map(sourcePropertiesFiltered, p => ([() => getTypeOfSymbol(p), p.escapedName] as [() => Type, __String])), isRelatedTo, /*defaultValue*/ undefined, skipPartial); + return discriminateTypeByDiscriminableItems(target, map(sourcePropertiesFiltered, p => ([() => getTypeOfSymbol(p), p.escapedName] as [() => Type, __String])), isRelatedTo, /*defaultValue*/ undefined, skipPartial); } } } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 456e02d57d596..46f6df6656137 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -7674,6 +7674,10 @@ namespace ts { factory.createStringLiteral(name, !!singleQuote); } + export function isBigIntLiteralType(type: Type): type is BigIntLiteralType { + return !!(type.flags & TypeFlags.BigIntLiteral); + } + export function isConditionalType(type: Type): type is ConditionalType { return !!(type.flags & TypeFlags.Conditional); } @@ -7690,6 +7694,10 @@ namespace ts { return !!(type.flags & TypeFlags.Intersection); } + export function isNumberLiteralType(type: Type): type is NumberLiteralType { + return !!(type.flags & TypeFlags.NumberLiteral); + } + export function isObjectType(type: Type): type is ObjectType { return !!(type.flags & TypeFlags.Object); } @@ -7702,6 +7710,10 @@ namespace ts { return !!(type.flags & TypeFlags.Substitution); } + export function isStringLiteralType(type: Type): type is StringLiteralType { + return !!(type.flags & TypeFlags.StringLiteral); + } + export function isTemplateLiteralType(type: Type): type is TemplateLiteralType { return !!(type.flags & TypeFlags.TemplateLiteral); } From f2a2db1d7d96fa3984987ad2565dc7a2501a9a18 Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Sat, 23 Jul 2022 10:55:05 -0400 Subject: [PATCH 5/7] Converted some more locations, again --- src/compiler/checker.ts | 98 ++++++++++++++++++++--------------------- 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 76a37c60dc2d2..c53e4d9e65235 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -15147,9 +15147,9 @@ namespace ts { } function getConstituentCount(type: Type): number { - return !(type.flags & TypeFlags.UnionOrIntersection) || type.aliasSymbol ? 1 : - type.flags & TypeFlags.Union && (type as UnionType).origin ? getConstituentCount((type as UnionType).origin!) : - getConstituentCountOfTypes((type as UnionOrIntersectionType).types); + return !isUnionOrIntersectionType(type) || type.aliasSymbol ? 1 : + isUnionType(type) && type.origin ? getConstituentCount(type.origin) : + getConstituentCountOfTypes(type.types); } function getConstituentCountOfTypes(types: Type[]): number { @@ -15756,19 +15756,19 @@ namespace ts { } function getGenericObjectFlags(type: Type): ObjectFlags { - if (type.flags & TypeFlags.UnionOrIntersection) { - if (!((type as UnionOrIntersectionType).objectFlags & ObjectFlags.IsGenericTypeComputed)) { - (type as UnionOrIntersectionType).objectFlags |= ObjectFlags.IsGenericTypeComputed | - reduceLeft((type as UnionOrIntersectionType).types, (flags, t) => flags | getGenericObjectFlags(t), 0); + if (isUnionOrIntersectionType(type)) { + if (!(type.objectFlags & ObjectFlags.IsGenericTypeComputed)) { + type.objectFlags |= ObjectFlags.IsGenericTypeComputed | + reduceLeft(type.types, (flags, t) => flags | getGenericObjectFlags(t), 0); } - return (type as UnionOrIntersectionType).objectFlags & ObjectFlags.IsGenericType; + return type.objectFlags & ObjectFlags.IsGenericType; } - if (type.flags & TypeFlags.Substitution) { - if (!((type as SubstitutionType).objectFlags & ObjectFlags.IsGenericTypeComputed)) { - (type as SubstitutionType).objectFlags |= ObjectFlags.IsGenericTypeComputed | - getGenericObjectFlags((type as SubstitutionType).substitute) | getGenericObjectFlags((type as SubstitutionType).baseType); + if (isSubstitutionType(type)) { + if (!(type.objectFlags & ObjectFlags.IsGenericTypeComputed)) { + type.objectFlags |= ObjectFlags.IsGenericTypeComputed | + getGenericObjectFlags(type.substitute) | getGenericObjectFlags(type.baseType); } - return (type as SubstitutionType).objectFlags & ObjectFlags.IsGenericType; + return type.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); @@ -17263,8 +17263,8 @@ namespace ts { if (flags & TypeFlags.TypeParameter) { return getMappedType(type, mapper); } - if (flags & TypeFlags.Object) { - const objectFlags = (type as ObjectType).objectFlags; + if (isObjectType(type)) { + const objectFlags = type.objectFlags; if (objectFlags & (ObjectFlags.Reference | ObjectFlags.Anonymous | ObjectFlags.Mapped)) { if (objectFlags & ObjectFlags.Reference && !(type as TypeReference).node) { const resolvedTypeArguments = (type as TypeReference).resolvedTypeArguments; @@ -17278,9 +17278,9 @@ namespace ts { } return type; } - if (flags & TypeFlags.UnionOrIntersection) { - const origin = type.flags & TypeFlags.Union ? (type as UnionType).origin : undefined; - const types = origin && origin.flags & TypeFlags.UnionOrIntersection ? (origin as UnionOrIntersectionType).types : (type as UnionOrIntersectionType).types; + if (isUnionOrIntersectionType(type)) { + const origin = isUnionType(type) ? type.origin : undefined; + const types = origin && isUnionOrIntersectionType(origin) ? origin.types : type.types; const newTypes = instantiateTypes(types, mapper); if (newTypes === types && aliasSymbol === type.aliasSymbol) { return type; @@ -18234,12 +18234,12 @@ namespace ts { } function containsUndefinedType(type: Type) { - return !!((type.flags & TypeFlags.Union ? (type as UnionType).types[0] : type).flags & TypeFlags.Undefined); + return !!((isUnionType(type) ? type.types[0] : type).flags & TypeFlags.Undefined); } function isStringIndexSignatureOnlyType(type: Type): boolean { return type.flags & TypeFlags.Object && !isGenericMappedType(type) && getPropertiesOfType(type).length === 0 && getIndexInfosOfType(type).length === 1 && !!getIndexInfoOfType(type, stringType) || - type.flags & TypeFlags.UnionOrIntersection && every((type as UnionOrIntersectionType).types, isStringIndexSignatureOnlyType) || + isUnionOrIntersectionType(type) && every(type.types, isStringIndexSignatureOnlyType) || false; } @@ -18358,8 +18358,8 @@ namespace ts { while (true) { const t = isFreshLiteralType(type) ? (type as FreshableType).regularType : getObjectFlags(type) & ObjectFlags.Reference ? (type as TypeReference).node ? createTypeReference((type as TypeReference).target, getTypeArguments(type as TypeReference)) : getSingleBaseForNonAugmentingSubtype(type) || type : - type.flags & TypeFlags.UnionOrIntersection ? getNormalizedUnionOrIntersectionType(type as UnionOrIntersectionType, writing) : - type.flags & TypeFlags.Substitution ? writing ? (type as SubstitutionType).baseType : (type as SubstitutionType).substitute : + isUnionOrIntersectionType(type) ? getNormalizedUnionOrIntersectionType(type, writing) : + isSubstitutionType(type) ? writing ? type.baseType : type.substitute : type.flags & TypeFlags.Simplifiable ? getSimplifiedType(type, writing) : type; if (t === type) return t; @@ -19390,10 +19390,10 @@ namespace ts { const targetFlags = target.flags; if (relation === identityRelation) { // We've already checked that source.flags and target.flags are identical - if (sourceFlags & TypeFlags.UnionOrIntersection) { - let result = eachTypeRelatedToSomeType(source as UnionOrIntersectionType, target as UnionOrIntersectionType); + if (isUnionOrIntersectionType(source)) { + let result = eachTypeRelatedToSomeType(source, target as UnionOrIntersectionType); if (result) { - result &= eachTypeRelatedToSomeType(target as UnionOrIntersectionType, source as UnionOrIntersectionType); + result &= eachTypeRelatedToSomeType(target as UnionOrIntersectionType, source); } return result; } @@ -22037,7 +22037,7 @@ namespace ts { objectFlags & ObjectFlags.Reference && ((type as TypeReference).node || forEach(getTypeArguments(type as TypeReference), couldContainTypeVariables)) || objectFlags & ObjectFlags.Anonymous && type.symbol && type.symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.TypeLiteral | SymbolFlags.ObjectLiteral) && type.symbol.declarations || objectFlags & (ObjectFlags.Mapped | ObjectFlags.ReverseMapped | ObjectFlags.ObjectRestType | ObjectFlags.InstantiationExpressionType)) || - type.flags & TypeFlags.UnionOrIntersection && !(type.flags & TypeFlags.EnumLiteral) && !isNonGenericTopLevelType(type) && some((type as UnionOrIntersectionType).types, couldContainTypeVariables)); + isUnionOrIntersectionType(type) && !(type.flags & TypeFlags.EnumLiteral) && !isNonGenericTopLevelType(type) && some(type.types, couldContainTypeVariables)); if (type.flags & TypeFlags.ObjectFlagsType) { (type as ObjectFlagsType).objectFlags |= ObjectFlags.CouldContainTypeVariablesComputed | (result ? ObjectFlags.CouldContainTypeVariables : 0); } @@ -22437,18 +22437,18 @@ namespace ts { // And if there weren't any type arguments, there's no reason to run inference as the types must be the same. return; } - if (source === target && source.flags & TypeFlags.UnionOrIntersection) { + if (source === target && isUnionOrIntersectionType(source)) { // When source and target are the same union or intersection type, just relate each constituent // type to itself. - for (const t of (source as UnionOrIntersectionType).types) { + for (const t of source.types) { inferFromTypes(t, t); } return; } - if (target.flags & TypeFlags.Union) { + if (isUnionType(target)) { // First, infer between identically matching source and target constituents and remove the // matching types. - const [tempSources, tempTargets] = inferFromMatchingTypes(source.flags & TypeFlags.Union ? (source as UnionType).types : [source], (target as UnionType).types, isTypeOrBaseIdenticalTo); + const [tempSources, tempTargets] = inferFromMatchingTypes(isUnionType(source) ? source.types : [source], target.types, isTypeOrBaseIdenticalTo); // Next, infer between closely matching source and target constituents and remove // the matching types. Types closely match when they are instantiations of the same // object type or instantiations of the same type alias. @@ -23967,8 +23967,8 @@ namespace ts { } function isTypeSubsetOfUnion(source: Type, target: UnionType) { - if (source.flags & TypeFlags.Union) { - for (const t of (source as UnionType).types) { + if (isUnionType(source)) { + for (const t of source.types) { if (!containsType(target.types, t)) { return false; } @@ -23982,37 +23982,37 @@ namespace ts { } function forEachType(type: Type, f: (t: Type) => T | undefined): T | undefined { - return type.flags & TypeFlags.Union ? forEach((type as UnionType).types, f) : f(type); + return isUnionType(type) ? forEach(type.types, f) : f(type); } function someType(type: Type, f: (t: Type) => boolean): boolean { - return type.flags & TypeFlags.Union ? some((type as UnionType).types, f) : f(type); + return isUnionType(type) ? some(type.types, f) : f(type); } function everyType(type: Type, f: (t: Type) => boolean): boolean { - return type.flags & TypeFlags.Union ? every((type as UnionType).types, f) : f(type); + return isUnionType(type) ? every(type.types, f) : f(type); } function everyContainedType(type: Type, f: (t: Type) => boolean): boolean { - return type.flags & TypeFlags.UnionOrIntersection ? every((type as UnionOrIntersectionType).types, f) : f(type); + return isUnionOrIntersectionType(type) ? every(type.types, f) : f(type); } function filterType(type: Type, f: (t: Type) => boolean): Type { - if (type.flags & TypeFlags.Union) { - const types = (type as UnionType).types; + if (isUnionType(type)) { + const types = type.types; const filtered = filter(types, f); if (filtered === types) { return type; } - const origin = (type as UnionType).origin; + const { origin } = type; let newOrigin: Type | undefined; - if (origin && origin.flags & TypeFlags.Union) { + if (origin && isUnionType(origin)) { // If the origin type is a (denormalized) union type, filter its non-union constituents. If that ends // up removing a smaller number of types than in the normalized constituent set (meaning some of the // filtered types are within nested unions in the origin), then we can't construct a new origin type. // Otherwise, if we have exactly one type left in the origin set, return that as the filtered type. // Otherwise, construct a new filtered origin type. - const originTypes = (origin as UnionType).types; + const originTypes = origin.types; const originFiltered = filter(originTypes, t => !!(t.flags & TypeFlags.Union) || f(t)); if (originTypes.length - originFiltered.length === types.length - filtered.length) { if (originFiltered.length === 1) { @@ -24021,7 +24021,7 @@ namespace ts { newOrigin = createOriginUnionOrIntersectionType(TypeFlags.Union, originFiltered); } } - return getUnionTypeFromSortedList(filtered, (type as UnionType).objectFlags, /*aliasSymbol*/ undefined, /*aliasTypeArguments*/ undefined, newOrigin); + return getUnionTypeFromSortedList(filtered, type.objectFlags, /*aliasSymbol*/ undefined, /*aliasTypeArguments*/ undefined, newOrigin); } return type.flags & TypeFlags.Never || f(type) ? type : neverType; } @@ -28157,7 +28157,7 @@ namespace ts { function isValidSpreadType(type: Type): boolean { const t = removeDefinitelyFalsyTypes(mapType(type, getBaseConstraintOrType)); return !!(t.flags & (TypeFlags.Any | TypeFlags.NonPrimitive | TypeFlags.Object | TypeFlags.InstantiableNonPrimitive) || - t.flags & TypeFlags.UnionOrIntersection && every((t as UnionOrIntersectionType).types, isValidSpreadType)); + isUnionOrIntersectionType(t) && every(t.types, isValidSpreadType)); } function checkJsxSelfClosingElementDeferred(node: JsxSelfClosingElement) { @@ -28764,8 +28764,8 @@ namespace ts { return true; } } - else if (targetType.flags & TypeFlags.UnionOrIntersection && isExcessPropertyCheckTarget(targetType)) { - for (const t of (targetType as UnionOrIntersectionType).types) { + else if (isUnionOrIntersectionType(targetType) && isExcessPropertyCheckTarget(targetType)) { + for (const t of targetType.types) { if (isKnownProperty(t, name, isComparingJsxAttributes)) { return true; } @@ -33527,8 +33527,8 @@ namespace ts { if (type.flags & kind) { return true; } - if (type.flags & TypeFlags.UnionOrIntersection) { - const types = (type as UnionOrIntersectionType).types; + if (isUnionOrIntersectionType(type)) { + const types = type.types; for (const t of types) { if (maybeTypeOfKind(t, kind)) { return true; @@ -34684,8 +34684,8 @@ namespace ts { function isLiteralOfContextualType(candidateType: Type, contextualType: Type | undefined): boolean { if (contextualType) { - if (contextualType.flags & TypeFlags.UnionOrIntersection) { - const types = (contextualType as UnionType).types; + if (isUnionOrIntersectionType(contextualType)) { + const types = contextualType.types; return some(types, t => isLiteralOfContextualType(candidateType, t)); } if (contextualType.flags & TypeFlags.InstantiableNonPrimitive) { From d1641d8ac132efe771f736f7f388d239e991f8c5 Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Sat, 23 Jul 2022 11:05:40 -0400 Subject: [PATCH 6/7] Converted some more locations, one more time --- src/compiler/checker.ts | 66 ++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c53e4d9e65235..486f518c13aa5 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -11959,8 +11959,8 @@ namespace ts { function getPropertiesOfType(type: Type): Symbol[] { type = getReducedApparentType(type); - return type.flags & TypeFlags.UnionOrIntersection ? - getPropertiesOfUnionOrIntersectionType(type as UnionType) : + return isUnionOrIntersectionType(type) ? + getPropertiesOfUnionOrIntersectionType(type) : getPropertiesOfObjectType(type); } @@ -12712,7 +12712,7 @@ namespace ts { // signature applies to types assignable to 'number', `${number}` and numeric string literal types. return isTypeAssignableTo(source, target) || target === stringType && isTypeAssignableTo(source, numberType) || - target === numberType && (source === numericStringType || !!(source.flags & TypeFlags.StringLiteral) && isNumericLiteralName((source as StringLiteralType).value)); + target === numberType && (source === numericStringType || isStringLiteralType(source) && isNumericLiteralName(source.value)); } function getIndexInfosOfStructuredType(type: Type): readonly IndexInfo[] { @@ -15436,7 +15436,7 @@ namespace ts { } function getTemplateStringForType(type: Type) { - return type.flags & TypeFlags.StringLiteral ? (type as StringLiteralType).value : + return isStringLiteralType(type) ? type.value : isNumberLiteralType(type) ? "" + type.value : isBigIntLiteralType(type) ? pseudoBigIntToString(type.value) : type.flags & (TypeFlags.BooleanLiteral | TypeFlags.Nullable) ? (type as IntrinsicType).intrinsicName : @@ -15736,11 +15736,11 @@ namespace ts { } function isPatternLiteralPlaceholderType(type: Type): boolean { - return !!(type.flags & (TypeFlags.Any | TypeFlags.String | TypeFlags.Number | TypeFlags.BigInt)) || !!(type.flags & TypeFlags.StringMapping && isPatternLiteralPlaceholderType((type as StringMappingType).type)); + return !!(type.flags & (TypeFlags.Any | TypeFlags.String | TypeFlags.Number | TypeFlags.BigInt)) || !!(isStringMappingType(type) && isPatternLiteralPlaceholderType(type.type)); } function isPatternLiteralType(type: Type) { - return !!(type.flags & TypeFlags.TemplateLiteral) && every((type as TemplateLiteralType).types, isPatternLiteralPlaceholderType); + return isTemplateLiteralType(type) && every(type.types, isPatternLiteralPlaceholderType); } function isGenericType(type: Type): boolean { @@ -15793,8 +15793,8 @@ namespace ts { function distributeObjectOverIndexType(objectType: Type, indexType: Type, writing: boolean) { // T[A | B] -> T[A] | T[B] (reading) // T[A | B] -> T[A] & T[B] (writing) - if (indexType.flags & TypeFlags.Union) { - const types = map((indexType as UnionType).types, t => getSimplifiedType(getIndexedAccessType(objectType, t), writing)); + if (isUnionType(indexType)) { + const types = map(indexType.types, t => getSimplifiedType(getIndexedAccessType(objectType, t), writing)); return writing ? getIntersectionType(types) : getUnionType(types); } } @@ -15945,10 +15945,10 @@ namespace ts { // We treat boolean as different from other unions to improve errors; // skipping straight to getPropertyTypeForIndexType gives errors with 'boolean' instead of 'true'. const apparentObjectType = getReducedApparentType(objectType); - if (indexType.flags & TypeFlags.Union && !(indexType.flags & TypeFlags.Boolean)) { + if (isUnionType(indexType) && !(indexType.flags & TypeFlags.Boolean)) { const propTypes: Type[] = []; let wasMissingProp = false; - for (const t of (indexType as UnionType).types) { + for (const t of indexType.types) { const propType = getPropertyTypeForIndexType(objectType, apparentObjectType, t, indexType, accessNode, accessFlags | (wasMissingProp ? AccessFlags.SuppressNoImplicitAnyError : 0)); if (propType) { propTypes.push(propType); @@ -16383,17 +16383,17 @@ namespace ts { } function tryMergeUnionOfObjectTypeAndEmptyObject(type: Type, readonly: boolean): Type { - if (!(type.flags & TypeFlags.Union)) { + if (!isUnionType(type)) { return type; } - if (every((type as UnionType).types, isEmptyObjectTypeOrSpreadsIntoEmptyObject)) { - return find((type as UnionType).types, isEmptyObjectType) || emptyObjectType; + if (every(type.types, isEmptyObjectTypeOrSpreadsIntoEmptyObject)) { + return find(type.types, isEmptyObjectType) || emptyObjectType; } - const firstType = find((type as UnionType).types, t => !isEmptyObjectTypeOrSpreadsIntoEmptyObject(t)); + const firstType = find(type.types, t => !isEmptyObjectTypeOrSpreadsIntoEmptyObject(t)); if (!firstType) { return type; } - const secondType = find((type as UnionType).types, t => t !== firstType && !isEmptyObjectTypeOrSpreadsIntoEmptyObject(t)); + const secondType = find(type.types, t => t !== firstType && !isEmptyObjectTypeOrSpreadsIntoEmptyObject(t)); if (secondType) { return type; } @@ -16563,7 +16563,7 @@ namespace ts { function getRegularTypeOfLiteralType(type: Type): Type { return type.flags & TypeFlags.Literal ? (type as LiteralType).regularType : - type.flags & TypeFlags.Union ? ((type as UnionType).regularType || ((type as UnionType).regularType = mapType(type, getRegularTypeOfLiteralType) as UnionType)) : + isUnionType(type) ? (type.regularType || (type.regularType = mapType(type, getRegularTypeOfLiteralType) as UnionType)) : type; } @@ -22062,10 +22062,10 @@ namespace ts { function createEmptyObjectTypeFromStringLiteral(type: Type) { const members = createSymbolTable(); forEachType(type, t => { - if (!(t.flags & TypeFlags.StringLiteral)) { + if (!isStringLiteralType(t)) { return; } - const name = escapeLeadingUnderscores((t as StringLiteralType).value); + const name = escapeLeadingUnderscores(t.value); const literalProp = createSymbol(SymbolFlags.Property, name); literalProp.type = anyType; if (t.symbol) { @@ -22274,7 +22274,7 @@ namespace ts { if (target.flags & TypeFlags.TemplateLiteral) { return isTypeAssignableTo(source, target); } - if (target.flags & TypeFlags.StringMapping) { + if (isStringMappingType(target)) { // We need to see whether applying the same mappings of the target // onto the source would produce an identical type *and* that // it's compatible with the inner-most non-string-mapped type. @@ -22283,9 +22283,9 @@ namespace ts { // and the source is compatible with the unmapped target, then they must // still reside in the same domain. const mappingStack = []; - while (target.flags & TypeFlags.StringMapping) { + while (isStringMappingType(target)) { mappingStack.unshift(target.symbol); - target = (target as StringMappingType).type; + target = target.type; } const mappedSource = reduceLeft(mappingStack, (memo, value) => getStringMappingType(value, memo), source); return mappedSource === source && isMemberOfStringMapping(source, target); @@ -22902,16 +22902,16 @@ namespace ts { // If we are inferring from a string literal type to a type variable whose constraint includes one of the // allowed template literal placeholder types, infer from a literal type corresponding to the constraint. - if (source.flags & TypeFlags.StringLiteral && target.flags & TypeFlags.TypeVariable) { + if (isStringLiteralType(source) && target.flags & TypeFlags.TypeVariable) { const inferenceContext = getInferenceInfoForType(target); const constraint = inferenceContext ? getBaseConstraintOfType(inferenceContext.typeParameter) : undefined; if (constraint && !isTypeAny(constraint)) { - const constraintTypes = constraint.flags & TypeFlags.Union ? (constraint as UnionType).types : [constraint]; + const constraintTypes = isUnionType(constraint) ? constraint.types : [constraint]; let allTypeFlags: TypeFlags = reduceLeft(constraintTypes, (flags, t) => flags | t.flags, 0 as TypeFlags); // If the constraint contains `string`, we don't need to look for a more preferred type if (!(allTypeFlags & TypeFlags.String)) { - const str = (source as StringLiteralType).value; + const str = source.value; // If the type contains `number` or a number literal and the string isn't a valid number, exclude numbers if (allTypeFlags & TypeFlags.NumberLike && !isValidNumberString(str, /*roundTripOnly*/ true)) { @@ -23662,7 +23662,7 @@ namespace ts { return strictNullChecks ? TypeFacts.StringStrictFacts : TypeFacts.StringFacts; } if (flags & (TypeFlags.StringLiteral | TypeFlags.TemplateLiteral)) { - const isEmpty = flags & TypeFlags.StringLiteral && (type as StringLiteralType).value === ""; + const isEmpty = isStringLiteralType(type) && type.value === ""; return strictNullChecks ? isEmpty ? TypeFacts.EmptyStringStrictFacts : TypeFacts.NonEmptyStringStrictFacts : isEmpty ? TypeFacts.EmptyStringFacts : TypeFacts.NonEmptyStringFacts; @@ -24743,7 +24743,7 @@ namespace ts { } else if (expr.kind === SyntaxKind.TypeOfExpression && optionalChainContainsReference((expr as TypeOfExpression).expression, reference)) { type = narrowTypeBySwitchOptionalChainContainment(type, flow.switchStatement, flow.clauseStart, flow.clauseEnd, - t => !(t.flags & TypeFlags.Never || t.flags & TypeFlags.StringLiteral && (t as StringLiteralType).value === "undefined")); + t => !(t.flags & TypeFlags.Never || isStringLiteralType(t) && t.value === "undefined")); } } const access = getDiscriminantPropertyAccess(expr, type); @@ -25093,8 +25093,8 @@ namespace ts { } const target = getReferenceCandidate(expr.right); const leftType = getTypeOfNode(expr.left); - if (leftType.flags & TypeFlags.StringLiteral) { - const name = escapeLeadingUnderscores((leftType as StringLiteralType).value); + if (isStringLiteralType(leftType)) { + const name = escapeLeadingUnderscores(leftType.value); if (containsMissingType(type) && isAccessExpression(reference) && isMatchingReference(reference.expression, target) && getAccessedPropertyName(reference) === name) { return getTypeWithFacts(type, assumeTrue ? TypeFacts.NEUndefined : TypeFacts.EQUndefined); @@ -27483,8 +27483,8 @@ namespace ts { return getOrCreateTypeFromSignature(fakeSignature); } const tagType = checkExpressionCached(context.tagName); - if (tagType.flags & TypeFlags.StringLiteral) { - const result = getIntrinsicAttributesTypeFromStringLiteralType(tagType as StringLiteralType, context); + if (isStringLiteralType(tagType)) { + const result = getIntrinsicAttributesTypeFromStringLiteralType(tagType, context); if (!result) { return errorType; } @@ -28548,10 +28548,10 @@ namespace ts { if (elementType.flags & TypeFlags.String) { return [anySignature]; } - else if (elementType.flags & TypeFlags.StringLiteral) { - const intrinsicType = getIntrinsicAttributesTypeFromStringLiteralType(elementType as StringLiteralType, caller); + else if (isStringLiteralType(elementType)) { + const intrinsicType = getIntrinsicAttributesTypeFromStringLiteralType(elementType, caller); if (!intrinsicType) { - error(caller, Diagnostics.Property_0_does_not_exist_on_type_1, (elementType as StringLiteralType).value, "JSX." + JsxNames.IntrinsicElements); + error(caller, Diagnostics.Property_0_does_not_exist_on_type_1, elementType.value, "JSX." + JsxNames.IntrinsicElements); return emptyArray; } else { From 5e851e7e2329beb654f9846b1ad05ac1ad933d2e Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Thu, 18 Aug 2022 17:53:01 -0400 Subject: [PATCH 7/7] Cut-and-paste functions into checker.ts --- src/compiler/checker.ts | 64 +++++++++++++++++++++++++++++++++++++++ src/compiler/utilities.ts | 64 --------------------------------------- 2 files changed, 64 insertions(+), 64 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 1cfaa903f7279..6fa57cc0a7143 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -45779,6 +45779,70 @@ namespace ts { } } + export function isBigIntLiteralType(type: Type): type is BigIntLiteralType { + return !!(type.flags & TypeFlags.BigIntLiteral); + } + + export function isConditionalType(type: Type): type is ConditionalType { + return !!(type.flags & TypeFlags.Conditional); + } + + export function isIndexType(type: Type): type is IndexType { + return !!(type.flags & TypeFlags.Index); + } + + export function isIndexedAccessType(type: Type): type is IndexedAccessType { + return !!(type.flags & TypeFlags.IndexedAccess); + } + + export function isIntersectionType(type: Type): type is IntersectionType { + return !!(type.flags & TypeFlags.Intersection); + } + + export function isNumberLiteralType(type: Type): type is NumberLiteralType { + return !!(type.flags & TypeFlags.NumberLiteral); + } + + export function isObjectType(type: Type): type is ObjectType { + return !!(type.flags & TypeFlags.Object); + } + + export function isStringMappingType(type: Type): type is StringMappingType { + return !!(type.flags & TypeFlags.StringMapping); + } + + export function isSubstitutionType(type: Type): type is SubstitutionType { + return !!(type.flags & TypeFlags.Substitution); + } + + export function isStringLiteralType(type: Type): type is StringLiteralType { + return !!(type.flags & TypeFlags.StringLiteral); + } + + export function isTemplateLiteralType(type: Type): type is TemplateLiteralType { + return !!(type.flags & TypeFlags.TemplateLiteral); + } + + export function isTypeParameterType(type: Type): type is TypeParameter { + return !!(type.flags & TypeFlags.TypeParameter); + } + + export function isThisTypeParameter(type: Type): boolean { + return isTypeParameterType(type) && !!type.isThisType; + } + + export function isTypeVariableType(type: Type): type is TypeVariable { + return !!(type.flags & TypeFlags.TypeVariable); + } + + export function isUnionType(type: Type): type is UnionType { + return !!(type.flags & TypeFlags.Union); + } + + export function isUnionOrIntersectionType(type: Type): type is IntersectionType | UnionType { + return !!(type.flags & TypeFlags.UnionOrIntersection); + } + namespace JsxNames { export const JSX = "JSX" as __String; export const IntrinsicElements = "IntrinsicElements" as __String; diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 921d75d14ebab..17bd2ec6f5ca8 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -7670,70 +7670,6 @@ namespace ts { factory.createStringLiteral(name, !!singleQuote); } - export function isBigIntLiteralType(type: Type): type is BigIntLiteralType { - return !!(type.flags & TypeFlags.BigIntLiteral); - } - - export function isConditionalType(type: Type): type is ConditionalType { - return !!(type.flags & TypeFlags.Conditional); - } - - export function isIndexType(type: Type): type is IndexType { - return !!(type.flags & TypeFlags.Index); - } - - export function isIndexedAccessType(type: Type): type is IndexedAccessType { - return !!(type.flags & TypeFlags.IndexedAccess); - } - - export function isIntersectionType(type: Type): type is IntersectionType { - return !!(type.flags & TypeFlags.Intersection); - } - - export function isNumberLiteralType(type: Type): type is NumberLiteralType { - return !!(type.flags & TypeFlags.NumberLiteral); - } - - export function isObjectType(type: Type): type is ObjectType { - return !!(type.flags & TypeFlags.Object); - } - - export function isStringMappingType(type: Type): type is StringMappingType { - return !!(type.flags & TypeFlags.StringMapping); - } - - export function isSubstitutionType(type: Type): type is SubstitutionType { - return !!(type.flags & TypeFlags.Substitution); - } - - export function isStringLiteralType(type: Type): type is StringLiteralType { - return !!(type.flags & TypeFlags.StringLiteral); - } - - export function isTemplateLiteralType(type: Type): type is TemplateLiteralType { - return !!(type.flags & TypeFlags.TemplateLiteral); - } - - export function isTypeParameterType(type: Type): type is TypeParameter { - return !!(type.flags & TypeFlags.TypeParameter); - } - - export function isThisTypeParameter(type: Type): boolean { - return isTypeParameterType(type) && !!type.isThisType; - } - - export function isTypeVariableType(type: Type): type is TypeVariable { - return !!(type.flags & TypeFlags.TypeVariable); - } - - export function isUnionType(type: Type): type is UnionType { - return !!(type.flags & TypeFlags.Union); - } - - export function isUnionOrIntersectionType(type: Type): type is IntersectionType | UnionType { - return !!(type.flags & TypeFlags.UnionOrIntersection); - } - export interface NodeModulePathParts { readonly topLevelNodeModulesIndex: number; readonly topLevelPackageNameIndex: number;