Skip to content

Commit 0599f84

Browse files
committed
Support 'asserts this' and 'asserts this is T' type predicates
1 parent 9791f1d commit 0599f84

File tree

3 files changed

+31
-21
lines changed

3 files changed

+31
-21
lines changed

src/compiler/checker.ts

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4228,8 +4228,10 @@ namespace ts {
42284228
let returnTypeNode: TypeNode | undefined;
42294229
const typePredicate = getTypePredicateOfSignature(signature);
42304230
if (typePredicate) {
4231-
const assertsModifier = typePredicate.kind === TypePredicateKind.Assertion ? createToken(SyntaxKind.AssertsKeyword) : undefined;
4232-
const parameterName = typePredicate.kind !== TypePredicateKind.This ?
4231+
const assertsModifier = typePredicate.kind === TypePredicateKind.AssertsThis || typePredicate.kind === TypePredicateKind.AssertsIdentifier ?
4232+
createToken(SyntaxKind.AssertsKeyword) :
4233+
undefined;
4234+
const parameterName = typePredicate.kind === TypePredicateKind.Identifier || typePredicate.kind === TypePredicateKind.AssertsIdentifier ?
42334235
setEmitFlags(createIdentifier(typePredicate.parameterName), EmitFlags.NoAsciiEscaping) :
42344236
createThisTypeNode();
42354237
const typeNode = typePredicate.type && typeToTypeNodeHelper(typePredicate.type, context);
@@ -4702,8 +4704,8 @@ namespace ts {
47024704

47034705
function typePredicateToStringWorker(writer: EmitTextWriter) {
47044706
const predicate = createTypePredicateNode(
4705-
typePredicate.kind === TypePredicateKind.Assertion ? createToken(SyntaxKind.AssertsKeyword) : undefined,
4706-
typePredicate.kind !== TypePredicateKind.This ? createIdentifier(typePredicate.parameterName) : createThisTypeNode(),
4707+
typePredicate.kind === TypePredicateKind.AssertsThis || typePredicate.kind === TypePredicateKind.AssertsIdentifier ? createToken(SyntaxKind.AssertsKeyword) : undefined,
4708+
typePredicate.kind === TypePredicateKind.Identifier || typePredicate.kind === TypePredicateKind.AssertsIdentifier ? createIdentifier(typePredicate.parameterName) : createThisTypeNode(),
47074709
typePredicate.type && nodeBuilder.typeToTypeNode(typePredicate.type, enclosingDeclaration, toNodeBuilderFlags(flags) | NodeBuilderFlags.IgnoreErrors | NodeBuilderFlags.WriteTypeParametersInQualifiedName)! // TODO: GH#18217
47084710
);
47094711
const printer = createPrinter({ removeComments: true });
@@ -8721,8 +8723,8 @@ namespace ts {
87218723
const parameterName = node.parameterName;
87228724
const type = node.type && getTypeFromTypeNode(node.type);
87238725
return parameterName.kind === SyntaxKind.ThisType ?
8724-
createTypePredicate(TypePredicateKind.This, /*parameterName*/ undefined, /*parameterIndex*/ undefined, type) :
8725-
createTypePredicate(node.assertsModifier ? TypePredicateKind.Assertion : TypePredicateKind.Identifier, parameterName.escapedText as string,
8726+
createTypePredicate(node.assertsModifier ? TypePredicateKind.AssertsThis : TypePredicateKind.This, /*parameterName*/ undefined, /*parameterIndex*/ undefined, type) :
8727+
createTypePredicate(node.assertsModifier ? TypePredicateKind.AssertsIdentifier : TypePredicateKind.Identifier, parameterName.escapedText as string,
87268728
findIndex(signature.parameters, p => p.escapedName === parameterName.escapedText), type);
87278729
}
87288730

@@ -9829,7 +9831,7 @@ namespace ts {
98299831
const types: Type[] = [];
98309832
for (const sig of signatures) {
98319833
const pred = getTypePredicateOfSignature(sig);
9832-
if (!pred || pred.kind === TypePredicateKind.Assertion) {
9834+
if (!pred || pred.kind === TypePredicateKind.AssertsThis || pred.kind === TypePredicateKind.AssertsIdentifier) {
98339835
continue;
98349836
}
98359837

@@ -12400,7 +12402,7 @@ namespace ts {
1240012402
return Ternary.False;
1240112403
}
1240212404

12403-
if (source.kind !== TypePredicateKind.This) {
12405+
if (source.kind === TypePredicateKind.Identifier || source.kind === TypePredicateKind.AssertsIdentifier) {
1240412406
if (source.parameterIndex !== (target as IdentifierTypePredicate).parameterIndex) {
1240512407
if (reportErrors) {
1240612408
errorReporter!(Diagnostics.Parameter_0_is_not_in_the_same_position_as_parameter_1, source.parameterName, (target as IdentifierTypePredicate).parameterName);
@@ -17119,12 +17121,12 @@ namespace ts {
1711917121
const signature = getEffectsSignature(flow.node);
1712017122
if (signature) {
1712117123
const predicate = getTypePredicateOfSignature(signature);
17122-
if (predicate && predicate.kind === TypePredicateKind.Assertion) {
17124+
if (predicate && (predicate.kind === TypePredicateKind.AssertsThis || predicate.kind === TypePredicateKind.AssertsIdentifier)) {
1712317125
const flowType = getTypeAtFlowNode(flow.antecedent);
1712417126
const type = getTypeFromFlowType(flowType);
17125-
const narrowedType = predicate.type ?
17126-
narrowTypeByTypePredicate(type, predicate, flow.node, /*assumeTrue*/ true) :
17127-
narrowTypeByAssertion(type, flow.node.arguments[predicate.parameterIndex]);
17127+
const narrowedType = predicate.type ? narrowTypeByTypePredicate(type, predicate, flow.node, /*assumeTrue*/ true) :
17128+
predicate.kind === TypePredicateKind.AssertsIdentifier ? narrowTypeByAssertion(type, flow.node.arguments[predicate.parameterIndex]) :
17129+
type;
1712817130
return narrowedType === type ? flowType : createFlowType(narrowedType, isIncomplete(flowType));
1712917131
}
1713017132
if (getReturnTypeOfSignature(signature).flags & TypeFlags.Never) {
@@ -17721,7 +17723,7 @@ namespace ts {
1772117723
if (hasMatchingArgument(callExpression, reference)) {
1772217724
const signature = getEffectsSignature(callExpression);
1772317725
const predicate = signature && getTypePredicateOfSignature(signature);
17724-
if (predicate && predicate.kind !== TypePredicateKind.Assertion) {
17726+
if (predicate && (predicate.kind === TypePredicateKind.This || predicate.kind === TypePredicateKind.Identifier)) {
1772517727
return narrowTypeByTypePredicate(type, predicate, callExpression, assumeTrue);
1772617728
}
1772717729
}
@@ -17733,7 +17735,7 @@ namespace ts {
1773317735
if (isTypeAny(type) && (predicate.type === globalObjectType || predicate.type === globalFunctionType)) {
1773417736
return type;
1773517737
}
17736-
if (predicate.kind !== TypePredicateKind.This) {
17738+
if (predicate.kind === TypePredicateKind.Identifier || predicate.kind === TypePredicateKind.AssertsIdentifier) {
1773717739
const predicateArgument = callExpression.arguments[predicate.parameterIndex];
1773817740
if (predicateArgument && predicate.type) {
1773917741
if (isMatchingReference(reference, predicateArgument)) {
@@ -17746,7 +17748,7 @@ namespace ts {
1774617748
}
1774717749
else {
1774817750
const invokedExpression = skipParentheses(callExpression.expression);
17749-
if (isAccessExpression(invokedExpression)) {
17751+
if (isAccessExpression(invokedExpression) && predicate.type) {
1775017752
const possibleReference = skipParentheses(invokedExpression.expression);
1775117753
if (isMatchingReference(reference, possibleReference)) {
1775217754
return getNarrowedType(type, predicate.type, assumeTrue, isTypeSubtypeOf);
@@ -25501,7 +25503,7 @@ namespace ts {
2550125503
checkSourceElement(node.type);
2550225504

2550325505
const { parameterName } = node;
25504-
if (isThisTypePredicate(typePredicate)) {
25506+
if (typePredicate.kind === TypePredicateKind.This || typePredicate.kind === TypePredicateKind.AssertsThis) {
2550525507
getTypeFromThisTypeNode(parameterName as ThisTypeNode);
2550625508
}
2550725509
else {

src/compiler/parser.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3258,7 +3258,7 @@ namespace ts {
32583258
function parseAssertsTypePredicate(): TypeNode {
32593259
const node = <TypePredicateNode>createNode(SyntaxKind.TypePredicate);
32603260
node.assertsModifier = parseExpectedToken(SyntaxKind.AssertsKeyword);
3261-
node.parameterName = parseIdentifier();
3261+
node.parameterName = token() === SyntaxKind.ThisKeyword ? parseThisTypeNode() : parseIdentifier();
32623262
node.type = parseOptional(SyntaxKind.IsKeyword) ? parseType() : undefined;
32633263
return finishNode(node);
32643264
}

src/compiler/types.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3514,7 +3514,8 @@ namespace ts {
35143514
export const enum TypePredicateKind {
35153515
This,
35163516
Identifier,
3517-
Assertion
3517+
AssertsThis,
3518+
AssertsIdentifier
35183519
}
35193520

35203521
export interface ThisTypePredicate {
@@ -3531,14 +3532,21 @@ namespace ts {
35313532
type: Type;
35323533
}
35333534

3534-
export interface AssertionTypePredicate {
3535-
kind: TypePredicateKind.Assertion;
3535+
export interface AssertsThisTypePredicate {
3536+
kind: TypePredicateKind.AssertsThis;
3537+
parameterName: undefined;
3538+
parameterIndex: undefined;
3539+
type: Type | undefined;
3540+
}
3541+
3542+
export interface AssertsIdentifierTypePredicate {
3543+
kind: TypePredicateKind.AssertsIdentifier;
35363544
parameterName: string;
35373545
parameterIndex: number;
35383546
type: Type | undefined;
35393547
}
35403548

3541-
export type TypePredicate = ThisTypePredicate | IdentifierTypePredicate | AssertionTypePredicate;
3549+
export type TypePredicate = ThisTypePredicate | IdentifierTypePredicate | AssertsThisTypePredicate | AssertsIdentifierTypePredicate;
35423550

35433551
/* @internal */
35443552
export type AnyImportSyntax = ImportDeclaration | ImportEqualsDeclaration;

0 commit comments

Comments
 (0)