diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 6b43b3802c2..9b7b2bd12c8 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -131,8 +131,8 @@ namespace ts { const noConstraintType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined); - const anySignature = createSignature(undefined, undefined, emptyArray, anyType, 0, /*hasRestParameter*/ false, /*hasStringLiterals*/ false); - const unknownSignature = createSignature(undefined, undefined, emptyArray, unknownType, 0, /*hasRestParameter*/ false, /*hasStringLiterals*/ false); + const anySignature = createSignature(undefined, undefined, emptyArray, anyType, /*typePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasStringLiterals*/ false); + const unknownSignature = createSignature(undefined, undefined, emptyArray, unknownType, /*typePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasStringLiterals*/ false); const enumNumberIndexInfo = createIndexInfo(stringType, /*isReadonly*/ true); @@ -1711,6 +1711,15 @@ namespace ts { return result; } + function typePredicateToString(typePredicate: TypePredicate, enclosingDeclaration?: Declaration, flags?: TypeFormatFlags): string { + const writer = getSingleLineStringWriter(); + getSymbolDisplayBuilder().buildTypePredicateDisplay(typePredicate, writer, enclosingDeclaration, flags); + const result = writer.string(); + releaseStringWriter(writer); + + return result; + } + function getTypeAliasForTypeLiteral(type: Type): Symbol { if (type.symbol && type.symbol.flags & SymbolFlags.TypeLiteral) { let node = type.symbol.declarations[0].parent; @@ -1844,16 +1853,10 @@ namespace ts { function writeType(type: Type, flags: TypeFormatFlags) { // Write undefined/null type as any if (type.flags & TypeFlags.Intrinsic) { - if (type.flags & TypeFlags.PredicateType) { - buildTypePredicateDisplay(writer, (type as PredicateType).predicate); - buildTypeDisplay((type as PredicateType).predicate.type, writer, enclosingDeclaration, flags, symbolStack); - } - else { - // Special handling for unknown / resolving types, they should show up as any and not unknown or __resolving - writer.writeKeyword(!(globalFlags & TypeFormatFlags.WriteOwnNameForAnyLike) && isTypeAny(type) - ? "any" - : (type).intrinsicName); - } + // Special handling for unknown / resolving types, they should show up as any and not unknown or __resolving + writer.writeKeyword(!(globalFlags & TypeFormatFlags.WriteOwnNameForAnyLike) && isTypeAny(type) + ? "any" + : (type).intrinsicName); } else if (type.flags & TypeFlags.ThisType) { if (inObjectTypeLiteral) { @@ -2213,7 +2216,7 @@ namespace ts { writePunctuation(writer, SyntaxKind.CloseParenToken); } - function buildTypePredicateDisplay(writer: SymbolWriter, predicate: TypePredicate) { + function buildTypePredicateDisplay(predicate: TypePredicate, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, symbolStack?: Symbol[]): void { if (isIdentifierTypePredicate(predicate)) { writer.writeParameter(predicate.parameterName); } @@ -2223,6 +2226,7 @@ namespace ts { writeSpace(writer); writeKeyword(writer, SyntaxKind.IsKeyword); writeSpace(writer); + buildTypeDisplay(predicate.type, writer, enclosingDeclaration, flags, symbolStack); } function buildReturnTypeDisplay(signature: Signature, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, symbolStack?: Symbol[]) { @@ -2235,8 +2239,13 @@ namespace ts { } writeSpace(writer); - const returnType = getReturnTypeOfSignature(signature); - buildTypeDisplay(returnType, writer, enclosingDeclaration, flags, symbolStack); + if (signature.typePredicate) { + buildTypePredicateDisplay(signature.typePredicate, writer, enclosingDeclaration, flags, symbolStack); + } + else { + const returnType = getReturnTypeOfSignature(signature); + buildTypeDisplay(returnType, writer, enclosingDeclaration, flags, symbolStack); + } } function buildSignatureDisplay(signature: Signature, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, kind?: SignatureKind, symbolStack?: Symbol[]) { @@ -2255,6 +2264,7 @@ namespace ts { } buildDisplayForParametersAndDelimiters(signature.parameters, writer, enclosingDeclaration, flags, symbolStack); + buildReturnTypeDisplay(signature, writer, enclosingDeclaration, flags, symbolStack); } @@ -2262,6 +2272,7 @@ namespace ts { buildSymbolDisplay, buildTypeDisplay, buildTypeParameterDisplay, + buildTypePredicateDisplay, buildParameterDisplay, buildDisplayForParametersAndDelimiters, buildDisplayForTypeParametersAndDelimiters, @@ -2800,9 +2811,6 @@ namespace ts { if (declaration.kind === SyntaxKind.PropertyAssignment) { return type; } - if (type.flags & TypeFlags.PredicateType && (declaration.kind === SyntaxKind.PropertyDeclaration || declaration.kind === SyntaxKind.PropertySignature)) { - return type; - } return getWidenedType(type); } @@ -3533,12 +3541,13 @@ namespace ts { } function createSignature(declaration: SignatureDeclaration, typeParameters: TypeParameter[], parameters: Symbol[], - resolvedReturnType: Type, minArgumentCount: number, hasRestParameter: boolean, hasStringLiterals: boolean): Signature { + resolvedReturnType: Type, typePredicate: TypePredicate, minArgumentCount: number, hasRestParameter: boolean, hasStringLiterals: boolean): Signature { const sig = new Signature(checker); sig.declaration = declaration; sig.typeParameters = typeParameters; sig.parameters = parameters; sig.resolvedReturnType = resolvedReturnType; + sig.typePredicate = typePredicate; sig.minArgumentCount = minArgumentCount; sig.hasRestParameter = hasRestParameter; sig.hasStringLiterals = hasStringLiterals; @@ -3547,14 +3556,14 @@ namespace ts { function cloneSignature(sig: Signature): Signature { return createSignature(sig.declaration, sig.typeParameters, sig.parameters, sig.resolvedReturnType, - sig.minArgumentCount, sig.hasRestParameter, sig.hasStringLiterals); + sig.typePredicate, sig.minArgumentCount, sig.hasRestParameter, sig.hasStringLiterals); } function getDefaultConstructSignatures(classType: InterfaceType): Signature[] { const baseConstructorType = getBaseConstructorTypeOfClass(classType); const baseSignatures = getSignaturesOfType(baseConstructorType, SignatureKind.Construct); if (baseSignatures.length === 0) { - return [createSignature(undefined, classType.localTypeParameters, emptyArray, classType, 0, /*hasRestParameter*/ false, /*hasStringLiterals*/ false)]; + return [createSignature(undefined, classType.localTypeParameters, emptyArray, classType, /*typePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasStringLiterals*/ false)]; } const baseTypeNode = getBaseTypeNodeOfClass(classType); const typeArguments = map(baseTypeNode.typeArguments, getTypeFromTypeNode); @@ -4086,6 +4095,7 @@ namespace ts { let minArgumentCount = -1; const isJSConstructSignature = isJSDocConstructSignature(declaration); let returnType: Type = undefined; + let typePredicate: TypePredicate = undefined; // If this is a JSDoc construct signature, then skip the first parameter in the // parameter list. The first parameter represents the return type of the construct @@ -4129,6 +4139,9 @@ namespace ts { } else if (declaration.type) { returnType = getTypeFromTypeNode(declaration.type); + if (declaration.type.kind === SyntaxKind.TypePredicate) { + typePredicate = createTypePredicateFromTypePredicateNode(declaration.type as TypePredicateNode); + } } else { if (declaration.flags & NodeFlags.JavaScriptFile) { @@ -4150,7 +4163,7 @@ namespace ts { } } - links.resolvedSignature = createSignature(declaration, typeParameters, parameters, returnType, minArgumentCount, hasRestParameter(declaration), hasStringLiterals); + links.resolvedSignature = createSignature(declaration, typeParameters, parameters, returnType, typePredicate, minArgumentCount, hasRestParameter(declaration), hasStringLiterals); } return links.resolvedSignature; } @@ -4862,25 +4875,6 @@ namespace ts { return links.resolvedType; } - function getPredicateType(node: TypePredicateNode): Type { - return createPredicateType(getSymbolOfNode(node), createTypePredicateFromTypePredicateNode(node)); - } - - function createPredicateType(symbol: Symbol, predicate: ThisTypePredicate | IdentifierTypePredicate) { - const type = createType(TypeFlags.Boolean | TypeFlags.PredicateType) as PredicateType; - type.symbol = symbol; - type.predicate = predicate; - return type; - } - - function getTypeFromPredicateTypeNode(node: TypePredicateNode): Type { - const links = getNodeLinks(node); - if (!links.resolvedType) { - links.resolvedType = getPredicateType(node); - } - return links.resolvedType; - } - function getTypeFromTypeNode(node: TypeNode): Type { switch (node.kind) { case SyntaxKind.AnyKeyword: @@ -4905,7 +4899,7 @@ namespace ts { case SyntaxKind.JSDocTypeReference: return getTypeFromTypeReference(node); case SyntaxKind.TypePredicate: - return getTypeFromPredicateTypeNode(node); + return booleanType; case SyntaxKind.ExpressionWithTypeArguments: return getTypeFromTypeReference(node); case SyntaxKind.TypeQuery: @@ -5057,6 +5051,7 @@ namespace ts { function instantiateSignature(signature: Signature, mapper: TypeMapper, eraseTypeParameters?: boolean): Signature { let freshTypeParameters: TypeParameter[]; + let freshTypePredicate: TypePredicate; if (signature.typeParameters && !eraseTypeParameters) { // First create a fresh set of type parameters, then include a mapping from the old to the // new type parameters in the mapper function. Finally store this mapper in the new type @@ -5067,9 +5062,13 @@ namespace ts { tp.mapper = mapper; } } + if (signature.typePredicate) { + freshTypePredicate = cloneTypePredicate(signature.typePredicate, mapper); + } const result = createSignature(signature.declaration, freshTypeParameters, instantiateList(signature.parameters, mapper, instantiateSymbol), instantiateType(signature.resolvedReturnType, mapper), + freshTypePredicate, signature.minArgumentCount, signature.hasRestParameter, signature.hasStringLiterals); result.target = signature; result.mapper = mapper; @@ -5139,10 +5138,6 @@ namespace ts { if (type.flags & TypeFlags.Intersection) { return getIntersectionType(instantiateList((type).types, mapper, instantiateType)); } - if (type.flags & TypeFlags.PredicateType) { - const predicate = (type as PredicateType).predicate; - return createPredicateType(type.symbol, cloneTypePredicate(predicate, mapper)); - } } return type; } @@ -5288,21 +5283,58 @@ namespace ts { const sourceReturnType = getReturnTypeOfSignature(source); // The following block preserves behavior forbidding boolean returning functions from being assignable to type guard returning functions - if (targetReturnType.flags & TypeFlags.PredicateType && (targetReturnType as PredicateType).predicate.kind === TypePredicateKind.Identifier) { - if (!(sourceReturnType.flags & TypeFlags.PredicateType)) { + if (target.typePredicate) { + if (source.typePredicate) { + result &= compareTypePredicateRelatedTo(source.typePredicate, target.typePredicate, reportErrors, errorReporter, compareTypes); + } + else if (isIdentifierTypePredicate(target.typePredicate)) { if (reportErrors) { errorReporter(Diagnostics.Signature_0_must_have_a_type_predicate, signatureToString(source)); } return Ternary.False; } } + else { + result &= compareTypes(sourceReturnType, targetReturnType, reportErrors); + } - result &= compareTypes(sourceReturnType, targetReturnType, reportErrors); } return result; } + function compareTypePredicateRelatedTo(source: TypePredicate, + target: TypePredicate, + reportErrors: boolean, + errorReporter: (d: DiagnosticMessage, arg0?: string, arg1?: string) => void, + compareTypes: (s: Type, t: Type, reportErrors?: boolean) => Ternary): Ternary { + if (source.kind !== target.kind) { + if (reportErrors) { + errorReporter(Diagnostics.A_this_based_type_guard_is_not_compatible_with_a_parameter_based_type_guard); + errorReporter(Diagnostics.Type_predicate_0_is_not_assignable_to_1, typePredicateToString(source), typePredicateToString(target)); + } + return Ternary.False; + } + + if (source.kind === TypePredicateKind.Identifier) { + const sourceIdentifierPredicate = source as IdentifierTypePredicate; + const targetIdentifierPredicate = target as IdentifierTypePredicate; + if (sourceIdentifierPredicate.parameterIndex !== targetIdentifierPredicate.parameterIndex) { + if (reportErrors) { + errorReporter(Diagnostics.Parameter_0_is_not_in_the_same_position_as_parameter_1, sourceIdentifierPredicate.parameterName, targetIdentifierPredicate.parameterName); + errorReporter(Diagnostics.Type_predicate_0_is_not_assignable_to_1, typePredicateToString(source), typePredicateToString(target)); + } + return Ternary.False; + } + } + + const related = compareTypes(source.type, target.type, reportErrors); + if (related === Ternary.False && reportErrors) { + errorReporter(Diagnostics.Type_predicate_0_is_not_assignable_to_1, typePredicateToString(source), typePredicateToString(target)); + } + return related; + } + function isImplementationCompatibleWithOverload(implementation: Signature, overload: Signature): boolean { const erasedSource = getErasedSignature(implementation); const erasedTarget = getErasedSignature(overload); @@ -5429,33 +5461,6 @@ namespace ts { if (source === numberType && target.flags & TypeFlags.Enum) return Ternary.True; } if (source.flags & TypeFlags.Boolean && target.flags & TypeFlags.Boolean) { - if (source.flags & TypeFlags.PredicateType && target.flags & TypeFlags.PredicateType) { - const sourcePredicate = source as PredicateType; - const targetPredicate = target as PredicateType; - if (sourcePredicate.predicate.kind !== targetPredicate.predicate.kind) { - if (reportErrors) { - reportError(Diagnostics.A_this_based_type_guard_is_not_compatible_with_a_parameter_based_type_guard); - reportError(Diagnostics.Type_predicate_0_is_not_assignable_to_1, typeToString(source), typeToString(target)); - } - return Ternary.False; - } - if (sourcePredicate.predicate.kind === TypePredicateKind.Identifier) { - const sourceIdentifierPredicate = sourcePredicate.predicate as IdentifierTypePredicate; - const targetIdentifierPredicate = targetPredicate.predicate as IdentifierTypePredicate; - if (sourceIdentifierPredicate.parameterIndex !== targetIdentifierPredicate.parameterIndex) { - if (reportErrors) { - reportError(Diagnostics.Parameter_0_is_not_in_the_same_position_as_parameter_1, sourceIdentifierPredicate.parameterName, targetIdentifierPredicate.parameterName); - reportError(Diagnostics.Type_predicate_0_is_not_assignable_to_1, typeToString(source), typeToString(target)); - } - return Ternary.False; - } - } - const related = isRelatedTo(sourcePredicate.predicate.type, targetPredicate.predicate.type, reportErrors, headMessage); - if (related === Ternary.False && reportErrors) { - reportError(Diagnostics.Type_predicate_0_is_not_assignable_to_1, typeToString(source), typeToString(target)); - } - return related; - } return Ternary.True; } @@ -6311,9 +6316,6 @@ namespace ts { if (type.flags & (TypeFlags.Undefined | TypeFlags.Null)) { return anyType; } - if (type.flags & TypeFlags.PredicateType) { - return booleanType; - } if (type.flags & TypeFlags.ObjectLiteral) { return getWidenedTypeOfObjectLiteral(type); } @@ -6541,11 +6543,6 @@ namespace ts { inferFromTypes(sourceTypes[i], targetTypes[i]); } } - else if (source.flags & TypeFlags.PredicateType && target.flags & TypeFlags.PredicateType) { - if ((source as PredicateType).predicate.kind === (target as PredicateType).predicate.kind) { - inferFromTypes((source as PredicateType).predicate.type, (target as PredicateType).predicate.type); - } - } else if (source.flags & TypeFlags.Tuple && target.flags & TypeFlags.Tuple && (source).elementTypes.length === (target).elementTypes.length) { // If source and target are tuples of the same size, infer from element types const sourceTypes = (source).elementTypes; @@ -6641,7 +6638,13 @@ namespace ts { function inferFromSignature(source: Signature, target: Signature) { forEachMatchingParameterType(source, target, inferFromTypes); - inferFromTypes(getReturnTypeOfSignature(source), getReturnTypeOfSignature(target)); + + if (source.typePredicate && target.typePredicate && source.typePredicate.kind === target.typePredicate.kind) { + inferFromTypes(source.typePredicate.type, target.typePredicate.type); + } + else { + inferFromTypes(getReturnTypeOfSignature(source), getReturnTypeOfSignature(target)); + } } function inferFromIndexTypes(source: Type, target: Type, sourceKind: IndexKind, targetKind: IndexKind) { @@ -7067,46 +7070,33 @@ namespace ts { return originalType; } - function narrowTypeByTypePredicate(type: Type, expr: CallExpression, assumeTrue: boolean): Type { + function narrowTypeByTypePredicate(type: Type, callExpression: CallExpression, assumeTrue: boolean): Type { if (type.flags & TypeFlags.Any) { return type; } - const signature = getResolvedSignature(expr); - const predicateType = getReturnTypeOfSignature(signature); - - if (!predicateType || !(predicateType.flags & TypeFlags.PredicateType)) { + const signature = getResolvedSignature(callExpression); + + const predicate = signature.typePredicate; + if (!predicate) { return type; } - const predicate = (predicateType as PredicateType).predicate; + if (isIdentifierTypePredicate(predicate)) { - const callExpression = expr as CallExpression; if (callExpression.arguments[predicate.parameterIndex] && getSymbolAtTypePredicatePosition(callExpression.arguments[predicate.parameterIndex]) === symbol) { return getNarrowedType(type, predicate.type, assumeTrue); } } else { - const expression = skipParenthesizedNodes(expr.expression); - return narrowTypeByThisTypePredicate(type, predicate, expression, assumeTrue); + const invokedExpression = skipParenthesizedNodes(callExpression.expression); + return narrowTypeByThisTypePredicate(type, predicate, invokedExpression, assumeTrue); } return type; } - function narrowTypeByTypePredicateMember(type: Type, expr: ElementAccessExpression | PropertyAccessExpression, assumeTrue: boolean): Type { - if (type.flags & TypeFlags.Any) { - return type; - } - const memberType = getTypeOfExpression(expr); - if (!(memberType.flags & TypeFlags.PredicateType)) { - return type; - } - - return narrowTypeByThisTypePredicate(type, (memberType as PredicateType).predicate as ThisTypePredicate, expr, assumeTrue); - } - - function narrowTypeByThisTypePredicate(type: Type, predicate: ThisTypePredicate, expression: Expression, assumeTrue: boolean): Type { - if (expression.kind === SyntaxKind.ElementAccessExpression || expression.kind === SyntaxKind.PropertyAccessExpression) { - const accessExpression = expression as ElementAccessExpression | PropertyAccessExpression; + function narrowTypeByThisTypePredicate(type: Type, predicate: ThisTypePredicate, invokedExpression: Expression, assumeTrue: boolean): Type { + if (invokedExpression.kind === SyntaxKind.ElementAccessExpression || invokedExpression.kind === SyntaxKind.PropertyAccessExpression) { + const accessExpression = invokedExpression as ElementAccessExpression | PropertyAccessExpression; const possibleIdentifier = skipParenthesizedNodes(accessExpression.expression); if (possibleIdentifier.kind === SyntaxKind.Identifier && getSymbolAtTypePredicatePosition(possibleIdentifier) === symbol) { return getNarrowedType(type, predicate.type, assumeTrue); @@ -7121,6 +7111,7 @@ namespace ts { case SyntaxKind.Identifier: case SyntaxKind.PropertyAccessExpression: case SyntaxKind.QualifiedName: + // TODO (drosen): Why a qualified name? return getSymbolOfEntityNameOrPropertyAccessExpression(expr as Node as (EntityName | PropertyAccessExpression)); } } @@ -7153,9 +7144,6 @@ namespace ts { return narrowType(type, (expr).operand, !assumeTrue); } break; - case SyntaxKind.ElementAccessExpression: - case SyntaxKind.PropertyAccessExpression: - return narrowTypeByTypePredicateMember(type, expr as (ElementAccessExpression | PropertyAccessExpression), assumeTrue); } return type; } @@ -10544,12 +10532,13 @@ namespace ts { return aggregatedTypes; } - /* - *TypeScript Specification 1.0 (6.3) - July 2014 - * An explicitly typed function whose return type isn't the Void type, - * the Any type, or a union type containing the Void or Any type as a constituent - * must have at least one return statement somewhere in its body. - * An exception to this rule is if the function implementation consists of a single 'throw' statement. + /** + * TypeScript Specification 1.0 (6.3) - July 2014 + * An explicitly typed function whose return type isn't the Void type, + * the Any type, or a union type containing the Void or Any type as a constituent + * must have at least one return statement somewhere in its body. + * An exception to this rule is if the function implementation consists of a single 'throw' statement. + * * @param returnType - return type of the function, can be undefined if return type is not explicitly specified */ function checkAllCodePathsInNonVoidFunctionReturnOrThrow(func: FunctionLikeDeclaration, returnType: Type): void { @@ -11579,16 +11568,16 @@ namespace ts { if (!parent) { return; } - const returnType = getReturnTypeOfSignature(getSignatureFromDeclaration(parent)); - if (!returnType || !(returnType.flags & TypeFlags.PredicateType)) { + const typePredicate = getSignatureFromDeclaration(parent).typePredicate; + if (!typePredicate) { return; } + const { parameterName } = node; - if (parameterName.kind === SyntaxKind.ThisType) { + if (isThisTypePredicate(typePredicate)) { getTypeFromThisTypeNode(parameterName as ThisTypeNode); } else { - const typePredicate = (returnType).predicate; if (typePredicate.parameterIndex >= 0) { if (parent.parameters[typePredicate.parameterIndex].dotDotDotToken) { error(parameterName, @@ -11603,12 +11592,8 @@ namespace ts { else if (parameterName) { let hasReportedError = false; for (const { name } of parent.parameters) { - if ((name.kind === SyntaxKind.ObjectBindingPattern || - name.kind === SyntaxKind.ArrayBindingPattern) && - checkIfTypePredicateVariableIsDeclaredInBindingPattern( - name, - parameterName, - typePredicate.parameterName)) { + if (isBindingPattern(name) && + checkIfTypePredicateVariableIsDeclaredInBindingPattern(name, parameterName, typePredicate.parameterName)) { hasReportedError = true; break; } @@ -11676,8 +11661,9 @@ namespace ts { forEach(node.parameters, checkParameter); - checkSourceElement(node.type); - + if (node.type) { + checkSourceElement(node.type); + } if (produceDiagnostics) { checkCollisionWithArgumentsInGeneratedCode(node); @@ -13634,7 +13620,7 @@ namespace ts { error(node.expression, Diagnostics.Return_type_of_constructor_signature_must_be_assignable_to_the_instance_type_of_the_class); } } - else if (func.type || isGetAccessorWithAnnotatedSetAccessor(func) || returnType.flags & TypeFlags.PredicateType) { + else if (func.type || isGetAccessorWithAnnotatedSetAccessor(func)) { if (isAsyncFunctionLike(func)) { const promisedType = getPromisedType(returnType); const awaitedType = checkAwaitedType(exprType, node.expression, Diagnostics.Return_expression_in_async_function_does_not_have_a_valid_callable_then_member); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 6b9f49cac01..7f88879c75f 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1749,6 +1749,7 @@ namespace ts { buildSignatureDisplay(signatures: Signature, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, kind?: SignatureKind): void; buildParameterDisplay(parameter: Symbol, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void; buildTypeParameterDisplay(tp: TypeParameter, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void; + buildTypePredicateDisplay(predicate: TypePredicate, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void; buildTypeParameterDisplayFromSymbol(symbol: Symbol, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void; buildDisplayForParametersAndDelimiters(parameters: Symbol[], writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void; buildDisplayForTypeParametersAndDelimiters(typeParameters: TypeParameter[], writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void; @@ -1814,22 +1815,24 @@ namespace ts { Identifier } - export interface TypePredicate { + export interface TypePredicateBase { kind: TypePredicateKind; type: Type; } // @kind (TypePredicateKind.This) - export interface ThisTypePredicate extends TypePredicate { + export interface ThisTypePredicate extends TypePredicateBase { _thisTypePredicateBrand: any; } // @kind (TypePredicateKind.Identifier) - export interface IdentifierTypePredicate extends TypePredicate { + export interface IdentifierTypePredicate extends TypePredicateBase { parameterName: string; parameterIndex: number; } + export type TypePredicate = IdentifierTypePredicate | ThisTypePredicate; + /* @internal */ export type AnyImportSyntax = ImportDeclaration | ImportEqualsDeclaration; @@ -2095,7 +2098,6 @@ namespace ts { ESSymbol = 0x01000000, // Type of symbol primitive introduced in ES6 ThisType = 0x02000000, // This type ObjectLiteralPatternWithComputedProperties = 0x04000000, // Object literal type implied by binding pattern has computed properties - PredicateType = 0x08000000, // Predicate types are also Boolean types, but should not be considered Intrinsics - there's no way to capture this with flags /* @internal */ Intrinsic = Any | String | Number | Boolean | ESSymbol | Void | Undefined | Null, @@ -2107,7 +2109,7 @@ namespace ts { UnionOrIntersection = Union | Intersection, StructuredType = ObjectType | Union | Intersection, /* @internal */ - RequiresWidening = ContainsUndefinedOrNull | ContainsObjectLiteral | PredicateType, + RequiresWidening = ContainsUndefinedOrNull | ContainsObjectLiteral, /* @internal */ PropagatingFlags = ContainsUndefinedOrNull | ContainsObjectLiteral | ContainsAnyFunctionType } @@ -2128,11 +2130,6 @@ namespace ts { intrinsicName: string; // Name of intrinsic type } - // Predicate types (TypeFlags.Predicate) - export interface PredicateType extends Type { - predicate: ThisTypePredicate | IdentifierTypePredicate; - } - // String literal types (TypeFlags.StringLiteral) export interface StringLiteralType extends Type { text: string; // Text of string literal @@ -2267,6 +2264,8 @@ namespace ts { erasedSignatureCache?: Signature; // Erased version of signature (deferred) /* @internal */ isolatedSignatureType?: ObjectType; // A manufactured type that just contains the signature for purposes of signature comparison + /* @internal */ + typePredicate?: TypePredicate; } export const enum IndexKind { diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 0903d937d7b..4df8d723f5e 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -746,6 +746,10 @@ namespace ts { return predicate && predicate.kind === TypePredicateKind.Identifier; } + export function isThisTypePredicate(predicate: TypePredicate): predicate is ThisTypePredicate { + return predicate && predicate.kind === TypePredicateKind.This; + } + export function getContainingFunction(node: Node): FunctionLikeDeclaration { while (true) { node = node.parent;