Merge pull request #5906 from weswigham/this-type-guards

This type predicates for type guards
This commit is contained in:
Wesley Wigham 2015-12-09 17:22:39 -08:00
commit 58400ed771
30 changed files with 2943 additions and 178 deletions

View file

@ -1189,7 +1189,8 @@ namespace ts {
case SyntaxKind.ThisType:
seenThisKeyword = true;
return;
case SyntaxKind.TypePredicate:
return checkTypePredicate(node as TypePredicateNode);
case SyntaxKind.TypeParameter:
return declareSymbolAndAddToSymbolTable(<Declaration>node, SymbolFlags.TypeParameter, SymbolFlags.TypeParameterExcludes);
case SyntaxKind.Parameter:
@ -1275,6 +1276,17 @@ namespace ts {
}
}
function checkTypePredicate(node: TypePredicateNode) {
const { parameterName, type } = node;
if (parameterName && parameterName.kind === SyntaxKind.Identifier) {
checkStrictModeIdentifier(parameterName as Identifier);
}
if (parameterName && parameterName.kind === SyntaxKind.ThisType) {
seenThisKeyword = true;
}
bind(type);
}
function bindSourceFileIfExternalModule() {
setExportContextFlag(file);
if (isExternalModule(file)) {

View file

@ -124,8 +124,8 @@ namespace ts {
const noConstraintType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
const anySignature = createSignature(undefined, undefined, emptyArray, anyType, undefined, 0, /*hasRestParameter*/ false, /*hasStringLiterals*/ false);
const unknownSignature = createSignature(undefined, undefined, emptyArray, unknownType, undefined, 0, /*hasRestParameter*/ false, /*hasStringLiterals*/ false);
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 globals: SymbolTable = {};
@ -1743,10 +1743,16 @@ namespace ts {
function writeType(type: Type, flags: TypeFormatFlags) {
// Write undefined/null type as any
if (type.flags & TypeFlags.Intrinsic) {
// 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"
: (<IntrinsicType>type).intrinsicName);
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"
: (<IntrinsicType>type).intrinsicName);
}
}
else if (type.flags & TypeFlags.ThisType) {
if (inObjectTypeLiteral) {
@ -2116,6 +2122,18 @@ namespace ts {
writePunctuation(writer, SyntaxKind.CloseParenToken);
}
function buildTypePredicateDisplay(writer: SymbolWriter, predicate: TypePredicate) {
if (isIdentifierTypePredicate(predicate)) {
writer.writeParameter(predicate.parameterName);
}
else {
writeKeyword(writer, SyntaxKind.ThisKeyword);
}
writeSpace(writer);
writeKeyword(writer, SyntaxKind.IsKeyword);
writeSpace(writer);
}
function buildReturnTypeDisplay(signature: Signature, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, symbolStack?: Symbol[]) {
if (flags & TypeFormatFlags.WriteArrowStyleSignature) {
writeSpace(writer);
@ -2126,17 +2144,7 @@ namespace ts {
}
writeSpace(writer);
let returnType: Type;
if (signature.typePredicate) {
writer.writeParameter(signature.typePredicate.parameterName);
writeSpace(writer);
writeKeyword(writer, SyntaxKind.IsKeyword);
writeSpace(writer);
returnType = signature.typePredicate.type;
}
else {
returnType = getReturnTypeOfSignature(signature);
}
const returnType = getReturnTypeOfSignature(signature);
buildTypeDisplay(returnType, writer, enclosingDeclaration, flags, symbolStack);
}
@ -2693,7 +2701,13 @@ namespace ts {
// During a normal type check we'll never get to here with a property assignment (the check of the containing
// object literal uses a different path). We exclude widening only so that language services and type verification
// tools see the actual type.
return declaration.kind !== SyntaxKind.PropertyAssignment ? getWidenedType(type) : type;
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);
}
// Rest parameters default to type any[], other parameters default to type any
@ -3427,13 +3441,12 @@ namespace ts {
}
function createSignature(declaration: SignatureDeclaration, typeParameters: TypeParameter[], parameters: Symbol[],
resolvedReturnType: Type, typePredicate: TypePredicate, minArgumentCount: number, hasRestParameter: boolean, hasStringLiterals: boolean): Signature {
resolvedReturnType: Type, 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;
@ -3441,7 +3454,7 @@ namespace ts {
}
function cloneSignature(sig: Signature): Signature {
return createSignature(sig.declaration, sig.typeParameters, sig.parameters, sig.resolvedReturnType, sig.typePredicate,
return createSignature(sig.declaration, sig.typeParameters, sig.parameters, sig.resolvedReturnType,
sig.minArgumentCount, sig.hasRestParameter, sig.hasStringLiterals);
}
@ -3449,7 +3462,7 @@ namespace ts {
const baseConstructorType = getBaseConstructorTypeOfClass(classType);
const baseSignatures = getSignaturesOfType(baseConstructorType, SignatureKind.Construct);
if (baseSignatures.length === 0) {
return [createSignature(undefined, classType.localTypeParameters, emptyArray, classType, undefined, 0, /*hasRestParameter*/ false, /*hasStringLiterals*/ false)];
return [createSignature(undefined, classType.localTypeParameters, emptyArray, classType, 0, /*hasRestParameter*/ false, /*hasStringLiterals*/ false)];
}
const baseTypeNode = getBaseTypeNodeOfClass(classType);
const typeArguments = map(baseTypeNode.typeArguments, getTypeFromTypeNode);
@ -3915,6 +3928,24 @@ namespace ts {
return false;
}
function createTypePredicateFromTypePredicateNode(node: TypePredicateNode): IdentifierTypePredicate | ThisTypePredicate {
if (node.parameterName.kind === SyntaxKind.Identifier) {
const parameterName = node.parameterName as Identifier;
return {
kind: TypePredicateKind.Identifier,
parameterName: parameterName ? parameterName.text : undefined,
parameterIndex: parameterName ? getTypePredicateParameterIndex((node.parent as SignatureDeclaration).parameters, parameterName) : undefined,
type: getTypeFromTypeNode(node.type)
} as IdentifierTypePredicate;
}
else {
return {
kind: TypePredicateKind.This,
type: getTypeFromTypeNode(node.type)
} as ThisTypePredicate;
}
}
function getSignatureFromDeclaration(declaration: SignatureDeclaration): Signature {
const links = getNodeLinks(declaration);
if (!links.resolvedSignature) {
@ -3955,20 +3986,11 @@ namespace ts {
}
let returnType: Type;
let typePredicate: TypePredicate;
if (classType) {
returnType = classType;
}
else if (declaration.type) {
returnType = getTypeFromTypeNode(declaration.type);
if (declaration.type.kind === SyntaxKind.TypePredicate) {
const typePredicateNode = <TypePredicateNode>declaration.type;
typePredicate = {
parameterName: typePredicateNode.parameterName ? typePredicateNode.parameterName.text : undefined,
parameterIndex: typePredicateNode.parameterName ? getTypePredicateParameterIndex(declaration.parameters, typePredicateNode.parameterName) : undefined,
type: getTypeFromTypeNode(typePredicateNode.type)
};
}
}
else {
// TypeScript 1.0 spec (April 2014):
@ -3983,8 +4005,7 @@ namespace ts {
}
}
links.resolvedSignature = createSignature(declaration, typeParameters, parameters, returnType, typePredicate,
minArgumentCount, hasRestParameter(declaration), hasStringLiterals);
links.resolvedSignature = createSignature(declaration, typeParameters, parameters, returnType, minArgumentCount, hasRestParameter(declaration), hasStringLiterals);
}
return links.resolvedSignature;
}
@ -4643,6 +4664,25 @@ 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:
@ -4664,7 +4704,7 @@ namespace ts {
case SyntaxKind.TypeReference:
return getTypeFromTypeReference(<TypeReferenceNode>node);
case SyntaxKind.TypePredicate:
return booleanType;
return getTypeFromPredicateTypeNode(<TypePredicateNode>node);
case SyntaxKind.ExpressionWithTypeArguments:
return getTypeFromTypeReference(<ExpressionWithTypeArguments>node);
case SyntaxKind.TypeQuery:
@ -4787,24 +4827,32 @@ namespace ts {
return result;
}
function cloneTypePredicate(predicate: TypePredicate, mapper: TypeMapper): ThisTypePredicate | IdentifierTypePredicate {
if (isIdentifierTypePredicate(predicate)) {
return {
kind: TypePredicateKind.Identifier,
parameterName: predicate.parameterName,
parameterIndex: predicate.parameterIndex,
type: instantiateType(predicate.type, mapper)
} as IdentifierTypePredicate;
}
else {
return {
kind: TypePredicateKind.This,
type: instantiateType(predicate.type, mapper)
} as ThisTypePredicate;
}
}
function instantiateSignature(signature: Signature, mapper: TypeMapper, eraseTypeParameters?: boolean): Signature {
let freshTypeParameters: TypeParameter[];
let freshTypePredicate: TypePredicate;
if (signature.typeParameters && !eraseTypeParameters) {
freshTypeParameters = instantiateList(signature.typeParameters, mapper, instantiateTypeParameter);
mapper = combineTypeMappers(createTypeMapper(signature.typeParameters, freshTypeParameters), mapper);
}
if (signature.typePredicate) {
freshTypePredicate = {
parameterName: signature.typePredicate.parameterName,
parameterIndex: signature.typePredicate.parameterIndex,
type: instantiateType(signature.typePredicate.type, 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;
@ -4874,6 +4922,10 @@ namespace ts {
if (type.flags & TypeFlags.Intersection) {
return getIntersectionType(instantiateList((<IntersectionType>type).types, mapper, instantiateType));
}
if (type.flags & TypeFlags.PredicateType) {
const predicate = (type as PredicateType).predicate;
return createPredicateType(type.symbol, cloneTypePredicate(predicate, mapper));
}
}
return type;
}
@ -5045,6 +5097,36 @@ namespace ts {
if (isTypeAny(source)) return Ternary.True;
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;
}
if (source.flags & TypeFlags.FreshObjectLiteral) {
if (hasExcessProperties(<FreshObjectLiteralType>source, target, reportErrors)) {
@ -5610,46 +5692,19 @@ namespace ts {
result &= related;
}
if (source.typePredicate && target.typePredicate) {
const hasDifferentParameterIndex = source.typePredicate.parameterIndex !== target.typePredicate.parameterIndex;
let hasDifferentTypes: boolean;
if (hasDifferentParameterIndex ||
(hasDifferentTypes = !isTypeIdenticalTo(source.typePredicate.type, target.typePredicate.type))) {
const targetReturnType = getReturnTypeOfSignature(target);
if (targetReturnType === voidType) return result;
const sourceReturnType = getReturnTypeOfSignature(source);
// The follow block preserves old 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 (reportErrors) {
const sourceParamText = source.typePredicate.parameterName;
const targetParamText = target.typePredicate.parameterName;
const sourceTypeText = typeToString(source.typePredicate.type);
const targetTypeText = typeToString(target.typePredicate.type);
if (hasDifferentParameterIndex) {
reportError(Diagnostics.Parameter_0_is_not_in_the_same_position_as_parameter_1,
sourceParamText,
targetParamText);
}
else if (hasDifferentTypes) {
reportError(Diagnostics.Type_0_is_not_assignable_to_type_1,
sourceTypeText,
targetTypeText);
}
reportError(Diagnostics.Type_predicate_0_is_not_assignable_to_1,
`${sourceParamText} is ${sourceTypeText}`,
`${targetParamText} is ${targetTypeText}`);
reportError(Diagnostics.Signature_0_must_have_a_type_predicate, signatureToString(source));
}
return Ternary.False;
}
}
else if (!source.typePredicate && target.typePredicate) {
if (reportErrors) {
reportError(Diagnostics.Signature_0_must_have_a_type_predicate, signatureToString(source));
}
return Ternary.False;
}
const targetReturnType = getReturnTypeOfSignature(target);
if (targetReturnType === voidType) return result;
const sourceReturnType = getReturnTypeOfSignature(source);
return result & isRelatedTo(sourceReturnType, targetReturnType, reportErrors);
}
@ -5986,6 +6041,9 @@ 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);
}
@ -6209,6 +6267,11 @@ 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 && (<TupleType>source).elementTypes.length === (<TupleType>target).elementTypes.length) {
// If source and target are tuples of the same size, infer from element types
const sourceTypes = (<TupleType>source).elementTypes;
@ -6304,17 +6367,7 @@ namespace ts {
function inferFromSignature(source: Signature, target: Signature) {
forEachMatchingParameterType(source, target, inferFromTypes);
if (source.typePredicate && target.typePredicate) {
if (target.typePredicate.parameterIndex === source.typePredicate.parameterIndex) {
// Return types from type predicates are treated as booleans. In order to infer types
// from type predicates we would need to infer using the type within the type predicate
// (i.e. 'Foo' from 'x is Foo').
inferFromTypes(source.typePredicate.type, target.typePredicate.type);
}
}
else {
inferFromTypes(getReturnTypeOfSignature(source), getReturnTypeOfSignature(target));
}
inferFromTypes(getReturnTypeOfSignature(source), getReturnTypeOfSignature(target));
}
function inferFromIndexTypes(source: Type, target: Type, sourceKind: IndexKind, targetKind: IndexKind) {
@ -6453,10 +6506,7 @@ namespace ts {
function isAssignedInBinaryExpression(node: BinaryExpression) {
if (node.operatorToken.kind >= SyntaxKind.FirstAssignment && node.operatorToken.kind <= SyntaxKind.LastAssignment) {
let n = node.left;
while (n.kind === SyntaxKind.ParenthesizedExpression) {
n = (<ParenthesizedExpression>n).expression;
}
const n = skipParenthesizedNodes(node.left);
if (n.kind === SyntaxKind.Identifier && getResolvedSymbol(<Identifier>n) === symbol) {
return true;
}
@ -6712,20 +6762,20 @@ namespace ts {
}
if (targetType) {
if (!assumeTrue) {
if (type.flags & TypeFlags.Union) {
return getUnionType(filter((<UnionType>type).types, t => !isTypeSubtypeOf(t, targetType)));
}
return type;
}
return getNarrowedType(type, targetType);
return getNarrowedType(type, targetType, assumeTrue);
}
return type;
}
function getNarrowedType(originalType: Type, narrowedTypeCandidate: Type) {
function getNarrowedType(originalType: Type, narrowedTypeCandidate: Type, assumeTrue: boolean) {
if (!assumeTrue) {
if (originalType.flags & TypeFlags.Union) {
return getUnionType(filter((<UnionType>originalType).types, t => !isTypeSubtypeOf(t, narrowedTypeCandidate)));
}
return originalType;
}
// If the current type is a union type, remove all constituents that aren't assignable to target. If that produces
// 0 candidates, fall back to the assignability check
if (originalType.flags & TypeFlags.Union) {
@ -6748,22 +6798,59 @@ namespace ts {
return type;
}
const signature = getResolvedSignature(expr);
const predicateType = getReturnTypeOfSignature(signature);
if (signature.typePredicate &&
expr.arguments[signature.typePredicate.parameterIndex] &&
getSymbolAtLocation(expr.arguments[signature.typePredicate.parameterIndex]) === symbol) {
if (!assumeTrue) {
if (type.flags & TypeFlags.Union) {
return getUnionType(filter((<UnionType>type).types, t => !isTypeSubtypeOf(t, signature.typePredicate.type)));
}
return type;
if (!predicateType || !(predicateType.flags & TypeFlags.PredicateType)) {
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);
}
return getNarrowedType(type, signature.typePredicate.type);
}
else {
const expression = skipParenthesizedNodes(expr.expression);
return narrowTypeByThisTypePredicate(type, predicate, expression, 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;
const possibleIdentifier = skipParenthesizedNodes(accessExpression.expression);
if (possibleIdentifier.kind === SyntaxKind.Identifier && getSymbolAtTypePredicatePosition(possibleIdentifier) === symbol) {
return getNarrowedType(type, predicate.type, assumeTrue);
}
}
return type;
}
function getSymbolAtTypePredicatePosition(expr: Expression): Symbol {
expr = skipParenthesizedNodes(expr);
switch (expr.kind) {
case SyntaxKind.Identifier:
case SyntaxKind.PropertyAccessExpression:
case SyntaxKind.QualifiedName:
return getSymbolOfEntityNameOrPropertyAccessExpression(expr as Node as (EntityName | PropertyAccessExpression));
}
}
// Narrow the given type based on the given expression having the assumed boolean value. The returned type
// will be a subtype or the same type as the argument.
function narrowType(type: Type, expr: Expression, assumeTrue: boolean): Type {
@ -6792,11 +6879,21 @@ namespace ts {
return narrowType(type, (<PrefixUnaryExpression>expr).operand, !assumeTrue);
}
break;
case SyntaxKind.ElementAccessExpression:
case SyntaxKind.PropertyAccessExpression:
return narrowTypeByTypePredicateMember(type, expr as (ElementAccessExpression | PropertyAccessExpression), assumeTrue);
}
return type;
}
}
function skipParenthesizedNodes(expression: Expression): Expression {
while (expression.kind === SyntaxKind.ParenthesizedExpression) {
expression = (expression as ParenthesizedExpression).expression;
}
return expression;
}
function checkIdentifier(node: Identifier): Type {
const symbol = getResolvedSymbol(node);
@ -10985,7 +11082,7 @@ namespace ts {
return -1;
}
function isInLegalTypePredicatePosition(node: Node): boolean {
function isInLegalParameterTypePredicatePosition(node: Node): boolean {
switch (node.parent.kind) {
case SyntaxKind.ArrowFunction:
case SyntaxKind.CallSignature:
@ -10999,6 +11096,19 @@ namespace ts {
return false;
}
function isInLegalThisTypePredicatePosition(node: Node): boolean {
if (isInLegalParameterTypePredicatePosition(node)) {
return true;
}
switch (node.parent.kind) {
case SyntaxKind.PropertyDeclaration:
case SyntaxKind.PropertySignature:
case SyntaxKind.GetAccessor:
return node === (node.parent as (PropertyDeclaration | GetAccessorDeclaration | PropertySignature)).type;
}
return false;
}
function checkSignatureDeclaration(node: SignatureDeclaration) {
// Grammar checking
if (node.kind === SyntaxKind.IndexSignature) {
@ -11017,9 +11127,14 @@ namespace ts {
if (node.type) {
if (node.type.kind === SyntaxKind.TypePredicate) {
const typePredicate = getSignatureFromDeclaration(node).typePredicate;
const typePredicateNode = <TypePredicateNode>node.type;
if (isInLegalTypePredicatePosition(typePredicateNode)) {
const returnType = getReturnTypeOfSignature(getSignatureFromDeclaration(node));
if (!returnType || !(returnType.flags & TypeFlags.PredicateType)) {
return;
}
const typePredicate = (returnType as PredicateType).predicate;
const typePredicateNode = node.type as TypePredicateNode;
checkSourceElement(typePredicateNode);
if (isIdentifierTypePredicate(typePredicate)) {
if (typePredicate.parameterIndex >= 0) {
if (node.parameters[typePredicate.parameterIndex].dotDotDotToken) {
error(typePredicateNode.parameterName,
@ -11067,10 +11182,6 @@ namespace ts {
}
}
}
else {
error(typePredicateNode,
Diagnostics.A_type_predicate_is_only_allowed_in_return_type_position_for_functions_and_methods);
}
}
else {
checkSourceElement(node.type);
@ -13027,7 +13138,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 || isGetAccessorWithAnnotatatedSetAccessor(func) || signature.typePredicate) {
else if (func.type || isGetAccessorWithAnnotatatedSetAccessor(func) || returnType.flags & TypeFlags.PredicateType) {
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);
@ -14218,9 +14329,18 @@ namespace ts {
}
function checkTypePredicate(node: TypePredicateNode) {
if (!isInLegalTypePredicatePosition(node)) {
const { parameterName } = node;
if (parameterName.kind === SyntaxKind.Identifier && !isInLegalParameterTypePredicatePosition(node)) {
error(node, Diagnostics.A_type_predicate_is_only_allowed_in_return_type_position_for_functions_and_methods);
}
else if (parameterName.kind === SyntaxKind.ThisType) {
if (!isInLegalThisTypePredicatePosition(node)) {
error(node, Diagnostics.A_this_based_type_predicate_is_only_allowed_within_a_class_or_interface_s_members_get_accessors_or_return_type_positions_for_functions_and_methods);
}
else {
getTypeFromThisTypeNode(parameterName as ThisTypeNode);
}
}
}
function checkSourceElement(node: Node): void {

View file

@ -1647,6 +1647,14 @@
"category": "Error",
"code": 2517
},
"A 'this'-based type guard is not compatible with a parameter-based type guard.": {
"category": "Error",
"code": 2518
},
"A 'this'-based type predicate is only allowed within a class or interface's members, get accessors, or return type positions for functions and methods.": {
"category": "Error",
"code": 2519
},
"Duplicate identifier '{0}'. Compiler uses declaration '{1}' to support async functions.": {
"category": "Error",
"code": 2520

View file

@ -1963,11 +1963,7 @@ namespace ts {
function parseTypeReferenceOrTypePredicate(): TypeReferenceNode | TypePredicateNode {
const typeName = parseEntityName(/*allowReservedWords*/ false, Diagnostics.Type_expected);
if (typeName.kind === SyntaxKind.Identifier && token === SyntaxKind.IsKeyword && !scanner.hasPrecedingLineBreak()) {
nextToken();
const node = <TypePredicateNode>createNode(SyntaxKind.TypePredicate, typeName.pos);
node.parameterName = <Identifier>typeName;
node.type = parseType();
return finishNode(node);
return parseTypePredicate(typeName as Identifier);
}
const node = <TypeReferenceNode>createNode(SyntaxKind.TypeReference, typeName.pos);
node.typeName = typeName;
@ -1977,8 +1973,16 @@ namespace ts {
return finishNode(node);
}
function parseThisTypeNode(): TypeNode {
const node = <TypeNode>createNode(SyntaxKind.ThisType);
function parseTypePredicate(lhs: Identifier | ThisTypeNode): TypePredicateNode {
nextToken();
const node = createNode(SyntaxKind.TypePredicate, lhs.pos) as TypePredicateNode;
node.parameterName = lhs;
node.type = parseType();
return finishNode(node);
}
function parseThisTypeNode(): ThisTypeNode {
const node = createNode(SyntaxKind.ThisType) as ThisTypeNode;
nextToken();
return finishNode(node);
}
@ -2424,8 +2428,15 @@ namespace ts {
return parseStringLiteralTypeNode();
case SyntaxKind.VoidKeyword:
return parseTokenNode<TypeNode>();
case SyntaxKind.ThisKeyword:
return parseThisTypeNode();
case SyntaxKind.ThisKeyword: {
const thisKeyword = parseThisTypeNode();
if (token === SyntaxKind.IsKeyword && !scanner.hasPrecedingLineBreak()) {
return parseTypePredicate(thisKeyword);
}
else {
return thisKeyword;
}
}
case SyntaxKind.TypeOfKeyword:
return parseTypeQuery();
case SyntaxKind.OpenBraceToken:

View file

@ -733,11 +733,15 @@ namespace ts {
// @kind(SyntaxKind.StringKeyword)
// @kind(SyntaxKind.SymbolKeyword)
// @kind(SyntaxKind.VoidKeyword)
// @kind(SyntaxKind.ThisType)
export interface TypeNode extends Node {
_typeNodeBrand: any;
}
// @kind(SyntaxKind.ThisType)
export interface ThisTypeNode extends TypeNode {
_thisTypeNodeBrand: any;
}
export interface FunctionOrConstructorTypeNode extends TypeNode, SignatureDeclaration {
_functionOrConstructorTypeNodeBrand: any;
}
@ -756,7 +760,7 @@ namespace ts {
// @kind(SyntaxKind.TypePredicate)
export interface TypePredicateNode extends TypeNode {
parameterName: Identifier;
parameterName: Identifier | ThisTypeNode;
type: TypeNode;
}
@ -1820,10 +1824,25 @@ namespace ts {
CannotBeNamed
}
export const enum TypePredicateKind {
This,
Identifier
}
export interface TypePredicate {
kind: TypePredicateKind;
type: Type;
}
// @kind (TypePredicateKind.This)
export interface ThisTypePredicate extends TypePredicate {
_thisTypePredicateBrand: any;
}
// @kind (TypePredicateKind.Identifier)
export interface IdentifierTypePredicate extends TypePredicate {
parameterName: string;
parameterIndex: number;
type: Type;
}
/* @internal */
@ -2091,6 +2110,7 @@ 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,
@ -2102,7 +2122,7 @@ namespace ts {
UnionOrIntersection = Union | Intersection,
StructuredType = ObjectType | Union | Intersection,
/* @internal */
RequiresWidening = ContainsUndefinedOrNull | ContainsObjectLiteral,
RequiresWidening = ContainsUndefinedOrNull | ContainsObjectLiteral | PredicateType,
/* @internal */
PropagatingFlags = ContainsUndefinedOrNull | ContainsObjectLiteral | ContainsAnyFunctionType
}
@ -2123,6 +2143,11 @@ 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
@ -2239,7 +2264,6 @@ namespace ts {
declaration: SignatureDeclaration; // Originating declaration
typeParameters: TypeParameter[]; // Type parameters (undefined if non-generic)
parameters: Symbol[]; // Parameters
typePredicate?: TypePredicate; // Type predicate
/* @internal */
resolvedReturnType: Type; // Resolved return type
/* @internal */

View file

@ -693,6 +693,10 @@ namespace ts {
return node && node.kind === SyntaxKind.MethodDeclaration && node.parent.kind === SyntaxKind.ObjectLiteralExpression;
}
export function isIdentifierTypePredicate(predicate: TypePredicate): predicate is IdentifierTypePredicate {
return predicate && predicate.kind === TypePredicateKind.Identifier;
}
export function getContainingFunction(node: Node): FunctionLikeDeclaration {
while (true) {
node = node.parent;

View file

@ -4,7 +4,7 @@ var obj: Object;
>Object : Object
if (ArrayBuffer.isView(obj)) {
>ArrayBuffer.isView(obj) : boolean
>ArrayBuffer.isView(obj) : arg is ArrayBufferView
>ArrayBuffer.isView : (arg: any) => arg is ArrayBufferView
>ArrayBuffer : ArrayBufferConstructor
>isView : (arg: any) => arg is ArrayBufferView

View file

@ -4,7 +4,7 @@ var maybeArray: number | number[];
if (Array.isArray(maybeArray)) {
>Array.isArray(maybeArray) : boolean
>Array.isArray(maybeArray) : arg is any[]
>Array.isArray : (arg: any) => arg is any[]
>Array : ArrayConstructor
>isArray : (arg: any) => arg is any[]

View file

@ -31,7 +31,7 @@ function f(foo: T) {
>T : ("a" | "b")[] | "a" | "b"
if (isS(foo)) {
>isS(foo) : boolean
>isS(foo) : t is "a" | "b"
>isS : (t: ("a" | "b")[] | "a" | "b") => t is "a" | "b"
>foo : ("a" | "b")[] | "a" | "b"

View file

@ -1,10 +1,8 @@
tests/cases/conformance/types/stringLiteral/stringLiteralTypesAsTags01.ts(18,10): error TS2382: Specialized overload signature is not assignable to any non-specialized signature.
tests/cases/conformance/types/stringLiteral/stringLiteralTypesAsTags01.ts(19,10): error TS2382: Specialized overload signature is not assignable to any non-specialized signature.
tests/cases/conformance/types/stringLiteral/stringLiteralTypesAsTags01.ts(20,10): error TS2394: Overload signature is not compatible with function implementation.
tests/cases/conformance/types/stringLiteral/stringLiteralTypesAsTags01.ts(22,21): error TS2304: Cannot find name 'is'.
==== tests/cases/conformance/types/stringLiteral/stringLiteralTypesAsTags01.ts (4 errors) ====
==== tests/cases/conformance/types/stringLiteral/stringLiteralTypesAsTags01.ts (2 errors) ====
type Kind = "A" | "B"
@ -23,11 +21,7 @@ tests/cases/conformance/types/stringLiteral/stringLiteralTypesAsTags01.ts(22,21)
}
function hasKind(entity: Entity, kind: "A"): entity is A;
~~~~~~~
!!! error TS2382: Specialized overload signature is not assignable to any non-specialized signature.
function hasKind(entity: Entity, kind: "B"): entity is B;
~~~~~~~
!!! error TS2382: Specialized overload signature is not assignable to any non-specialized signature.
function hasKind(entity: Entity, kind: Kind): entity is Entity;
~~~~~~~
!!! error TS2394: Overload signature is not compatible with function implementation.

View file

@ -54,7 +54,7 @@ var b: B;
// Basic
if (isC(a)) {
>isC(a) : boolean
>isC(a) : p1 is C
>isC : (p1: any) => p1 is C
>a : A
@ -70,7 +70,7 @@ var subType: C;
>C : C
if(isA(subType)) {
>isA(subType) : boolean
>isA(subType) : p1 is A
>isA : (p1: any) => p1 is A
>subType : C
@ -87,7 +87,7 @@ var union: A | B;
>B : B
if(isA(union)) {
>isA(union) : boolean
>isA(union) : p1 is A
>isA : (p1: any) => p1 is A
>union : A | B
@ -118,7 +118,7 @@ declare function isC_multipleParams(p1, p2): p1 is C;
>C : C
if (isC_multipleParams(a, 0)) {
>isC_multipleParams(a, 0) : boolean
>isC_multipleParams(a, 0) : p1 is C
>isC_multipleParams : (p1: any, p2: any) => p1 is C
>a : A
>0 : number
@ -197,7 +197,7 @@ declare function acceptingBoolean(a: boolean);
acceptingBoolean(isA(a));
>acceptingBoolean(isA(a)) : any
>acceptingBoolean : (a: boolean) => any
>isA(a) : boolean
>isA(a) : p1 is A
>isA : (p1: any) => p1 is A
>a : A
@ -223,8 +223,8 @@ let union2: C | B;
let union3: boolean | B = isA(union2) || union2;
>union3 : boolean | B
>B : B
>isA(union2) || union2 : boolean | B
>isA(union2) : boolean
>isA(union2) || union2 : p1 is A | B
>isA(union2) : p1 is A
>isA : (p1: any) => p1 is A
>union2 : C | B
>union2 : B

View file

@ -1,4 +1,4 @@
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(15,12): error TS2322: Type 'string' is not assignable to type 'boolean'.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(15,12): error TS2322: Type 'string' is not assignable to type 'x is A'.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(22,33): error TS2304: Cannot find name 'x'.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(26,33): error TS1225: Cannot find parameter 'x'.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(30,10): error TS2391: Function implementation is missing or not immediately following the declaration.
@ -16,6 +16,7 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(70,7):
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(75,46): error TS2345: Argument of type '(p1: any) => p1 is C' is not assignable to parameter of type '(p1: any) => p1 is B'.
Type predicate 'p1 is C' is not assignable to 'p1 is B'.
Type 'C' is not assignable to type 'B'.
Property 'propB' is missing in type 'C'.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(79,1): error TS2322: Type '(p1: any, p2: any) => boolean' is not assignable to type '(p1: any, p2: any) => p1 is A'.
Signature '(p1: any, p2: any): boolean' must have a type predicate.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(85,1): error TS2322: Type '(p1: any, p2: any) => p2 is A' is not assignable to type '(p1: any, p2: any) => p1 is A'.
@ -25,7 +26,6 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(91,1):
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(96,9): error TS1228: A type predicate is only allowed in return type position for functions and methods.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(97,16): error TS1228: A type predicate is only allowed in return type position for functions and methods.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(98,20): error TS1228: A type predicate is only allowed in return type position for functions and methods.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(104,25): error TS1228: A type predicate is only allowed in return type position for functions and methods.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(105,16): error TS2322: Type 'boolean' is not assignable to type 'D'.
Property 'm1' is missing in type 'Boolean'.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(105,16): error TS2409: Return type of constructor signature must be assignable to the instance type of the class
@ -33,6 +33,7 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(107,20
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(110,20): error TS1228: A type predicate is only allowed in return type position for functions and methods.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(111,16): error TS2408: Setters cannot return a value.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(116,18): error TS1228: A type predicate is only allowed in return type position for functions and methods.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(120,22): error TS1225: Cannot find parameter 'p1'.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(120,22): error TS1228: A type predicate is only allowed in return type position for functions and methods.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(124,20): error TS1229: A type predicate cannot reference a rest parameter.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(129,34): error TS1230: A type predicate cannot reference element 'p1' in a binding pattern.
@ -57,7 +58,7 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(137,39
function hasANonBooleanReturnStatement(x): x is A {
return '';
~~
!!! error TS2322: Type 'string' is not assignable to type 'boolean'.
!!! error TS2322: Type 'string' is not assignable to type 'x is A'.
}
function hasTypeGuardTypeInsideTypeGuardType(x): x is x is A {
@ -149,6 +150,7 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(137,39
!!! error TS2345: Argument of type '(p1: any) => p1 is C' is not assignable to parameter of type '(p1: any) => p1 is B'.
!!! error TS2345: Type predicate 'p1 is C' is not assignable to 'p1 is B'.
!!! error TS2345: Type 'C' is not assignable to type 'B'.
!!! error TS2345: Property 'propB' is missing in type 'C'.
// Boolean not assignable to type guard
var assign1: (p1, p2) => p1 is A;
@ -193,8 +195,6 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(137,39
// Non-compatiable type predicate positions for signature declarations
class D {
constructor(p1: A): p1 is C {
~~~~~~~
!!! error TS1228: A type predicate is only allowed in return type position for functions and methods.
return true;
~~~~
!!! error TS2322: Type 'boolean' is not assignable to type 'D'.
@ -224,6 +224,8 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(137,39
interface I2 {
[index: number]: p1 is C;
~~
!!! error TS1225: Cannot find parameter 'p1'.
~~~~~~~
!!! error TS1228: A type predicate is only allowed in return type position for functions and methods.
}

View file

@ -100,7 +100,7 @@ let test1: boolean = funA(isB);
>isB : (p1: any) => p1 is B
if (funB(retC, a)) {
>funB(retC, a) : boolean
>funB(retC, a) : p2 is C
>funB : <T>(p1: (p1: any) => T, p2: any) => p2 is T
>retC : (x: any) => C
>a : A
@ -118,7 +118,7 @@ let test2: B = funC(isB);
>isB : (p1: any) => p1 is B
if (funD(isC, a)) {
>funD(isC, a) : boolean
>funD(isC, a) : p2 is C
>funD : <T>(p1: (p1: any) => p1 is T, p2: any) => p2 is T
>isC : (p1: any) => p1 is C
>a : A

View file

@ -0,0 +1,347 @@
//// [typeGuardFunctionOfFormThis.ts]
class RoyalGuard {
isLeader(): this is LeadGuard {
return this instanceof LeadGuard;
}
isFollower(): this is FollowerGuard {
return this instanceof FollowerGuard;
}
}
class LeadGuard extends RoyalGuard {
lead(): void {};
}
class FollowerGuard extends RoyalGuard {
follow(): void {};
}
let a: RoyalGuard = new FollowerGuard();
if (a.isLeader()) {
a.lead();
}
else if (a.isFollower()) {
a.follow();
}
interface GuardInterface extends RoyalGuard {}
let b: GuardInterface;
if (b.isLeader()) {
b.lead();
}
else if (b.isFollower()) {
b.follow();
}
if (((a.isLeader)())) {
a.lead();
}
else if (((a).isFollower())) {
a.follow();
}
if (((a["isLeader"])())) {
a.lead();
}
else if (((a)["isFollower"]())) {
a.follow();
}
var holder2 = {a};
if (holder2.a.isLeader()) {
holder2.a;
}
else {
holder2.a;
}
class ArrowGuard {
isElite = (): this is ArrowElite => {
return this instanceof ArrowElite;
}
isMedic = (): this is ArrowMedic => {
return this instanceof ArrowMedic;
}
}
class ArrowElite extends ArrowGuard {
defend(): void {}
}
class ArrowMedic extends ArrowGuard {
heal(): void {}
}
let guard = new ArrowGuard();
if (guard.isElite()) {
guard.defend();
}
else if (guard.isMedic()) {
guard.heal();
}
interface Supplies {
spoiled: boolean;
}
interface Sundries {
broken: boolean;
}
interface Crate<T> {
contents: T;
volume: number;
isSupplies(): this is Crate<Supplies>;
isSundries(): this is Crate<Sundries>;
}
let crate: Crate<{}>;
if (crate.isSundries()) {
crate.contents.broken = true;
}
else if (crate.isSupplies()) {
crate.contents.spoiled = true;
}
// Matching guards should be assignable
a.isFollower = b.isFollower;
a.isLeader = b.isLeader;
class MimicGuard {
isLeader(): this is MimicLeader { return this instanceof MimicLeader; };
isFollower(): this is MimicFollower { return this instanceof MimicFollower; };
}
class MimicLeader extends MimicGuard {
lead(): void {}
}
class MimicFollower extends MimicGuard {
follow(): void {}
}
let mimic = new MimicGuard();
a.isLeader = mimic.isLeader;
a.isFollower = mimic.isFollower;
if (mimic.isFollower()) {
mimic.follow();
mimic.isFollower = a.isFollower;
}
interface MimicGuardInterface {
isLeader(): this is LeadGuard;
isFollower(): this is FollowerGuard;
}
//// [typeGuardFunctionOfFormThis.js]
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var RoyalGuard = (function () {
function RoyalGuard() {
}
RoyalGuard.prototype.isLeader = function () {
return this instanceof LeadGuard;
};
RoyalGuard.prototype.isFollower = function () {
return this instanceof FollowerGuard;
};
return RoyalGuard;
}());
var LeadGuard = (function (_super) {
__extends(LeadGuard, _super);
function LeadGuard() {
_super.apply(this, arguments);
}
LeadGuard.prototype.lead = function () { };
;
return LeadGuard;
}(RoyalGuard));
var FollowerGuard = (function (_super) {
__extends(FollowerGuard, _super);
function FollowerGuard() {
_super.apply(this, arguments);
}
FollowerGuard.prototype.follow = function () { };
;
return FollowerGuard;
}(RoyalGuard));
var a = new FollowerGuard();
if (a.isLeader()) {
a.lead();
}
else if (a.isFollower()) {
a.follow();
}
var b;
if (b.isLeader()) {
b.lead();
}
else if (b.isFollower()) {
b.follow();
}
if (((a.isLeader)())) {
a.lead();
}
else if (((a).isFollower())) {
a.follow();
}
if (((a["isLeader"])())) {
a.lead();
}
else if (((a)["isFollower"]())) {
a.follow();
}
var holder2 = { a: a };
if (holder2.a.isLeader()) {
holder2.a;
}
else {
holder2.a;
}
var ArrowGuard = (function () {
function ArrowGuard() {
var _this = this;
this.isElite = function () {
return _this instanceof ArrowElite;
};
this.isMedic = function () {
return _this instanceof ArrowMedic;
};
}
return ArrowGuard;
}());
var ArrowElite = (function (_super) {
__extends(ArrowElite, _super);
function ArrowElite() {
_super.apply(this, arguments);
}
ArrowElite.prototype.defend = function () { };
return ArrowElite;
}(ArrowGuard));
var ArrowMedic = (function (_super) {
__extends(ArrowMedic, _super);
function ArrowMedic() {
_super.apply(this, arguments);
}
ArrowMedic.prototype.heal = function () { };
return ArrowMedic;
}(ArrowGuard));
var guard = new ArrowGuard();
if (guard.isElite()) {
guard.defend();
}
else if (guard.isMedic()) {
guard.heal();
}
var crate;
if (crate.isSundries()) {
crate.contents.broken = true;
}
else if (crate.isSupplies()) {
crate.contents.spoiled = true;
}
// Matching guards should be assignable
a.isFollower = b.isFollower;
a.isLeader = b.isLeader;
var MimicGuard = (function () {
function MimicGuard() {
}
MimicGuard.prototype.isLeader = function () { return this instanceof MimicLeader; };
;
MimicGuard.prototype.isFollower = function () { return this instanceof MimicFollower; };
;
return MimicGuard;
}());
var MimicLeader = (function (_super) {
__extends(MimicLeader, _super);
function MimicLeader() {
_super.apply(this, arguments);
}
MimicLeader.prototype.lead = function () { };
return MimicLeader;
}(MimicGuard));
var MimicFollower = (function (_super) {
__extends(MimicFollower, _super);
function MimicFollower() {
_super.apply(this, arguments);
}
MimicFollower.prototype.follow = function () { };
return MimicFollower;
}(MimicGuard));
var mimic = new MimicGuard();
a.isLeader = mimic.isLeader;
a.isFollower = mimic.isFollower;
if (mimic.isFollower()) {
mimic.follow();
mimic.isFollower = a.isFollower;
}
//// [typeGuardFunctionOfFormThis.d.ts]
declare class RoyalGuard {
isLeader(): this is LeadGuard;
isFollower(): this is FollowerGuard;
}
declare class LeadGuard extends RoyalGuard {
lead(): void;
}
declare class FollowerGuard extends RoyalGuard {
follow(): void;
}
declare let a: RoyalGuard;
interface GuardInterface extends RoyalGuard {
}
declare let b: GuardInterface;
declare var holder2: {
a: RoyalGuard;
};
declare class ArrowGuard {
isElite: () => this is ArrowElite;
isMedic: () => this is ArrowMedic;
}
declare class ArrowElite extends ArrowGuard {
defend(): void;
}
declare class ArrowMedic extends ArrowGuard {
heal(): void;
}
declare let guard: ArrowGuard;
interface Supplies {
spoiled: boolean;
}
interface Sundries {
broken: boolean;
}
interface Crate<T> {
contents: T;
volume: number;
isSupplies(): this is Crate<Supplies>;
isSundries(): this is Crate<Sundries>;
}
declare let crate: Crate<{}>;
declare class MimicGuard {
isLeader(): this is MimicLeader;
isFollower(): this is MimicFollower;
}
declare class MimicLeader extends MimicGuard {
lead(): void;
}
declare class MimicFollower extends MimicGuard {
follow(): void;
}
declare let mimic: MimicGuard;
interface MimicGuardInterface {
isLeader(): this is LeadGuard;
isFollower(): this is FollowerGuard;
}

View file

@ -0,0 +1,385 @@
=== tests/cases/conformance/expressions/typeGuards/typeGuardFunctionOfFormThis.ts ===
class RoyalGuard {
>RoyalGuard : Symbol(RoyalGuard, Decl(typeGuardFunctionOfFormThis.ts, 0, 0))
isLeader(): this is LeadGuard {
>isLeader : Symbol(isLeader, Decl(typeGuardFunctionOfFormThis.ts, 0, 18))
>LeadGuard : Symbol(LeadGuard, Decl(typeGuardFunctionOfFormThis.ts, 7, 1))
return this instanceof LeadGuard;
>this : Symbol(RoyalGuard, Decl(typeGuardFunctionOfFormThis.ts, 0, 0))
>LeadGuard : Symbol(LeadGuard, Decl(typeGuardFunctionOfFormThis.ts, 7, 1))
}
isFollower(): this is FollowerGuard {
>isFollower : Symbol(isFollower, Decl(typeGuardFunctionOfFormThis.ts, 3, 5))
>FollowerGuard : Symbol(FollowerGuard, Decl(typeGuardFunctionOfFormThis.ts, 11, 1))
return this instanceof FollowerGuard;
>this : Symbol(RoyalGuard, Decl(typeGuardFunctionOfFormThis.ts, 0, 0))
>FollowerGuard : Symbol(FollowerGuard, Decl(typeGuardFunctionOfFormThis.ts, 11, 1))
}
}
class LeadGuard extends RoyalGuard {
>LeadGuard : Symbol(LeadGuard, Decl(typeGuardFunctionOfFormThis.ts, 7, 1))
>RoyalGuard : Symbol(RoyalGuard, Decl(typeGuardFunctionOfFormThis.ts, 0, 0))
lead(): void {};
>lead : Symbol(lead, Decl(typeGuardFunctionOfFormThis.ts, 9, 36))
}
class FollowerGuard extends RoyalGuard {
>FollowerGuard : Symbol(FollowerGuard, Decl(typeGuardFunctionOfFormThis.ts, 11, 1))
>RoyalGuard : Symbol(RoyalGuard, Decl(typeGuardFunctionOfFormThis.ts, 0, 0))
follow(): void {};
>follow : Symbol(follow, Decl(typeGuardFunctionOfFormThis.ts, 13, 40))
}
let a: RoyalGuard = new FollowerGuard();
>a : Symbol(a, Decl(typeGuardFunctionOfFormThis.ts, 17, 3))
>RoyalGuard : Symbol(RoyalGuard, Decl(typeGuardFunctionOfFormThis.ts, 0, 0))
>FollowerGuard : Symbol(FollowerGuard, Decl(typeGuardFunctionOfFormThis.ts, 11, 1))
if (a.isLeader()) {
>a.isLeader : Symbol(RoyalGuard.isLeader, Decl(typeGuardFunctionOfFormThis.ts, 0, 18))
>a : Symbol(a, Decl(typeGuardFunctionOfFormThis.ts, 17, 3))
>isLeader : Symbol(RoyalGuard.isLeader, Decl(typeGuardFunctionOfFormThis.ts, 0, 18))
a.lead();
>a.lead : Symbol(LeadGuard.lead, Decl(typeGuardFunctionOfFormThis.ts, 9, 36))
>a : Symbol(a, Decl(typeGuardFunctionOfFormThis.ts, 17, 3))
>lead : Symbol(LeadGuard.lead, Decl(typeGuardFunctionOfFormThis.ts, 9, 36))
}
else if (a.isFollower()) {
>a.isFollower : Symbol(RoyalGuard.isFollower, Decl(typeGuardFunctionOfFormThis.ts, 3, 5))
>a : Symbol(a, Decl(typeGuardFunctionOfFormThis.ts, 17, 3))
>isFollower : Symbol(RoyalGuard.isFollower, Decl(typeGuardFunctionOfFormThis.ts, 3, 5))
a.follow();
>a.follow : Symbol(FollowerGuard.follow, Decl(typeGuardFunctionOfFormThis.ts, 13, 40))
>a : Symbol(a, Decl(typeGuardFunctionOfFormThis.ts, 17, 3))
>follow : Symbol(FollowerGuard.follow, Decl(typeGuardFunctionOfFormThis.ts, 13, 40))
}
interface GuardInterface extends RoyalGuard {}
>GuardInterface : Symbol(GuardInterface, Decl(typeGuardFunctionOfFormThis.ts, 23, 1))
>RoyalGuard : Symbol(RoyalGuard, Decl(typeGuardFunctionOfFormThis.ts, 0, 0))
let b: GuardInterface;
>b : Symbol(b, Decl(typeGuardFunctionOfFormThis.ts, 27, 3))
>GuardInterface : Symbol(GuardInterface, Decl(typeGuardFunctionOfFormThis.ts, 23, 1))
if (b.isLeader()) {
>b.isLeader : Symbol(RoyalGuard.isLeader, Decl(typeGuardFunctionOfFormThis.ts, 0, 18))
>b : Symbol(b, Decl(typeGuardFunctionOfFormThis.ts, 27, 3))
>isLeader : Symbol(RoyalGuard.isLeader, Decl(typeGuardFunctionOfFormThis.ts, 0, 18))
b.lead();
>b.lead : Symbol(LeadGuard.lead, Decl(typeGuardFunctionOfFormThis.ts, 9, 36))
>b : Symbol(b, Decl(typeGuardFunctionOfFormThis.ts, 27, 3))
>lead : Symbol(LeadGuard.lead, Decl(typeGuardFunctionOfFormThis.ts, 9, 36))
}
else if (b.isFollower()) {
>b.isFollower : Symbol(RoyalGuard.isFollower, Decl(typeGuardFunctionOfFormThis.ts, 3, 5))
>b : Symbol(b, Decl(typeGuardFunctionOfFormThis.ts, 27, 3))
>isFollower : Symbol(RoyalGuard.isFollower, Decl(typeGuardFunctionOfFormThis.ts, 3, 5))
b.follow();
>b.follow : Symbol(FollowerGuard.follow, Decl(typeGuardFunctionOfFormThis.ts, 13, 40))
>b : Symbol(b, Decl(typeGuardFunctionOfFormThis.ts, 27, 3))
>follow : Symbol(FollowerGuard.follow, Decl(typeGuardFunctionOfFormThis.ts, 13, 40))
}
if (((a.isLeader)())) {
>a.isLeader : Symbol(RoyalGuard.isLeader, Decl(typeGuardFunctionOfFormThis.ts, 0, 18))
>a : Symbol(a, Decl(typeGuardFunctionOfFormThis.ts, 17, 3))
>isLeader : Symbol(RoyalGuard.isLeader, Decl(typeGuardFunctionOfFormThis.ts, 0, 18))
a.lead();
>a.lead : Symbol(LeadGuard.lead, Decl(typeGuardFunctionOfFormThis.ts, 9, 36))
>a : Symbol(a, Decl(typeGuardFunctionOfFormThis.ts, 17, 3))
>lead : Symbol(LeadGuard.lead, Decl(typeGuardFunctionOfFormThis.ts, 9, 36))
}
else if (((a).isFollower())) {
>(a).isFollower : Symbol(RoyalGuard.isFollower, Decl(typeGuardFunctionOfFormThis.ts, 3, 5))
>a : Symbol(a, Decl(typeGuardFunctionOfFormThis.ts, 17, 3))
>isFollower : Symbol(RoyalGuard.isFollower, Decl(typeGuardFunctionOfFormThis.ts, 3, 5))
a.follow();
>a.follow : Symbol(FollowerGuard.follow, Decl(typeGuardFunctionOfFormThis.ts, 13, 40))
>a : Symbol(a, Decl(typeGuardFunctionOfFormThis.ts, 17, 3))
>follow : Symbol(FollowerGuard.follow, Decl(typeGuardFunctionOfFormThis.ts, 13, 40))
}
if (((a["isLeader"])())) {
>a : Symbol(a, Decl(typeGuardFunctionOfFormThis.ts, 17, 3))
>"isLeader" : Symbol(RoyalGuard.isLeader, Decl(typeGuardFunctionOfFormThis.ts, 0, 18))
a.lead();
>a.lead : Symbol(LeadGuard.lead, Decl(typeGuardFunctionOfFormThis.ts, 9, 36))
>a : Symbol(a, Decl(typeGuardFunctionOfFormThis.ts, 17, 3))
>lead : Symbol(LeadGuard.lead, Decl(typeGuardFunctionOfFormThis.ts, 9, 36))
}
else if (((a)["isFollower"]())) {
>a : Symbol(a, Decl(typeGuardFunctionOfFormThis.ts, 17, 3))
>"isFollower" : Symbol(RoyalGuard.isFollower, Decl(typeGuardFunctionOfFormThis.ts, 3, 5))
a.follow();
>a.follow : Symbol(FollowerGuard.follow, Decl(typeGuardFunctionOfFormThis.ts, 13, 40))
>a : Symbol(a, Decl(typeGuardFunctionOfFormThis.ts, 17, 3))
>follow : Symbol(FollowerGuard.follow, Decl(typeGuardFunctionOfFormThis.ts, 13, 40))
}
var holder2 = {a};
>holder2 : Symbol(holder2, Decl(typeGuardFunctionOfFormThis.ts, 49, 3))
>a : Symbol(a, Decl(typeGuardFunctionOfFormThis.ts, 49, 15))
if (holder2.a.isLeader()) {
>holder2.a.isLeader : Symbol(RoyalGuard.isLeader, Decl(typeGuardFunctionOfFormThis.ts, 0, 18))
>holder2.a : Symbol(a, Decl(typeGuardFunctionOfFormThis.ts, 49, 15))
>holder2 : Symbol(holder2, Decl(typeGuardFunctionOfFormThis.ts, 49, 3))
>a : Symbol(a, Decl(typeGuardFunctionOfFormThis.ts, 49, 15))
>isLeader : Symbol(RoyalGuard.isLeader, Decl(typeGuardFunctionOfFormThis.ts, 0, 18))
holder2.a;
>holder2.a : Symbol(a, Decl(typeGuardFunctionOfFormThis.ts, 49, 15))
>holder2 : Symbol(holder2, Decl(typeGuardFunctionOfFormThis.ts, 49, 3))
>a : Symbol(a, Decl(typeGuardFunctionOfFormThis.ts, 49, 15))
}
else {
holder2.a;
>holder2.a : Symbol(a, Decl(typeGuardFunctionOfFormThis.ts, 49, 15))
>holder2 : Symbol(holder2, Decl(typeGuardFunctionOfFormThis.ts, 49, 3))
>a : Symbol(a, Decl(typeGuardFunctionOfFormThis.ts, 49, 15))
}
class ArrowGuard {
>ArrowGuard : Symbol(ArrowGuard, Decl(typeGuardFunctionOfFormThis.ts, 56, 1))
isElite = (): this is ArrowElite => {
>isElite : Symbol(isElite, Decl(typeGuardFunctionOfFormThis.ts, 58, 18))
>ArrowElite : Symbol(ArrowElite, Decl(typeGuardFunctionOfFormThis.ts, 65, 1))
return this instanceof ArrowElite;
>this : Symbol(ArrowGuard, Decl(typeGuardFunctionOfFormThis.ts, 56, 1))
>ArrowElite : Symbol(ArrowElite, Decl(typeGuardFunctionOfFormThis.ts, 65, 1))
}
isMedic = (): this is ArrowMedic => {
>isMedic : Symbol(isMedic, Decl(typeGuardFunctionOfFormThis.ts, 61, 5))
>ArrowMedic : Symbol(ArrowMedic, Decl(typeGuardFunctionOfFormThis.ts, 69, 1))
return this instanceof ArrowMedic;
>this : Symbol(ArrowGuard, Decl(typeGuardFunctionOfFormThis.ts, 56, 1))
>ArrowMedic : Symbol(ArrowMedic, Decl(typeGuardFunctionOfFormThis.ts, 69, 1))
}
}
class ArrowElite extends ArrowGuard {
>ArrowElite : Symbol(ArrowElite, Decl(typeGuardFunctionOfFormThis.ts, 65, 1))
>ArrowGuard : Symbol(ArrowGuard, Decl(typeGuardFunctionOfFormThis.ts, 56, 1))
defend(): void {}
>defend : Symbol(defend, Decl(typeGuardFunctionOfFormThis.ts, 67, 37))
}
class ArrowMedic extends ArrowGuard {
>ArrowMedic : Symbol(ArrowMedic, Decl(typeGuardFunctionOfFormThis.ts, 69, 1))
>ArrowGuard : Symbol(ArrowGuard, Decl(typeGuardFunctionOfFormThis.ts, 56, 1))
heal(): void {}
>heal : Symbol(heal, Decl(typeGuardFunctionOfFormThis.ts, 71, 37))
}
let guard = new ArrowGuard();
>guard : Symbol(guard, Decl(typeGuardFunctionOfFormThis.ts, 75, 3))
>ArrowGuard : Symbol(ArrowGuard, Decl(typeGuardFunctionOfFormThis.ts, 56, 1))
if (guard.isElite()) {
>guard.isElite : Symbol(ArrowGuard.isElite, Decl(typeGuardFunctionOfFormThis.ts, 58, 18))
>guard : Symbol(guard, Decl(typeGuardFunctionOfFormThis.ts, 75, 3))
>isElite : Symbol(ArrowGuard.isElite, Decl(typeGuardFunctionOfFormThis.ts, 58, 18))
guard.defend();
>guard.defend : Symbol(ArrowElite.defend, Decl(typeGuardFunctionOfFormThis.ts, 67, 37))
>guard : Symbol(guard, Decl(typeGuardFunctionOfFormThis.ts, 75, 3))
>defend : Symbol(ArrowElite.defend, Decl(typeGuardFunctionOfFormThis.ts, 67, 37))
}
else if (guard.isMedic()) {
>guard.isMedic : Symbol(ArrowGuard.isMedic, Decl(typeGuardFunctionOfFormThis.ts, 61, 5))
>guard : Symbol(guard, Decl(typeGuardFunctionOfFormThis.ts, 75, 3))
>isMedic : Symbol(ArrowGuard.isMedic, Decl(typeGuardFunctionOfFormThis.ts, 61, 5))
guard.heal();
>guard.heal : Symbol(ArrowMedic.heal, Decl(typeGuardFunctionOfFormThis.ts, 71, 37))
>guard : Symbol(guard, Decl(typeGuardFunctionOfFormThis.ts, 75, 3))
>heal : Symbol(ArrowMedic.heal, Decl(typeGuardFunctionOfFormThis.ts, 71, 37))
}
interface Supplies {
>Supplies : Symbol(Supplies, Decl(typeGuardFunctionOfFormThis.ts, 81, 1))
spoiled: boolean;
>spoiled : Symbol(spoiled, Decl(typeGuardFunctionOfFormThis.ts, 83, 20))
}
interface Sundries {
>Sundries : Symbol(Sundries, Decl(typeGuardFunctionOfFormThis.ts, 85, 1))
broken: boolean;
>broken : Symbol(broken, Decl(typeGuardFunctionOfFormThis.ts, 87, 20))
}
interface Crate<T> {
>Crate : Symbol(Crate, Decl(typeGuardFunctionOfFormThis.ts, 89, 1))
>T : Symbol(T, Decl(typeGuardFunctionOfFormThis.ts, 91, 16))
contents: T;
>contents : Symbol(contents, Decl(typeGuardFunctionOfFormThis.ts, 91, 20))
>T : Symbol(T, Decl(typeGuardFunctionOfFormThis.ts, 91, 16))
volume: number;
>volume : Symbol(volume, Decl(typeGuardFunctionOfFormThis.ts, 92, 16))
isSupplies(): this is Crate<Supplies>;
>isSupplies : Symbol(isSupplies, Decl(typeGuardFunctionOfFormThis.ts, 93, 19))
>Crate : Symbol(Crate, Decl(typeGuardFunctionOfFormThis.ts, 89, 1))
>Supplies : Symbol(Supplies, Decl(typeGuardFunctionOfFormThis.ts, 81, 1))
isSundries(): this is Crate<Sundries>;
>isSundries : Symbol(isSundries, Decl(typeGuardFunctionOfFormThis.ts, 94, 42))
>Crate : Symbol(Crate, Decl(typeGuardFunctionOfFormThis.ts, 89, 1))
>Sundries : Symbol(Sundries, Decl(typeGuardFunctionOfFormThis.ts, 85, 1))
}
let crate: Crate<{}>;
>crate : Symbol(crate, Decl(typeGuardFunctionOfFormThis.ts, 98, 3))
>Crate : Symbol(Crate, Decl(typeGuardFunctionOfFormThis.ts, 89, 1))
if (crate.isSundries()) {
>crate.isSundries : Symbol(Crate.isSundries, Decl(typeGuardFunctionOfFormThis.ts, 94, 42))
>crate : Symbol(crate, Decl(typeGuardFunctionOfFormThis.ts, 98, 3))
>isSundries : Symbol(Crate.isSundries, Decl(typeGuardFunctionOfFormThis.ts, 94, 42))
crate.contents.broken = true;
>crate.contents.broken : Symbol(Sundries.broken, Decl(typeGuardFunctionOfFormThis.ts, 87, 20))
>crate.contents : Symbol(Crate.contents, Decl(typeGuardFunctionOfFormThis.ts, 91, 20))
>crate : Symbol(crate, Decl(typeGuardFunctionOfFormThis.ts, 98, 3))
>contents : Symbol(Crate.contents, Decl(typeGuardFunctionOfFormThis.ts, 91, 20))
>broken : Symbol(Sundries.broken, Decl(typeGuardFunctionOfFormThis.ts, 87, 20))
}
else if (crate.isSupplies()) {
>crate.isSupplies : Symbol(Crate.isSupplies, Decl(typeGuardFunctionOfFormThis.ts, 93, 19))
>crate : Symbol(crate, Decl(typeGuardFunctionOfFormThis.ts, 98, 3))
>isSupplies : Symbol(Crate.isSupplies, Decl(typeGuardFunctionOfFormThis.ts, 93, 19))
crate.contents.spoiled = true;
>crate.contents.spoiled : Symbol(Supplies.spoiled, Decl(typeGuardFunctionOfFormThis.ts, 83, 20))
>crate.contents : Symbol(Crate.contents, Decl(typeGuardFunctionOfFormThis.ts, 91, 20))
>crate : Symbol(crate, Decl(typeGuardFunctionOfFormThis.ts, 98, 3))
>contents : Symbol(Crate.contents, Decl(typeGuardFunctionOfFormThis.ts, 91, 20))
>spoiled : Symbol(Supplies.spoiled, Decl(typeGuardFunctionOfFormThis.ts, 83, 20))
}
// Matching guards should be assignable
a.isFollower = b.isFollower;
>a.isFollower : Symbol(RoyalGuard.isFollower, Decl(typeGuardFunctionOfFormThis.ts, 3, 5))
>a : Symbol(a, Decl(typeGuardFunctionOfFormThis.ts, 17, 3))
>isFollower : Symbol(RoyalGuard.isFollower, Decl(typeGuardFunctionOfFormThis.ts, 3, 5))
>b.isFollower : Symbol(RoyalGuard.isFollower, Decl(typeGuardFunctionOfFormThis.ts, 3, 5))
>b : Symbol(b, Decl(typeGuardFunctionOfFormThis.ts, 27, 3))
>isFollower : Symbol(RoyalGuard.isFollower, Decl(typeGuardFunctionOfFormThis.ts, 3, 5))
a.isLeader = b.isLeader;
>a.isLeader : Symbol(RoyalGuard.isLeader, Decl(typeGuardFunctionOfFormThis.ts, 0, 18))
>a : Symbol(a, Decl(typeGuardFunctionOfFormThis.ts, 17, 3))
>isLeader : Symbol(RoyalGuard.isLeader, Decl(typeGuardFunctionOfFormThis.ts, 0, 18))
>b.isLeader : Symbol(RoyalGuard.isLeader, Decl(typeGuardFunctionOfFormThis.ts, 0, 18))
>b : Symbol(b, Decl(typeGuardFunctionOfFormThis.ts, 27, 3))
>isLeader : Symbol(RoyalGuard.isLeader, Decl(typeGuardFunctionOfFormThis.ts, 0, 18))
class MimicGuard {
>MimicGuard : Symbol(MimicGuard, Decl(typeGuardFunctionOfFormThis.ts, 110, 24))
isLeader(): this is MimicLeader { return this instanceof MimicLeader; };
>isLeader : Symbol(isLeader, Decl(typeGuardFunctionOfFormThis.ts, 112, 18))
>MimicLeader : Symbol(MimicLeader, Decl(typeGuardFunctionOfFormThis.ts, 115, 1))
>this : Symbol(MimicGuard, Decl(typeGuardFunctionOfFormThis.ts, 110, 24))
>MimicLeader : Symbol(MimicLeader, Decl(typeGuardFunctionOfFormThis.ts, 115, 1))
isFollower(): this is MimicFollower { return this instanceof MimicFollower; };
>isFollower : Symbol(isFollower, Decl(typeGuardFunctionOfFormThis.ts, 113, 76))
>MimicFollower : Symbol(MimicFollower, Decl(typeGuardFunctionOfFormThis.ts, 119, 1))
>this : Symbol(MimicGuard, Decl(typeGuardFunctionOfFormThis.ts, 110, 24))
>MimicFollower : Symbol(MimicFollower, Decl(typeGuardFunctionOfFormThis.ts, 119, 1))
}
class MimicLeader extends MimicGuard {
>MimicLeader : Symbol(MimicLeader, Decl(typeGuardFunctionOfFormThis.ts, 115, 1))
>MimicGuard : Symbol(MimicGuard, Decl(typeGuardFunctionOfFormThis.ts, 110, 24))
lead(): void {}
>lead : Symbol(lead, Decl(typeGuardFunctionOfFormThis.ts, 117, 38))
}
class MimicFollower extends MimicGuard {
>MimicFollower : Symbol(MimicFollower, Decl(typeGuardFunctionOfFormThis.ts, 119, 1))
>MimicGuard : Symbol(MimicGuard, Decl(typeGuardFunctionOfFormThis.ts, 110, 24))
follow(): void {}
>follow : Symbol(follow, Decl(typeGuardFunctionOfFormThis.ts, 121, 40))
}
let mimic = new MimicGuard();
>mimic : Symbol(mimic, Decl(typeGuardFunctionOfFormThis.ts, 125, 3))
>MimicGuard : Symbol(MimicGuard, Decl(typeGuardFunctionOfFormThis.ts, 110, 24))
a.isLeader = mimic.isLeader;
>a.isLeader : Symbol(RoyalGuard.isLeader, Decl(typeGuardFunctionOfFormThis.ts, 0, 18))
>a : Symbol(a, Decl(typeGuardFunctionOfFormThis.ts, 17, 3))
>isLeader : Symbol(RoyalGuard.isLeader, Decl(typeGuardFunctionOfFormThis.ts, 0, 18))
>mimic.isLeader : Symbol(MimicGuard.isLeader, Decl(typeGuardFunctionOfFormThis.ts, 112, 18))
>mimic : Symbol(mimic, Decl(typeGuardFunctionOfFormThis.ts, 125, 3))
>isLeader : Symbol(MimicGuard.isLeader, Decl(typeGuardFunctionOfFormThis.ts, 112, 18))
a.isFollower = mimic.isFollower;
>a.isFollower : Symbol(RoyalGuard.isFollower, Decl(typeGuardFunctionOfFormThis.ts, 3, 5))
>a : Symbol(a, Decl(typeGuardFunctionOfFormThis.ts, 17, 3))
>isFollower : Symbol(RoyalGuard.isFollower, Decl(typeGuardFunctionOfFormThis.ts, 3, 5))
>mimic.isFollower : Symbol(MimicGuard.isFollower, Decl(typeGuardFunctionOfFormThis.ts, 113, 76))
>mimic : Symbol(mimic, Decl(typeGuardFunctionOfFormThis.ts, 125, 3))
>isFollower : Symbol(MimicGuard.isFollower, Decl(typeGuardFunctionOfFormThis.ts, 113, 76))
if (mimic.isFollower()) {
>mimic.isFollower : Symbol(MimicGuard.isFollower, Decl(typeGuardFunctionOfFormThis.ts, 113, 76))
>mimic : Symbol(mimic, Decl(typeGuardFunctionOfFormThis.ts, 125, 3))
>isFollower : Symbol(MimicGuard.isFollower, Decl(typeGuardFunctionOfFormThis.ts, 113, 76))
mimic.follow();
>mimic.follow : Symbol(MimicFollower.follow, Decl(typeGuardFunctionOfFormThis.ts, 121, 40))
>mimic : Symbol(mimic, Decl(typeGuardFunctionOfFormThis.ts, 125, 3))
>follow : Symbol(MimicFollower.follow, Decl(typeGuardFunctionOfFormThis.ts, 121, 40))
mimic.isFollower = a.isFollower;
>mimic.isFollower : Symbol(MimicGuard.isFollower, Decl(typeGuardFunctionOfFormThis.ts, 113, 76))
>mimic : Symbol(mimic, Decl(typeGuardFunctionOfFormThis.ts, 125, 3))
>isFollower : Symbol(MimicGuard.isFollower, Decl(typeGuardFunctionOfFormThis.ts, 113, 76))
>a.isFollower : Symbol(RoyalGuard.isFollower, Decl(typeGuardFunctionOfFormThis.ts, 3, 5))
>a : Symbol(a, Decl(typeGuardFunctionOfFormThis.ts, 17, 3))
>isFollower : Symbol(RoyalGuard.isFollower, Decl(typeGuardFunctionOfFormThis.ts, 3, 5))
}
interface MimicGuardInterface {
>MimicGuardInterface : Symbol(MimicGuardInterface, Decl(typeGuardFunctionOfFormThis.ts, 133, 1))
isLeader(): this is LeadGuard;
>isLeader : Symbol(isLeader, Decl(typeGuardFunctionOfFormThis.ts, 136, 31))
>LeadGuard : Symbol(LeadGuard, Decl(typeGuardFunctionOfFormThis.ts, 7, 1))
isFollower(): this is FollowerGuard;
>isFollower : Symbol(isFollower, Decl(typeGuardFunctionOfFormThis.ts, 137, 34))
>FollowerGuard : Symbol(FollowerGuard, Decl(typeGuardFunctionOfFormThis.ts, 11, 1))
}

View file

@ -0,0 +1,441 @@
=== tests/cases/conformance/expressions/typeGuards/typeGuardFunctionOfFormThis.ts ===
class RoyalGuard {
>RoyalGuard : RoyalGuard
isLeader(): this is LeadGuard {
>isLeader : () => this is LeadGuard
>LeadGuard : LeadGuard
return this instanceof LeadGuard;
>this instanceof LeadGuard : boolean
>this : this
>LeadGuard : typeof LeadGuard
}
isFollower(): this is FollowerGuard {
>isFollower : () => this is FollowerGuard
>FollowerGuard : FollowerGuard
return this instanceof FollowerGuard;
>this instanceof FollowerGuard : boolean
>this : this
>FollowerGuard : typeof FollowerGuard
}
}
class LeadGuard extends RoyalGuard {
>LeadGuard : LeadGuard
>RoyalGuard : RoyalGuard
lead(): void {};
>lead : () => void
}
class FollowerGuard extends RoyalGuard {
>FollowerGuard : FollowerGuard
>RoyalGuard : RoyalGuard
follow(): void {};
>follow : () => void
}
let a: RoyalGuard = new FollowerGuard();
>a : RoyalGuard
>RoyalGuard : RoyalGuard
>new FollowerGuard() : FollowerGuard
>FollowerGuard : typeof FollowerGuard
if (a.isLeader()) {
>a.isLeader() : this is LeadGuard
>a.isLeader : () => this is LeadGuard
>a : RoyalGuard
>isLeader : () => this is LeadGuard
a.lead();
>a.lead() : void
>a.lead : () => void
>a : LeadGuard
>lead : () => void
}
else if (a.isFollower()) {
>a.isFollower() : this is FollowerGuard
>a.isFollower : () => this is FollowerGuard
>a : RoyalGuard
>isFollower : () => this is FollowerGuard
a.follow();
>a.follow() : void
>a.follow : () => void
>a : FollowerGuard
>follow : () => void
}
interface GuardInterface extends RoyalGuard {}
>GuardInterface : GuardInterface
>RoyalGuard : RoyalGuard
let b: GuardInterface;
>b : GuardInterface
>GuardInterface : GuardInterface
if (b.isLeader()) {
>b.isLeader() : this is LeadGuard
>b.isLeader : () => this is LeadGuard
>b : GuardInterface
>isLeader : () => this is LeadGuard
b.lead();
>b.lead() : void
>b.lead : () => void
>b : LeadGuard
>lead : () => void
}
else if (b.isFollower()) {
>b.isFollower() : this is FollowerGuard
>b.isFollower : () => this is FollowerGuard
>b : GuardInterface
>isFollower : () => this is FollowerGuard
b.follow();
>b.follow() : void
>b.follow : () => void
>b : FollowerGuard
>follow : () => void
}
if (((a.isLeader)())) {
>((a.isLeader)()) : this is LeadGuard
>(a.isLeader)() : this is LeadGuard
>(a.isLeader) : () => this is LeadGuard
>a.isLeader : () => this is LeadGuard
>a : RoyalGuard
>isLeader : () => this is LeadGuard
a.lead();
>a.lead() : void
>a.lead : () => void
>a : LeadGuard
>lead : () => void
}
else if (((a).isFollower())) {
>((a).isFollower()) : this is FollowerGuard
>(a).isFollower() : this is FollowerGuard
>(a).isFollower : () => this is FollowerGuard
>(a) : RoyalGuard
>a : RoyalGuard
>isFollower : () => this is FollowerGuard
a.follow();
>a.follow() : void
>a.follow : () => void
>a : FollowerGuard
>follow : () => void
}
if (((a["isLeader"])())) {
>((a["isLeader"])()) : this is LeadGuard
>(a["isLeader"])() : this is LeadGuard
>(a["isLeader"]) : () => this is LeadGuard
>a["isLeader"] : () => this is LeadGuard
>a : RoyalGuard
>"isLeader" : string
a.lead();
>a.lead() : void
>a.lead : () => void
>a : LeadGuard
>lead : () => void
}
else if (((a)["isFollower"]())) {
>((a)["isFollower"]()) : this is FollowerGuard
>(a)["isFollower"]() : this is FollowerGuard
>(a)["isFollower"] : () => this is FollowerGuard
>(a) : RoyalGuard
>a : RoyalGuard
>"isFollower" : string
a.follow();
>a.follow() : void
>a.follow : () => void
>a : FollowerGuard
>follow : () => void
}
var holder2 = {a};
>holder2 : { a: RoyalGuard; }
>{a} : { a: RoyalGuard; }
>a : RoyalGuard
if (holder2.a.isLeader()) {
>holder2.a.isLeader() : this is LeadGuard
>holder2.a.isLeader : () => this is LeadGuard
>holder2.a : RoyalGuard
>holder2 : { a: RoyalGuard; }
>a : RoyalGuard
>isLeader : () => this is LeadGuard
holder2.a;
>holder2.a : RoyalGuard
>holder2 : { a: RoyalGuard; }
>a : RoyalGuard
}
else {
holder2.a;
>holder2.a : RoyalGuard
>holder2 : { a: RoyalGuard; }
>a : RoyalGuard
}
class ArrowGuard {
>ArrowGuard : ArrowGuard
isElite = (): this is ArrowElite => {
>isElite : () => this is ArrowElite
>(): this is ArrowElite => { return this instanceof ArrowElite; } : () => this is ArrowElite
>ArrowElite : ArrowElite
return this instanceof ArrowElite;
>this instanceof ArrowElite : boolean
>this : this
>ArrowElite : typeof ArrowElite
}
isMedic = (): this is ArrowMedic => {
>isMedic : () => this is ArrowMedic
>(): this is ArrowMedic => { return this instanceof ArrowMedic; } : () => this is ArrowMedic
>ArrowMedic : ArrowMedic
return this instanceof ArrowMedic;
>this instanceof ArrowMedic : boolean
>this : this
>ArrowMedic : typeof ArrowMedic
}
}
class ArrowElite extends ArrowGuard {
>ArrowElite : ArrowElite
>ArrowGuard : ArrowGuard
defend(): void {}
>defend : () => void
}
class ArrowMedic extends ArrowGuard {
>ArrowMedic : ArrowMedic
>ArrowGuard : ArrowGuard
heal(): void {}
>heal : () => void
}
let guard = new ArrowGuard();
>guard : ArrowGuard
>new ArrowGuard() : ArrowGuard
>ArrowGuard : typeof ArrowGuard
if (guard.isElite()) {
>guard.isElite() : this is ArrowElite
>guard.isElite : () => this is ArrowElite
>guard : ArrowGuard
>isElite : () => this is ArrowElite
guard.defend();
>guard.defend() : void
>guard.defend : () => void
>guard : ArrowElite
>defend : () => void
}
else if (guard.isMedic()) {
>guard.isMedic() : this is ArrowMedic
>guard.isMedic : () => this is ArrowMedic
>guard : ArrowGuard
>isMedic : () => this is ArrowMedic
guard.heal();
>guard.heal() : void
>guard.heal : () => void
>guard : ArrowMedic
>heal : () => void
}
interface Supplies {
>Supplies : Supplies
spoiled: boolean;
>spoiled : boolean
}
interface Sundries {
>Sundries : Sundries
broken: boolean;
>broken : boolean
}
interface Crate<T> {
>Crate : Crate<T>
>T : T
contents: T;
>contents : T
>T : T
volume: number;
>volume : number
isSupplies(): this is Crate<Supplies>;
>isSupplies : () => this is Crate<Supplies>
>Crate : Crate<T>
>Supplies : Supplies
isSundries(): this is Crate<Sundries>;
>isSundries : () => this is Crate<Sundries>
>Crate : Crate<T>
>Sundries : Sundries
}
let crate: Crate<{}>;
>crate : Crate<{}>
>Crate : Crate<T>
if (crate.isSundries()) {
>crate.isSundries() : this is Crate<Sundries>
>crate.isSundries : () => this is Crate<Sundries>
>crate : Crate<{}>
>isSundries : () => this is Crate<Sundries>
crate.contents.broken = true;
>crate.contents.broken = true : boolean
>crate.contents.broken : boolean
>crate.contents : Sundries
>crate : Crate<Sundries>
>contents : Sundries
>broken : boolean
>true : boolean
}
else if (crate.isSupplies()) {
>crate.isSupplies() : this is Crate<Supplies>
>crate.isSupplies : () => this is Crate<Supplies>
>crate : Crate<{}>
>isSupplies : () => this is Crate<Supplies>
crate.contents.spoiled = true;
>crate.contents.spoiled = true : boolean
>crate.contents.spoiled : boolean
>crate.contents : Supplies
>crate : Crate<Supplies>
>contents : Supplies
>spoiled : boolean
>true : boolean
}
// Matching guards should be assignable
a.isFollower = b.isFollower;
>a.isFollower = b.isFollower : () => this is FollowerGuard
>a.isFollower : () => this is FollowerGuard
>a : RoyalGuard
>isFollower : () => this is FollowerGuard
>b.isFollower : () => this is FollowerGuard
>b : GuardInterface
>isFollower : () => this is FollowerGuard
a.isLeader = b.isLeader;
>a.isLeader = b.isLeader : () => this is LeadGuard
>a.isLeader : () => this is LeadGuard
>a : RoyalGuard
>isLeader : () => this is LeadGuard
>b.isLeader : () => this is LeadGuard
>b : GuardInterface
>isLeader : () => this is LeadGuard
class MimicGuard {
>MimicGuard : MimicGuard
isLeader(): this is MimicLeader { return this instanceof MimicLeader; };
>isLeader : () => this is MimicLeader
>MimicLeader : MimicLeader
>this instanceof MimicLeader : boolean
>this : this
>MimicLeader : typeof MimicLeader
isFollower(): this is MimicFollower { return this instanceof MimicFollower; };
>isFollower : () => this is MimicFollower
>MimicFollower : MimicFollower
>this instanceof MimicFollower : boolean
>this : this
>MimicFollower : typeof MimicFollower
}
class MimicLeader extends MimicGuard {
>MimicLeader : MimicLeader
>MimicGuard : MimicGuard
lead(): void {}
>lead : () => void
}
class MimicFollower extends MimicGuard {
>MimicFollower : MimicFollower
>MimicGuard : MimicGuard
follow(): void {}
>follow : () => void
}
let mimic = new MimicGuard();
>mimic : MimicGuard
>new MimicGuard() : MimicGuard
>MimicGuard : typeof MimicGuard
a.isLeader = mimic.isLeader;
>a.isLeader = mimic.isLeader : () => this is MimicLeader
>a.isLeader : () => this is LeadGuard
>a : RoyalGuard
>isLeader : () => this is LeadGuard
>mimic.isLeader : () => this is MimicLeader
>mimic : MimicGuard
>isLeader : () => this is MimicLeader
a.isFollower = mimic.isFollower;
>a.isFollower = mimic.isFollower : () => this is MimicFollower
>a.isFollower : () => this is FollowerGuard
>a : RoyalGuard
>isFollower : () => this is FollowerGuard
>mimic.isFollower : () => this is MimicFollower
>mimic : MimicGuard
>isFollower : () => this is MimicFollower
if (mimic.isFollower()) {
>mimic.isFollower() : this is MimicFollower
>mimic.isFollower : () => this is MimicFollower
>mimic : MimicGuard
>isFollower : () => this is MimicFollower
mimic.follow();
>mimic.follow() : void
>mimic.follow : () => void
>mimic : MimicFollower
>follow : () => void
mimic.isFollower = a.isFollower;
>mimic.isFollower = a.isFollower : () => this is FollowerGuard
>mimic.isFollower : () => this is MimicFollower
>mimic : MimicFollower
>isFollower : () => this is MimicFollower
>a.isFollower : () => this is FollowerGuard
>a : RoyalGuard
>isFollower : () => this is FollowerGuard
}
interface MimicGuardInterface {
>MimicGuardInterface : MimicGuardInterface
isLeader(): this is LeadGuard;
>isLeader : () => this is LeadGuard
>LeadGuard : LeadGuard
isFollower(): this is FollowerGuard;
>isFollower : () => this is FollowerGuard
>FollowerGuard : FollowerGuard
}

View file

@ -0,0 +1,103 @@
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionOfFormThisErrors.ts(23,1): error TS2322: Type '() => this is LeadGuard' is not assignable to type '() => this is FollowerGuard'.
Type predicate 'this is LeadGuard' is not assignable to 'this is FollowerGuard'.
Type 'LeadGuard' is not assignable to type 'FollowerGuard'.
Property 'follow' is missing in type 'LeadGuard'.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionOfFormThisErrors.ts(24,1): error TS2322: Type '() => this is FollowerGuard' is not assignable to type '() => this is LeadGuard'.
Type predicate 'this is FollowerGuard' is not assignable to 'this is LeadGuard'.
Type 'FollowerGuard' is not assignable to type 'LeadGuard'.
Property 'lead' is missing in type 'FollowerGuard'.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionOfFormThisErrors.ts(26,1): error TS2322: Type '() => this is LeadGuard' is not assignable to type '() => this is FollowerGuard'.
Type predicate 'this is LeadGuard' is not assignable to 'this is FollowerGuard'.
Type 'LeadGuard' is not assignable to type 'FollowerGuard'.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionOfFormThisErrors.ts(27,1): error TS2322: Type '() => this is FollowerGuard' is not assignable to type '() => this is LeadGuard'.
Type predicate 'this is FollowerGuard' is not assignable to 'this is LeadGuard'.
Type 'FollowerGuard' is not assignable to type 'LeadGuard'.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionOfFormThisErrors.ts(29,32): error TS2526: A 'this' type is available only in a non-static member of a class or interface.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionOfFormThisErrors.ts(55,7): error TS2339: Property 'follow' does not exist on type 'RoyalGuard'.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionOfFormThisErrors.ts(58,7): error TS2339: Property 'lead' does not exist on type 'RoyalGuard'.
==== tests/cases/conformance/expressions/typeGuards/typeGuardFunctionOfFormThisErrors.ts (7 errors) ====
class RoyalGuard {
isLeader(): this is LeadGuard {
return this instanceof LeadGuard;
}
isFollower(): this is FollowerGuard {
return this instanceof FollowerGuard;
}
}
class LeadGuard extends RoyalGuard {
lead(): void {};
}
class FollowerGuard extends RoyalGuard {
follow(): void {};
}
interface GuardInterface extends RoyalGuard {}
let a: RoyalGuard = new FollowerGuard();
let b: GuardInterface = new LeadGuard();
// Mismatched guards shouldn't be assignable
b.isFollower = b.isLeader;
~~~~~~~~~~~~
!!! error TS2322: Type '() => this is LeadGuard' is not assignable to type '() => this is FollowerGuard'.
!!! error TS2322: Type predicate 'this is LeadGuard' is not assignable to 'this is FollowerGuard'.
!!! error TS2322: Type 'LeadGuard' is not assignable to type 'FollowerGuard'.
!!! error TS2322: Property 'follow' is missing in type 'LeadGuard'.
b.isLeader = b.isFollower;
~~~~~~~~~~
!!! error TS2322: Type '() => this is FollowerGuard' is not assignable to type '() => this is LeadGuard'.
!!! error TS2322: Type predicate 'this is FollowerGuard' is not assignable to 'this is LeadGuard'.
!!! error TS2322: Type 'FollowerGuard' is not assignable to type 'LeadGuard'.
!!! error TS2322: Property 'lead' is missing in type 'FollowerGuard'.
a.isFollower = a.isLeader;
~~~~~~~~~~~~
!!! error TS2322: Type '() => this is LeadGuard' is not assignable to type '() => this is FollowerGuard'.
!!! error TS2322: Type predicate 'this is LeadGuard' is not assignable to 'this is FollowerGuard'.
!!! error TS2322: Type 'LeadGuard' is not assignable to type 'FollowerGuard'.
a.isLeader = a.isFollower;
~~~~~~~~~~
!!! error TS2322: Type '() => this is FollowerGuard' is not assignable to type '() => this is LeadGuard'.
!!! error TS2322: Type predicate 'this is FollowerGuard' is not assignable to 'this is LeadGuard'.
!!! error TS2322: Type 'FollowerGuard' is not assignable to type 'LeadGuard'.
function invalidGuard(c: any): this is number {
~~~~
!!! error TS2526: A 'this' type is available only in a non-static member of a class or interface.
return false;
}
let c: number | number[];
if (invalidGuard(c)) {
c;
}
else {
c;
}
let holder = {invalidGuard};
if (holder.invalidGuard(c)) {
c;
holder;
}
else {
c;
holder;
}
let detached = a.isFollower;
if (detached()) {
a.follow();
~~~~~~
!!! error TS2339: Property 'follow' does not exist on type 'RoyalGuard'.
}
else {
a.lead();
~~~~
!!! error TS2339: Property 'lead' does not exist on type 'RoyalGuard'.
}

View file

@ -0,0 +1,152 @@
//// [typeGuardFunctionOfFormThisErrors.ts]
class RoyalGuard {
isLeader(): this is LeadGuard {
return this instanceof LeadGuard;
}
isFollower(): this is FollowerGuard {
return this instanceof FollowerGuard;
}
}
class LeadGuard extends RoyalGuard {
lead(): void {};
}
class FollowerGuard extends RoyalGuard {
follow(): void {};
}
interface GuardInterface extends RoyalGuard {}
let a: RoyalGuard = new FollowerGuard();
let b: GuardInterface = new LeadGuard();
// Mismatched guards shouldn't be assignable
b.isFollower = b.isLeader;
b.isLeader = b.isFollower;
a.isFollower = a.isLeader;
a.isLeader = a.isFollower;
function invalidGuard(c: any): this is number {
return false;
}
let c: number | number[];
if (invalidGuard(c)) {
c;
}
else {
c;
}
let holder = {invalidGuard};
if (holder.invalidGuard(c)) {
c;
holder;
}
else {
c;
holder;
}
let detached = a.isFollower;
if (detached()) {
a.follow();
}
else {
a.lead();
}
//// [typeGuardFunctionOfFormThisErrors.js]
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var RoyalGuard = (function () {
function RoyalGuard() {
}
RoyalGuard.prototype.isLeader = function () {
return this instanceof LeadGuard;
};
RoyalGuard.prototype.isFollower = function () {
return this instanceof FollowerGuard;
};
return RoyalGuard;
}());
var LeadGuard = (function (_super) {
__extends(LeadGuard, _super);
function LeadGuard() {
_super.apply(this, arguments);
}
LeadGuard.prototype.lead = function () { };
;
return LeadGuard;
}(RoyalGuard));
var FollowerGuard = (function (_super) {
__extends(FollowerGuard, _super);
function FollowerGuard() {
_super.apply(this, arguments);
}
FollowerGuard.prototype.follow = function () { };
;
return FollowerGuard;
}(RoyalGuard));
var a = new FollowerGuard();
var b = new LeadGuard();
// Mismatched guards shouldn't be assignable
b.isFollower = b.isLeader;
b.isLeader = b.isFollower;
a.isFollower = a.isLeader;
a.isLeader = a.isFollower;
function invalidGuard(c) {
return false;
}
var c;
if (invalidGuard(c)) {
c;
}
else {
c;
}
var holder = { invalidGuard: invalidGuard };
if (holder.invalidGuard(c)) {
c;
holder;
}
else {
c;
holder;
}
var detached = a.isFollower;
if (detached()) {
a.follow();
}
else {
a.lead();
}
//// [typeGuardFunctionOfFormThisErrors.d.ts]
declare class RoyalGuard {
isLeader(): this is LeadGuard;
isFollower(): this is FollowerGuard;
}
declare class LeadGuard extends RoyalGuard {
lead(): void;
}
declare class FollowerGuard extends RoyalGuard {
follow(): void;
}
interface GuardInterface extends RoyalGuard {
}
declare let a: RoyalGuard;
declare let b: GuardInterface;
declare function invalidGuard(c: any): this is number;
declare let c: number | number[];
declare let holder: {
invalidGuard: (c: any) => this is number;
};
declare let detached: () => this is FollowerGuard;

View file

@ -67,7 +67,7 @@ str = isC1(c1Orc2) && c1Orc2.p1; // C1
>str = isC1(c1Orc2) && c1Orc2.p1 : string
>str : string
>isC1(c1Orc2) && c1Orc2.p1 : string
>isC1(c1Orc2) : boolean
>isC1(c1Orc2) : x is C1
>isC1 : (x: any) => x is C1
>c1Orc2 : C1 | C2
>c1Orc2.p1 : string
@ -78,7 +78,7 @@ num = isC2(c1Orc2) && c1Orc2.p2; // C2
>num = isC2(c1Orc2) && c1Orc2.p2 : number
>num : number
>isC2(c1Orc2) && c1Orc2.p2 : number
>isC2(c1Orc2) : boolean
>isC2(c1Orc2) : x is C2
>isC2 : (x: any) => x is C2
>c1Orc2 : C1 | C2
>c1Orc2.p2 : number
@ -89,7 +89,7 @@ str = isD1(c1Orc2) && c1Orc2.p1; // D1
>str = isD1(c1Orc2) && c1Orc2.p1 : string
>str : string
>isD1(c1Orc2) && c1Orc2.p1 : string
>isD1(c1Orc2) : boolean
>isD1(c1Orc2) : x is D1
>isD1 : (x: any) => x is D1
>c1Orc2 : C1 | C2
>c1Orc2.p1 : string
@ -100,7 +100,7 @@ num = isD1(c1Orc2) && c1Orc2.p3; // D1
>num = isD1(c1Orc2) && c1Orc2.p3 : number
>num : number
>isD1(c1Orc2) && c1Orc2.p3 : number
>isD1(c1Orc2) : boolean
>isD1(c1Orc2) : x is D1
>isD1 : (x: any) => x is D1
>c1Orc2 : C1 | C2
>c1Orc2.p3 : number
@ -116,7 +116,7 @@ num = isC2(c2Ord1) && c2Ord1.p2; // C2
>num = isC2(c2Ord1) && c2Ord1.p2 : number
>num : number
>isC2(c2Ord1) && c2Ord1.p2 : number
>isC2(c2Ord1) : boolean
>isC2(c2Ord1) : x is C2
>isC2 : (x: any) => x is C2
>c2Ord1 : C2 | D1
>c2Ord1.p2 : number
@ -127,7 +127,7 @@ num = isD1(c2Ord1) && c2Ord1.p3; // D1
>num = isD1(c2Ord1) && c2Ord1.p3 : number
>num : number
>isD1(c2Ord1) && c2Ord1.p3 : number
>isD1(c2Ord1) : boolean
>isD1(c2Ord1) : x is D1
>isD1 : (x: any) => x is D1
>c2Ord1 : C2 | D1
>c2Ord1.p3 : number
@ -138,7 +138,7 @@ str = isD1(c2Ord1) && c2Ord1.p1; // D1
>str = isD1(c2Ord1) && c2Ord1.p1 : string
>str : string
>isD1(c2Ord1) && c2Ord1.p1 : string
>isD1(c2Ord1) : boolean
>isD1(c2Ord1) : x is D1
>isD1 : (x: any) => x is D1
>c2Ord1 : C2 | D1
>c2Ord1.p1 : string
@ -150,7 +150,7 @@ var r2: C2 | D1 = isC1(c2Ord1) && c2Ord1; // C2 | D1
>C2 : C2
>D1 : D1
>isC1(c2Ord1) && c2Ord1 : D1
>isC1(c2Ord1) : boolean
>isC1(c2Ord1) : x is C1
>isC1 : (x: any) => x is C1
>c2Ord1 : C2 | D1
>c2Ord1 : D1

View file

@ -98,7 +98,7 @@ str = isC1(c1Orc2) && c1Orc2.p1; // C1
>str = isC1(c1Orc2) && c1Orc2.p1 : string
>str : string
>isC1(c1Orc2) && c1Orc2.p1 : string
>isC1(c1Orc2) : boolean
>isC1(c1Orc2) : x is C1
>isC1 : (x: any) => x is C1
>c1Orc2 : C1 | C2
>c1Orc2.p1 : string
@ -109,7 +109,7 @@ num = isC2(c1Orc2) && c1Orc2.p2; // C2
>num = isC2(c1Orc2) && c1Orc2.p2 : number
>num : number
>isC2(c1Orc2) && c1Orc2.p2 : number
>isC2(c1Orc2) : boolean
>isC2(c1Orc2) : x is C2
>isC2 : (x: any) => x is C2
>c1Orc2 : C1 | C2
>c1Orc2.p2 : number
@ -120,7 +120,7 @@ str = isD1(c1Orc2) && c1Orc2.p1; // D1
>str = isD1(c1Orc2) && c1Orc2.p1 : string
>str : string
>isD1(c1Orc2) && c1Orc2.p1 : string
>isD1(c1Orc2) : boolean
>isD1(c1Orc2) : x is D1
>isD1 : (x: any) => x is D1
>c1Orc2 : C1 | C2
>c1Orc2.p1 : string
@ -131,7 +131,7 @@ num = isD1(c1Orc2) && c1Orc2.p3; // D1
>num = isD1(c1Orc2) && c1Orc2.p3 : number
>num : number
>isD1(c1Orc2) && c1Orc2.p3 : number
>isD1(c1Orc2) : boolean
>isD1(c1Orc2) : x is D1
>isD1 : (x: any) => x is D1
>c1Orc2 : C1 | C2
>c1Orc2.p3 : number
@ -147,7 +147,7 @@ num = isC2(c2Ord1) && c2Ord1.p2; // C2
>num = isC2(c2Ord1) && c2Ord1.p2 : number
>num : number
>isC2(c2Ord1) && c2Ord1.p2 : number
>isC2(c2Ord1) : boolean
>isC2(c2Ord1) : x is C2
>isC2 : (x: any) => x is C2
>c2Ord1 : C2 | D1
>c2Ord1.p2 : number
@ -158,7 +158,7 @@ num = isD1(c2Ord1) && c2Ord1.p3; // D1
>num = isD1(c2Ord1) && c2Ord1.p3 : number
>num : number
>isD1(c2Ord1) && c2Ord1.p3 : number
>isD1(c2Ord1) : boolean
>isD1(c2Ord1) : x is D1
>isD1 : (x: any) => x is D1
>c2Ord1 : C2 | D1
>c2Ord1.p3 : number
@ -169,7 +169,7 @@ str = isD1(c2Ord1) && c2Ord1.p1; // D1
>str = isD1(c2Ord1) && c2Ord1.p1 : string
>str : string
>isD1(c2Ord1) && c2Ord1.p1 : string
>isD1(c2Ord1) : boolean
>isD1(c2Ord1) : x is D1
>isD1 : (x: any) => x is D1
>c2Ord1 : C2 | D1
>c2Ord1.p1 : string
@ -181,7 +181,7 @@ var r2: C2 | D1 = isC1(c2Ord1) && c2Ord1; // C2 | D1
>C2 : C2
>D1 : D1
>isC1(c2Ord1) && c2Ord1 : D1
>isC1(c2Ord1) : boolean
>isC1(c2Ord1) : x is C1
>isC1 : (x: any) => x is C1
>c2Ord1 : C2 | D1
>c2Ord1 : D1

View file

@ -0,0 +1,187 @@
//// [typeGuardOfFormThisMember.ts]
// There's a 'File' class in the stdlib, wrap with a namespace to avoid collision
namespace Test {
export class FileSystemObject {
isFSO: this is FileSystemObject;
get isFile(): this is File {
return this instanceof File;
}
set isFile(param) {
// noop
}
get isDirectory(): this is Directory {
return this instanceof Directory;
}
isNetworked: this is (Networked & this);
constructor(public path: string) {}
}
export class File extends FileSystemObject {
constructor(path: string, public content: string) { super(path); }
}
export class Directory extends FileSystemObject {
children: FileSystemObject[];
}
export interface Networked {
host: string;
}
let file: FileSystemObject = new File("foo/bar.txt", "foo");
file.isNetworked = false;
file.isFSO = file.isFile;
file.isFile = true;
let x = file.isFile;
if (file.isFile) {
file.content;
if (file.isNetworked) {
file.host;
file.content;
}
}
else if (file.isDirectory) {
file.children;
}
else if (file.isNetworked) {
file.host;
}
interface GenericLeadGuard<T> extends GenericGuard<T> {
lead(): void;
}
interface GenericFollowerGuard<T> extends GenericGuard<T> {
follow(): void;
}
interface GenericGuard<T> {
target: T;
isLeader: this is (GenericLeadGuard<T>);
isFollower: this is GenericFollowerGuard<T>;
}
let guard: GenericGuard<File>;
if (guard.isLeader) {
guard.lead();
}
else if (guard.isFollower) {
guard.follow();
}
interface SpecificGuard {
isMoreSpecific: this is MoreSpecificGuard;
}
interface MoreSpecificGuard extends SpecificGuard {
do(): void;
}
let general: SpecificGuard;
if (general.isMoreSpecific) {
general.do();
}
}
//// [typeGuardOfFormThisMember.js]
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
// There's a 'File' class in the stdlib, wrap with a namespace to avoid collision
var Test;
(function (Test) {
var FileSystemObject = (function () {
function FileSystemObject(path) {
this.path = path;
}
Object.defineProperty(FileSystemObject.prototype, "isFile", {
get: function () {
return this instanceof File;
},
set: function (param) {
// noop
},
enumerable: true,
configurable: true
});
Object.defineProperty(FileSystemObject.prototype, "isDirectory", {
get: function () {
return this instanceof Directory;
},
enumerable: true,
configurable: true
});
return FileSystemObject;
}());
Test.FileSystemObject = FileSystemObject;
var File = (function (_super) {
__extends(File, _super);
function File(path, content) {
_super.call(this, path);
this.content = content;
}
return File;
}(FileSystemObject));
Test.File = File;
var Directory = (function (_super) {
__extends(Directory, _super);
function Directory() {
_super.apply(this, arguments);
}
return Directory;
}(FileSystemObject));
Test.Directory = Directory;
var file = new File("foo/bar.txt", "foo");
file.isNetworked = false;
file.isFSO = file.isFile;
file.isFile = true;
var x = file.isFile;
if (file.isFile) {
file.content;
if (file.isNetworked) {
file.host;
file.content;
}
}
else if (file.isDirectory) {
file.children;
}
else if (file.isNetworked) {
file.host;
}
var guard;
if (guard.isLeader) {
guard.lead();
}
else if (guard.isFollower) {
guard.follow();
}
var general;
if (general.isMoreSpecific) {
general.do();
}
})(Test || (Test = {}));
//// [typeGuardOfFormThisMember.d.ts]
declare namespace Test {
class FileSystemObject {
path: string;
isFSO: this is FileSystemObject;
isFile: this is File;
isDirectory: this is Directory;
isNetworked: this is (Networked & this);
constructor(path: string);
}
class File extends FileSystemObject {
content: string;
constructor(path: string, content: string);
}
class Directory extends FileSystemObject {
children: FileSystemObject[];
}
interface Networked {
host: string;
}
}

View file

@ -0,0 +1,240 @@
=== tests/cases/conformance/expressions/typeGuards/typeGuardOfFormThisMember.ts ===
// There's a 'File' class in the stdlib, wrap with a namespace to avoid collision
namespace Test {
>Test : Symbol(Test, Decl(typeGuardOfFormThisMember.ts, 0, 0))
export class FileSystemObject {
>FileSystemObject : Symbol(FileSystemObject, Decl(typeGuardOfFormThisMember.ts, 1, 16))
isFSO: this is FileSystemObject;
>isFSO : Symbol(isFSO, Decl(typeGuardOfFormThisMember.ts, 2, 32))
>FileSystemObject : Symbol(FileSystemObject, Decl(typeGuardOfFormThisMember.ts, 1, 16))
get isFile(): this is File {
>isFile : Symbol(isFile, Decl(typeGuardOfFormThisMember.ts, 3, 34), Decl(typeGuardOfFormThisMember.ts, 6, 3))
>File : Symbol(File, Decl(typeGuardOfFormThisMember.ts, 15, 2))
return this instanceof File;
>this : Symbol(FileSystemObject, Decl(typeGuardOfFormThisMember.ts, 1, 16))
>File : Symbol(File, Decl(typeGuardOfFormThisMember.ts, 15, 2))
}
set isFile(param) {
>isFile : Symbol(isFile, Decl(typeGuardOfFormThisMember.ts, 3, 34), Decl(typeGuardOfFormThisMember.ts, 6, 3))
>param : Symbol(param, Decl(typeGuardOfFormThisMember.ts, 7, 13))
// noop
}
get isDirectory(): this is Directory {
>isDirectory : Symbol(isDirectory, Decl(typeGuardOfFormThisMember.ts, 9, 3))
>Directory : Symbol(Directory, Decl(typeGuardOfFormThisMember.ts, 19, 2))
return this instanceof Directory;
>this : Symbol(FileSystemObject, Decl(typeGuardOfFormThisMember.ts, 1, 16))
>Directory : Symbol(Directory, Decl(typeGuardOfFormThisMember.ts, 19, 2))
}
isNetworked: this is (Networked & this);
>isNetworked : Symbol(isNetworked, Decl(typeGuardOfFormThisMember.ts, 12, 3))
>Networked : Symbol(Networked, Decl(typeGuardOfFormThisMember.ts, 22, 2))
constructor(public path: string) {}
>path : Symbol(path, Decl(typeGuardOfFormThisMember.ts, 14, 14))
}
export class File extends FileSystemObject {
>File : Symbol(File, Decl(typeGuardOfFormThisMember.ts, 15, 2))
>FileSystemObject : Symbol(FileSystemObject, Decl(typeGuardOfFormThisMember.ts, 1, 16))
constructor(path: string, public content: string) { super(path); }
>path : Symbol(path, Decl(typeGuardOfFormThisMember.ts, 18, 14))
>content : Symbol(content, Decl(typeGuardOfFormThisMember.ts, 18, 27))
>super : Symbol(FileSystemObject, Decl(typeGuardOfFormThisMember.ts, 1, 16))
>path : Symbol(path, Decl(typeGuardOfFormThisMember.ts, 18, 14))
}
export class Directory extends FileSystemObject {
>Directory : Symbol(Directory, Decl(typeGuardOfFormThisMember.ts, 19, 2))
>FileSystemObject : Symbol(FileSystemObject, Decl(typeGuardOfFormThisMember.ts, 1, 16))
children: FileSystemObject[];
>children : Symbol(children, Decl(typeGuardOfFormThisMember.ts, 20, 50))
>FileSystemObject : Symbol(FileSystemObject, Decl(typeGuardOfFormThisMember.ts, 1, 16))
}
export interface Networked {
>Networked : Symbol(Networked, Decl(typeGuardOfFormThisMember.ts, 22, 2))
host: string;
>host : Symbol(host, Decl(typeGuardOfFormThisMember.ts, 23, 29))
}
let file: FileSystemObject = new File("foo/bar.txt", "foo");
>file : Symbol(file, Decl(typeGuardOfFormThisMember.ts, 27, 4))
>FileSystemObject : Symbol(FileSystemObject, Decl(typeGuardOfFormThisMember.ts, 1, 16))
>File : Symbol(File, Decl(typeGuardOfFormThisMember.ts, 15, 2))
file.isNetworked = false;
>file.isNetworked : Symbol(FileSystemObject.isNetworked, Decl(typeGuardOfFormThisMember.ts, 12, 3))
>file : Symbol(file, Decl(typeGuardOfFormThisMember.ts, 27, 4))
>isNetworked : Symbol(FileSystemObject.isNetworked, Decl(typeGuardOfFormThisMember.ts, 12, 3))
file.isFSO = file.isFile;
>file.isFSO : Symbol(FileSystemObject.isFSO, Decl(typeGuardOfFormThisMember.ts, 2, 32))
>file : Symbol(file, Decl(typeGuardOfFormThisMember.ts, 27, 4))
>isFSO : Symbol(FileSystemObject.isFSO, Decl(typeGuardOfFormThisMember.ts, 2, 32))
>file.isFile : Symbol(FileSystemObject.isFile, Decl(typeGuardOfFormThisMember.ts, 3, 34), Decl(typeGuardOfFormThisMember.ts, 6, 3))
>file : Symbol(file, Decl(typeGuardOfFormThisMember.ts, 27, 4))
>isFile : Symbol(FileSystemObject.isFile, Decl(typeGuardOfFormThisMember.ts, 3, 34), Decl(typeGuardOfFormThisMember.ts, 6, 3))
file.isFile = true;
>file.isFile : Symbol(FileSystemObject.isFile, Decl(typeGuardOfFormThisMember.ts, 3, 34), Decl(typeGuardOfFormThisMember.ts, 6, 3))
>file : Symbol(file, Decl(typeGuardOfFormThisMember.ts, 27, 4))
>isFile : Symbol(FileSystemObject.isFile, Decl(typeGuardOfFormThisMember.ts, 3, 34), Decl(typeGuardOfFormThisMember.ts, 6, 3))
let x = file.isFile;
>x : Symbol(x, Decl(typeGuardOfFormThisMember.ts, 31, 4))
>file.isFile : Symbol(FileSystemObject.isFile, Decl(typeGuardOfFormThisMember.ts, 3, 34), Decl(typeGuardOfFormThisMember.ts, 6, 3))
>file : Symbol(file, Decl(typeGuardOfFormThisMember.ts, 27, 4))
>isFile : Symbol(FileSystemObject.isFile, Decl(typeGuardOfFormThisMember.ts, 3, 34), Decl(typeGuardOfFormThisMember.ts, 6, 3))
if (file.isFile) {
>file.isFile : Symbol(FileSystemObject.isFile, Decl(typeGuardOfFormThisMember.ts, 3, 34), Decl(typeGuardOfFormThisMember.ts, 6, 3))
>file : Symbol(file, Decl(typeGuardOfFormThisMember.ts, 27, 4))
>isFile : Symbol(FileSystemObject.isFile, Decl(typeGuardOfFormThisMember.ts, 3, 34), Decl(typeGuardOfFormThisMember.ts, 6, 3))
file.content;
>file.content : Symbol(File.content, Decl(typeGuardOfFormThisMember.ts, 18, 27))
>file : Symbol(file, Decl(typeGuardOfFormThisMember.ts, 27, 4))
>content : Symbol(File.content, Decl(typeGuardOfFormThisMember.ts, 18, 27))
if (file.isNetworked) {
>file.isNetworked : Symbol(FileSystemObject.isNetworked, Decl(typeGuardOfFormThisMember.ts, 12, 3))
>file : Symbol(file, Decl(typeGuardOfFormThisMember.ts, 27, 4))
>isNetworked : Symbol(FileSystemObject.isNetworked, Decl(typeGuardOfFormThisMember.ts, 12, 3))
file.host;
>file.host : Symbol(Networked.host, Decl(typeGuardOfFormThisMember.ts, 23, 29))
>file : Symbol(file, Decl(typeGuardOfFormThisMember.ts, 27, 4))
>host : Symbol(Networked.host, Decl(typeGuardOfFormThisMember.ts, 23, 29))
file.content;
>file.content : Symbol(File.content, Decl(typeGuardOfFormThisMember.ts, 18, 27))
>file : Symbol(file, Decl(typeGuardOfFormThisMember.ts, 27, 4))
>content : Symbol(File.content, Decl(typeGuardOfFormThisMember.ts, 18, 27))
}
}
else if (file.isDirectory) {
>file.isDirectory : Symbol(FileSystemObject.isDirectory, Decl(typeGuardOfFormThisMember.ts, 9, 3))
>file : Symbol(file, Decl(typeGuardOfFormThisMember.ts, 27, 4))
>isDirectory : Symbol(FileSystemObject.isDirectory, Decl(typeGuardOfFormThisMember.ts, 9, 3))
file.children;
>file.children : Symbol(Directory.children, Decl(typeGuardOfFormThisMember.ts, 20, 50))
>file : Symbol(file, Decl(typeGuardOfFormThisMember.ts, 27, 4))
>children : Symbol(Directory.children, Decl(typeGuardOfFormThisMember.ts, 20, 50))
}
else if (file.isNetworked) {
>file.isNetworked : Symbol(FileSystemObject.isNetworked, Decl(typeGuardOfFormThisMember.ts, 12, 3))
>file : Symbol(file, Decl(typeGuardOfFormThisMember.ts, 27, 4))
>isNetworked : Symbol(FileSystemObject.isNetworked, Decl(typeGuardOfFormThisMember.ts, 12, 3))
file.host;
>file.host : Symbol(Networked.host, Decl(typeGuardOfFormThisMember.ts, 23, 29))
>file : Symbol(file, Decl(typeGuardOfFormThisMember.ts, 27, 4))
>host : Symbol(Networked.host, Decl(typeGuardOfFormThisMember.ts, 23, 29))
}
interface GenericLeadGuard<T> extends GenericGuard<T> {
>GenericLeadGuard : Symbol(GenericLeadGuard, Decl(typeGuardOfFormThisMember.ts, 44, 2))
>T : Symbol(T, Decl(typeGuardOfFormThisMember.ts, 46, 28))
>GenericGuard : Symbol(GenericGuard, Decl(typeGuardOfFormThisMember.ts, 52, 2))
>T : Symbol(T, Decl(typeGuardOfFormThisMember.ts, 46, 28))
lead(): void;
>lead : Symbol(lead, Decl(typeGuardOfFormThisMember.ts, 46, 56))
}
interface GenericFollowerGuard<T> extends GenericGuard<T> {
>GenericFollowerGuard : Symbol(GenericFollowerGuard, Decl(typeGuardOfFormThisMember.ts, 48, 2))
>T : Symbol(T, Decl(typeGuardOfFormThisMember.ts, 50, 32))
>GenericGuard : Symbol(GenericGuard, Decl(typeGuardOfFormThisMember.ts, 52, 2))
>T : Symbol(T, Decl(typeGuardOfFormThisMember.ts, 50, 32))
follow(): void;
>follow : Symbol(follow, Decl(typeGuardOfFormThisMember.ts, 50, 60))
}
interface GenericGuard<T> {
>GenericGuard : Symbol(GenericGuard, Decl(typeGuardOfFormThisMember.ts, 52, 2))
>T : Symbol(T, Decl(typeGuardOfFormThisMember.ts, 54, 24))
target: T;
>target : Symbol(target, Decl(typeGuardOfFormThisMember.ts, 54, 28))
>T : Symbol(T, Decl(typeGuardOfFormThisMember.ts, 54, 24))
isLeader: this is (GenericLeadGuard<T>);
>isLeader : Symbol(isLeader, Decl(typeGuardOfFormThisMember.ts, 55, 12))
>GenericLeadGuard : Symbol(GenericLeadGuard, Decl(typeGuardOfFormThisMember.ts, 44, 2))
>T : Symbol(T, Decl(typeGuardOfFormThisMember.ts, 54, 24))
isFollower: this is GenericFollowerGuard<T>;
>isFollower : Symbol(isFollower, Decl(typeGuardOfFormThisMember.ts, 56, 42))
>GenericFollowerGuard : Symbol(GenericFollowerGuard, Decl(typeGuardOfFormThisMember.ts, 48, 2))
>T : Symbol(T, Decl(typeGuardOfFormThisMember.ts, 54, 24))
}
let guard: GenericGuard<File>;
>guard : Symbol(guard, Decl(typeGuardOfFormThisMember.ts, 60, 4))
>GenericGuard : Symbol(GenericGuard, Decl(typeGuardOfFormThisMember.ts, 52, 2))
>File : Symbol(File, Decl(typeGuardOfFormThisMember.ts, 15, 2))
if (guard.isLeader) {
>guard.isLeader : Symbol(GenericGuard.isLeader, Decl(typeGuardOfFormThisMember.ts, 55, 12))
>guard : Symbol(guard, Decl(typeGuardOfFormThisMember.ts, 60, 4))
>isLeader : Symbol(GenericGuard.isLeader, Decl(typeGuardOfFormThisMember.ts, 55, 12))
guard.lead();
>guard.lead : Symbol(GenericLeadGuard.lead, Decl(typeGuardOfFormThisMember.ts, 46, 56))
>guard : Symbol(guard, Decl(typeGuardOfFormThisMember.ts, 60, 4))
>lead : Symbol(GenericLeadGuard.lead, Decl(typeGuardOfFormThisMember.ts, 46, 56))
}
else if (guard.isFollower) {
>guard.isFollower : Symbol(GenericGuard.isFollower, Decl(typeGuardOfFormThisMember.ts, 56, 42))
>guard : Symbol(guard, Decl(typeGuardOfFormThisMember.ts, 60, 4))
>isFollower : Symbol(GenericGuard.isFollower, Decl(typeGuardOfFormThisMember.ts, 56, 42))
guard.follow();
>guard.follow : Symbol(GenericFollowerGuard.follow, Decl(typeGuardOfFormThisMember.ts, 50, 60))
>guard : Symbol(guard, Decl(typeGuardOfFormThisMember.ts, 60, 4))
>follow : Symbol(GenericFollowerGuard.follow, Decl(typeGuardOfFormThisMember.ts, 50, 60))
}
interface SpecificGuard {
>SpecificGuard : Symbol(SpecificGuard, Decl(typeGuardOfFormThisMember.ts, 66, 2))
isMoreSpecific: this is MoreSpecificGuard;
>isMoreSpecific : Symbol(isMoreSpecific, Decl(typeGuardOfFormThisMember.ts, 68, 26))
>MoreSpecificGuard : Symbol(MoreSpecificGuard, Decl(typeGuardOfFormThisMember.ts, 70, 2))
}
interface MoreSpecificGuard extends SpecificGuard {
>MoreSpecificGuard : Symbol(MoreSpecificGuard, Decl(typeGuardOfFormThisMember.ts, 70, 2))
>SpecificGuard : Symbol(SpecificGuard, Decl(typeGuardOfFormThisMember.ts, 66, 2))
do(): void;
>do : Symbol(do, Decl(typeGuardOfFormThisMember.ts, 72, 52))
}
let general: SpecificGuard;
>general : Symbol(general, Decl(typeGuardOfFormThisMember.ts, 76, 4))
>SpecificGuard : Symbol(SpecificGuard, Decl(typeGuardOfFormThisMember.ts, 66, 2))
if (general.isMoreSpecific) {
>general.isMoreSpecific : Symbol(SpecificGuard.isMoreSpecific, Decl(typeGuardOfFormThisMember.ts, 68, 26))
>general : Symbol(general, Decl(typeGuardOfFormThisMember.ts, 76, 4))
>isMoreSpecific : Symbol(SpecificGuard.isMoreSpecific, Decl(typeGuardOfFormThisMember.ts, 68, 26))
general.do();
>general.do : Symbol(MoreSpecificGuard.do, Decl(typeGuardOfFormThisMember.ts, 72, 52))
>general : Symbol(general, Decl(typeGuardOfFormThisMember.ts, 76, 4))
>do : Symbol(MoreSpecificGuard.do, Decl(typeGuardOfFormThisMember.ts, 72, 52))
}
}

View file

@ -0,0 +1,254 @@
=== tests/cases/conformance/expressions/typeGuards/typeGuardOfFormThisMember.ts ===
// There's a 'File' class in the stdlib, wrap with a namespace to avoid collision
namespace Test {
>Test : typeof Test
export class FileSystemObject {
>FileSystemObject : FileSystemObject
isFSO: this is FileSystemObject;
>isFSO : this is FileSystemObject
>FileSystemObject : FileSystemObject
get isFile(): this is File {
>isFile : this is File
>File : File
return this instanceof File;
>this instanceof File : boolean
>this : this
>File : typeof File
}
set isFile(param) {
>isFile : this is File
>param : boolean
// noop
}
get isDirectory(): this is Directory {
>isDirectory : this is Directory
>Directory : Directory
return this instanceof Directory;
>this instanceof Directory : boolean
>this : this
>Directory : typeof Directory
}
isNetworked: this is (Networked & this);
>isNetworked : this is Networked & this
>Networked : Networked
constructor(public path: string) {}
>path : string
}
export class File extends FileSystemObject {
>File : File
>FileSystemObject : FileSystemObject
constructor(path: string, public content: string) { super(path); }
>path : string
>content : string
>super(path) : void
>super : typeof FileSystemObject
>path : string
}
export class Directory extends FileSystemObject {
>Directory : Directory
>FileSystemObject : FileSystemObject
children: FileSystemObject[];
>children : FileSystemObject[]
>FileSystemObject : FileSystemObject
}
export interface Networked {
>Networked : Networked
host: string;
>host : string
}
let file: FileSystemObject = new File("foo/bar.txt", "foo");
>file : FileSystemObject
>FileSystemObject : FileSystemObject
>new File("foo/bar.txt", "foo") : File
>File : typeof File
>"foo/bar.txt" : string
>"foo" : string
file.isNetworked = false;
>file.isNetworked = false : boolean
>file.isNetworked : this is Networked & FileSystemObject
>file : FileSystemObject
>isNetworked : this is Networked & FileSystemObject
>false : boolean
file.isFSO = file.isFile;
>file.isFSO = file.isFile : this is File
>file.isFSO : this is FileSystemObject
>file : FileSystemObject
>isFSO : this is FileSystemObject
>file.isFile : this is File
>file : FileSystemObject
>isFile : this is File
file.isFile = true;
>file.isFile = true : boolean
>file.isFile : this is File
>file : FileSystemObject
>isFile : this is File
>true : boolean
let x = file.isFile;
>x : boolean
>file.isFile : this is File
>file : FileSystemObject
>isFile : this is File
if (file.isFile) {
>file.isFile : this is File
>file : FileSystemObject
>isFile : this is File
file.content;
>file.content : string
>file : File
>content : string
if (file.isNetworked) {
>file.isNetworked : this is Networked & File
>file : File
>isNetworked : this is Networked & File
file.host;
>file.host : string
>file : Networked & File
>host : string
file.content;
>file.content : string
>file : Networked & File
>content : string
}
}
else if (file.isDirectory) {
>file.isDirectory : this is Directory
>file : FileSystemObject
>isDirectory : this is Directory
file.children;
>file.children : FileSystemObject[]
>file : Directory
>children : FileSystemObject[]
}
else if (file.isNetworked) {
>file.isNetworked : this is Networked & FileSystemObject
>file : FileSystemObject
>isNetworked : this is Networked & FileSystemObject
file.host;
>file.host : string
>file : Networked & FileSystemObject
>host : string
}
interface GenericLeadGuard<T> extends GenericGuard<T> {
>GenericLeadGuard : GenericLeadGuard<T>
>T : T
>GenericGuard : GenericGuard<T>
>T : T
lead(): void;
>lead : () => void
}
interface GenericFollowerGuard<T> extends GenericGuard<T> {
>GenericFollowerGuard : GenericFollowerGuard<T>
>T : T
>GenericGuard : GenericGuard<T>
>T : T
follow(): void;
>follow : () => void
}
interface GenericGuard<T> {
>GenericGuard : GenericGuard<T>
>T : T
target: T;
>target : T
>T : T
isLeader: this is (GenericLeadGuard<T>);
>isLeader : this is GenericLeadGuard<T>
>GenericLeadGuard : GenericLeadGuard<T>
>T : T
isFollower: this is GenericFollowerGuard<T>;
>isFollower : this is GenericFollowerGuard<T>
>GenericFollowerGuard : GenericFollowerGuard<T>
>T : T
}
let guard: GenericGuard<File>;
>guard : GenericGuard<File>
>GenericGuard : GenericGuard<T>
>File : File
if (guard.isLeader) {
>guard.isLeader : this is GenericLeadGuard<File>
>guard : GenericGuard<File>
>isLeader : this is GenericLeadGuard<File>
guard.lead();
>guard.lead() : void
>guard.lead : () => void
>guard : GenericLeadGuard<File>
>lead : () => void
}
else if (guard.isFollower) {
>guard.isFollower : this is GenericFollowerGuard<File>
>guard : GenericGuard<File>
>isFollower : this is GenericFollowerGuard<File>
guard.follow();
>guard.follow() : void
>guard.follow : () => void
>guard : GenericFollowerGuard<File>
>follow : () => void
}
interface SpecificGuard {
>SpecificGuard : SpecificGuard
isMoreSpecific: this is MoreSpecificGuard;
>isMoreSpecific : this is MoreSpecificGuard
>MoreSpecificGuard : MoreSpecificGuard
}
interface MoreSpecificGuard extends SpecificGuard {
>MoreSpecificGuard : MoreSpecificGuard
>SpecificGuard : SpecificGuard
do(): void;
>do : () => void
}
let general: SpecificGuard;
>general : SpecificGuard
>SpecificGuard : SpecificGuard
if (general.isMoreSpecific) {
>general.isMoreSpecific : this is MoreSpecificGuard
>general : SpecificGuard
>isMoreSpecific : this is MoreSpecificGuard
general.do();
>general.do() : void
>general.do : () => void
>general : MoreSpecificGuard
>do : () => void
}
}

View file

@ -0,0 +1,51 @@
tests/cases/conformance/expressions/typeGuards/typeGuardOfFormThisMemberErrors.ts(29,2): error TS1226: Type predicate 'this is File' is not assignable to 'this is Networked & FileSystemObject'.
Type 'File' is not assignable to type 'Networked & FileSystemObject'.
Type 'File' is not assignable to type 'Networked'.
Property 'host' is missing in type 'File'.
tests/cases/conformance/expressions/typeGuards/typeGuardOfFormThisMemberErrors.ts(31,2): error TS1226: Type predicate 'this is FileSystemObject' is not assignable to 'this is File'.
Type 'FileSystemObject' is not assignable to type 'File'.
Property 'content' is missing in type 'FileSystemObject'.
==== tests/cases/conformance/expressions/typeGuards/typeGuardOfFormThisMemberErrors.ts (2 errors) ====
// There's a 'File' class in the stdlib, wrap with a namespace to avoid collision
namespace Test {
export class FileSystemObject {
isFSO: this is FileSystemObject;
get isFile(): this is File {
return this instanceof File;
}
set isFile(param) {
// noop
}
get isDirectory(): this is Directory {
return this instanceof Directory;
}
isNetworked: this is (Networked & this);
constructor(public path: string) {}
}
export class File extends FileSystemObject {
constructor(path: string, public content: string) { super(path); }
}
export class Directory extends FileSystemObject {
children: FileSystemObject[];
}
export interface Networked {
host: string;
}
let file: FileSystemObject = new File("foo/bar.txt", "foo");
file.isNetworked = file.isFile;
~~~~~~~~~~~~~~~~
!!! error TS1226: Type predicate 'this is File' is not assignable to 'this is Networked & FileSystemObject'.
!!! error TS1226: Type 'File' is not assignable to type 'Networked & FileSystemObject'.
!!! error TS1226: Type 'File' is not assignable to type 'Networked'.
!!! error TS1226: Property 'host' is missing in type 'File'.
file.isFSO = file.isNetworked;
file.isFile = file.isFSO;
~~~~~~~~~~~
!!! error TS1226: Type predicate 'this is FileSystemObject' is not assignable to 'this is File'.
!!! error TS1226: Type 'FileSystemObject' is not assignable to type 'File'.
!!! error TS1226: Property 'content' is missing in type 'FileSystemObject'.
}

View file

@ -0,0 +1,112 @@
//// [typeGuardOfFormThisMemberErrors.ts]
// There's a 'File' class in the stdlib, wrap with a namespace to avoid collision
namespace Test {
export class FileSystemObject {
isFSO: this is FileSystemObject;
get isFile(): this is File {
return this instanceof File;
}
set isFile(param) {
// noop
}
get isDirectory(): this is Directory {
return this instanceof Directory;
}
isNetworked: this is (Networked & this);
constructor(public path: string) {}
}
export class File extends FileSystemObject {
constructor(path: string, public content: string) { super(path); }
}
export class Directory extends FileSystemObject {
children: FileSystemObject[];
}
export interface Networked {
host: string;
}
let file: FileSystemObject = new File("foo/bar.txt", "foo");
file.isNetworked = file.isFile;
file.isFSO = file.isNetworked;
file.isFile = file.isFSO;
}
//// [typeGuardOfFormThisMemberErrors.js]
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
// There's a 'File' class in the stdlib, wrap with a namespace to avoid collision
var Test;
(function (Test) {
var FileSystemObject = (function () {
function FileSystemObject(path) {
this.path = path;
}
Object.defineProperty(FileSystemObject.prototype, "isFile", {
get: function () {
return this instanceof File;
},
set: function (param) {
// noop
},
enumerable: true,
configurable: true
});
Object.defineProperty(FileSystemObject.prototype, "isDirectory", {
get: function () {
return this instanceof Directory;
},
enumerable: true,
configurable: true
});
return FileSystemObject;
}());
Test.FileSystemObject = FileSystemObject;
var File = (function (_super) {
__extends(File, _super);
function File(path, content) {
_super.call(this, path);
this.content = content;
}
return File;
}(FileSystemObject));
Test.File = File;
var Directory = (function (_super) {
__extends(Directory, _super);
function Directory() {
_super.apply(this, arguments);
}
return Directory;
}(FileSystemObject));
Test.Directory = Directory;
var file = new File("foo/bar.txt", "foo");
file.isNetworked = file.isFile;
file.isFSO = file.isNetworked;
file.isFile = file.isFSO;
})(Test || (Test = {}));
//// [typeGuardOfFormThisMemberErrors.d.ts]
declare namespace Test {
class FileSystemObject {
path: string;
isFSO: this is FileSystemObject;
isFile: this is File;
isDirectory: this is Directory;
isNetworked: this is (Networked & this);
constructor(path: string);
}
class File extends FileSystemObject {
content: string;
constructor(path: string, content: string);
}
class Directory extends FileSystemObject {
children: FileSystemObject[];
}
interface Networked {
host: string;
}
}

View file

@ -110,7 +110,7 @@ function foo1<a>(value: void|a): void {
>a : a
if (isVoid(value)) {
>isVoid(value) : boolean
>isVoid(value) : value is void
>isVoid : <a>(value: void | a) => value is void
>value : void | a
@ -130,7 +130,7 @@ function baz1<a>(value: void|a): void {
>a : a
if (isNonVoid(value)) {
>isNonVoid(value) : boolean
>isNonVoid(value) : value is a
>isNonVoid : <a>(value: void | a) => value is a
>value : void | a

View file

@ -0,0 +1,141 @@
// @declaration: true
class RoyalGuard {
isLeader(): this is LeadGuard {
return this instanceof LeadGuard;
}
isFollower(): this is FollowerGuard {
return this instanceof FollowerGuard;
}
}
class LeadGuard extends RoyalGuard {
lead(): void {};
}
class FollowerGuard extends RoyalGuard {
follow(): void {};
}
let a: RoyalGuard = new FollowerGuard();
if (a.isLeader()) {
a.lead();
}
else if (a.isFollower()) {
a.follow();
}
interface GuardInterface extends RoyalGuard {}
let b: GuardInterface;
if (b.isLeader()) {
b.lead();
}
else if (b.isFollower()) {
b.follow();
}
if (((a.isLeader)())) {
a.lead();
}
else if (((a).isFollower())) {
a.follow();
}
if (((a["isLeader"])())) {
a.lead();
}
else if (((a)["isFollower"]())) {
a.follow();
}
var holder2 = {a};
if (holder2.a.isLeader()) {
holder2.a;
}
else {
holder2.a;
}
class ArrowGuard {
isElite = (): this is ArrowElite => {
return this instanceof ArrowElite;
}
isMedic = (): this is ArrowMedic => {
return this instanceof ArrowMedic;
}
}
class ArrowElite extends ArrowGuard {
defend(): void {}
}
class ArrowMedic extends ArrowGuard {
heal(): void {}
}
let guard = new ArrowGuard();
if (guard.isElite()) {
guard.defend();
}
else if (guard.isMedic()) {
guard.heal();
}
interface Supplies {
spoiled: boolean;
}
interface Sundries {
broken: boolean;
}
interface Crate<T> {
contents: T;
volume: number;
isSupplies(): this is Crate<Supplies>;
isSundries(): this is Crate<Sundries>;
}
let crate: Crate<{}>;
if (crate.isSundries()) {
crate.contents.broken = true;
}
else if (crate.isSupplies()) {
crate.contents.spoiled = true;
}
// Matching guards should be assignable
a.isFollower = b.isFollower;
a.isLeader = b.isLeader;
class MimicGuard {
isLeader(): this is MimicLeader { return this instanceof MimicLeader; };
isFollower(): this is MimicFollower { return this instanceof MimicFollower; };
}
class MimicLeader extends MimicGuard {
lead(): void {}
}
class MimicFollower extends MimicGuard {
follow(): void {}
}
let mimic = new MimicGuard();
a.isLeader = mimic.isLeader;
a.isFollower = mimic.isFollower;
if (mimic.isFollower()) {
mimic.follow();
mimic.isFollower = a.isFollower;
}
interface MimicGuardInterface {
isLeader(): this is LeadGuard;
isFollower(): this is FollowerGuard;
}

View file

@ -0,0 +1,60 @@
// @declaration: true
class RoyalGuard {
isLeader(): this is LeadGuard {
return this instanceof LeadGuard;
}
isFollower(): this is FollowerGuard {
return this instanceof FollowerGuard;
}
}
class LeadGuard extends RoyalGuard {
lead(): void {};
}
class FollowerGuard extends RoyalGuard {
follow(): void {};
}
interface GuardInterface extends RoyalGuard {}
let a: RoyalGuard = new FollowerGuard();
let b: GuardInterface = new LeadGuard();
// Mismatched guards shouldn't be assignable
b.isFollower = b.isLeader;
b.isLeader = b.isFollower;
a.isFollower = a.isLeader;
a.isLeader = a.isFollower;
function invalidGuard(c: any): this is number {
return false;
}
let c: number | number[];
if (invalidGuard(c)) {
c;
}
else {
c;
}
let holder = {invalidGuard};
if (holder.invalidGuard(c)) {
c;
holder;
}
else {
c;
holder;
}
let detached = a.isFollower;
if (detached()) {
a.follow();
}
else {
a.lead();
}

View file

@ -0,0 +1,83 @@
// @target: es5
// @declaration: true
// There's a 'File' class in the stdlib, wrap with a namespace to avoid collision
namespace Test {
export class FileSystemObject {
isFSO: this is FileSystemObject;
get isFile(): this is File {
return this instanceof File;
}
set isFile(param) {
// noop
}
get isDirectory(): this is Directory {
return this instanceof Directory;
}
isNetworked: this is (Networked & this);
constructor(public path: string) {}
}
export class File extends FileSystemObject {
constructor(path: string, public content: string) { super(path); }
}
export class Directory extends FileSystemObject {
children: FileSystemObject[];
}
export interface Networked {
host: string;
}
let file: FileSystemObject = new File("foo/bar.txt", "foo");
file.isNetworked = false;
file.isFSO = file.isFile;
file.isFile = true;
let x = file.isFile;
if (file.isFile) {
file.content;
if (file.isNetworked) {
file.host;
file.content;
}
}
else if (file.isDirectory) {
file.children;
}
else if (file.isNetworked) {
file.host;
}
interface GenericLeadGuard<T> extends GenericGuard<T> {
lead(): void;
}
interface GenericFollowerGuard<T> extends GenericGuard<T> {
follow(): void;
}
interface GenericGuard<T> {
target: T;
isLeader: this is (GenericLeadGuard<T>);
isFollower: this is GenericFollowerGuard<T>;
}
let guard: GenericGuard<File>;
if (guard.isLeader) {
guard.lead();
}
else if (guard.isFollower) {
guard.follow();
}
interface SpecificGuard {
isMoreSpecific: this is MoreSpecificGuard;
}
interface MoreSpecificGuard extends SpecificGuard {
do(): void;
}
let general: SpecificGuard;
if (general.isMoreSpecific) {
general.do();
}
}

View file

@ -0,0 +1,34 @@
// @target: es5
// @declaration: true
// There's a 'File' class in the stdlib, wrap with a namespace to avoid collision
namespace Test {
export class FileSystemObject {
isFSO: this is FileSystemObject;
get isFile(): this is File {
return this instanceof File;
}
set isFile(param) {
// noop
}
get isDirectory(): this is Directory {
return this instanceof Directory;
}
isNetworked: this is (Networked & this);
constructor(public path: string) {}
}
export class File extends FileSystemObject {
constructor(path: string, public content: string) { super(path); }
}
export class Directory extends FileSystemObject {
children: FileSystemObject[];
}
export interface Networked {
host: string;
}
let file: FileSystemObject = new File("foo/bar.txt", "foo");
file.isNetworked = file.isFile;
file.isFSO = file.isNetworked;
file.isFile = file.isFSO;
}