Skip to content

Commit 7340c4c

Browse files
author
Arthur Ozga
committed
type predicate support
1 parent a39bb0a commit 7340c4c

File tree

9 files changed

+93
-68
lines changed

9 files changed

+93
-68
lines changed

src/compiler/checker.ts

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2610,18 +2610,27 @@ namespace ts {
26102610
/*initializer*/ undefined);
26112611
const typeNode = typeToTypeNodeHelper(indexInfo.type);
26122612
return createIndexSignatureDeclaration(
2613-
[indexingParameter],
2614-
typeNode,
26152613
/*decorators*/ undefined,
2616-
indexInfo.isReadonly ? [createToken(SyntaxKind.ReadonlyKeyword)] : undefined);
2614+
indexInfo.isReadonly ? [createToken(SyntaxKind.ReadonlyKeyword)] : undefined,
2615+
[indexingParameter],
2616+
typeNode);
26172617
}
26182618

26192619
function signatureToSignatureDeclarationHelper(signature: Signature, kind: SyntaxKind): SignatureDeclaration {
26202620

26212621
const typeParameters = signature.typeParameters && signature.typeParameters.map(parameter => typeParameterToDeclaration(parameter));
26222622
const parameters = signature.parameters.map(parameter => symbolToParameterDeclaration(parameter));
2623-
const returnType = getReturnTypeOfSignature(signature);
2624-
const returnTypeNode = returnType && typeToTypeNodeHelper(returnType);
2623+
let returnTypeNode: TypeNode | TypePredicate;
2624+
if (signature.typePredicate) {
2625+
const typePredicate = signature.typePredicate;
2626+
const parameterName = typePredicate.kind === TypePredicateKind.Identifier ? createIdentifier((<IdentifierTypePredicate>typePredicate).parameterName) : createThisTypeNode();
2627+
const typeNode = typeToTypeNodeHelper(typePredicate.type);
2628+
returnTypeNode = createTypePredicateNode(parameterName, typeNode);
2629+
}
2630+
else {
2631+
const returnType = getReturnTypeOfSignature(signature);
2632+
returnTypeNode = returnType && typeToTypeNodeHelper(returnType);
2633+
}
26252634
const returnTypeNodeExceptAny = returnTypeNode && returnTypeNode.kind !== SyntaxKind.AnyKeyword ? returnTypeNode : undefined;
26262635

26272636
return createSignatureDeclaration(kind, typeParameters, parameters, returnTypeNodeExceptAny);

src/compiler/factory.ts

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,10 @@ namespace ts {
286286
return <KeywordTypeNode>createSynthesizedNode(kind);
287287
}
288288

289+
export function createThisTypeNode() {
290+
return <ThisTypeNode>createSynthesizedNode(SyntaxKind.ThisType);
291+
}
292+
289293
export function createLiteralTypeNode(literal: Expression) {
290294
const literalTypeNode = createSynthesizedNode(SyntaxKind.LiteralType) as LiteralTypeNode;
291295
literalTypeNode.literal = literal;
@@ -312,6 +316,20 @@ namespace ts {
312316
: node;
313317
}
314318

319+
export function createTypePredicateNode(parameterName: Identifier | ThisTypeNode | string, type: TypeNode) {
320+
const typePredicateNode = createSynthesizedNode(SyntaxKind.TypePredicate) as TypePredicateNode;
321+
typePredicateNode.parameterName = asName(parameterName);
322+
typePredicateNode.type = type;
323+
return typePredicateNode;
324+
}
325+
326+
export function updateTypePredicateNode(node: TypePredicateNode, parameterName: Identifier | ThisTypeNode, type: TypeNode) {
327+
return node.parameterName !== parameterName
328+
|| node.type !== type
329+
? updateNode(createTypePredicateNode(parameterName, type), node)
330+
: node;
331+
}
332+
315333
export function createTypeQueryNode(exprName: EntityName) {
316334
const typeQueryNode = createSynthesizedNode(SyntaxKind.TypeQuery) as TypeQueryNode;
317335
typeQueryNode.exprName = exprName;
@@ -455,21 +473,21 @@ namespace ts {
455473
: node;
456474
}
457475

458-
export function createIndexSignatureDeclaration(parameters: ParameterDeclaration[], type: TypeNode, decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined): IndexSignatureDeclaration {
476+
export function createIndexSignatureDeclaration(decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, parameters: ParameterDeclaration[], type: TypeNode): IndexSignatureDeclaration {
459477
const indexSignature = createSynthesizedNode(SyntaxKind.IndexSignature) as IndexSignatureDeclaration;
460-
indexSignature.parameters = asNodeArray(parameters);
461-
indexSignature.type = type;
462478
indexSignature.decorators = asNodeArray(decorators);
463479
indexSignature.modifiers = asNodeArray(modifiers);
480+
indexSignature.parameters = createNodeArray(parameters);
481+
indexSignature.type = type;
464482
return indexSignature;
465483
}
466484

467-
export function updateIndexSignatureDeclaration(node: IndexSignatureDeclaration, parameters: ParameterDeclaration[], type: TypeNode, decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined) {
485+
export function updateIndexSignatureDeclaration(node: IndexSignatureDeclaration, decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, parameters: ParameterDeclaration[], type: TypeNode) {
468486
return node.parameters !== parameters
469487
|| node.type !== type
470488
|| node.decorators !== decorators
471489
|| node.modifiers !== modifiers
472-
? updateNode(createIndexSignatureDeclaration(parameters, type, decorators, modifiers), node)
490+
? updateNode(createIndexSignatureDeclaration(decorators, modifiers, parameters, type), node)
473491
: node;
474492
}
475493

@@ -542,7 +560,7 @@ namespace ts {
542560
node.name = asName(name);
543561
node.questionToken = questionToken;
544562
node.typeParameters = asNodeArray(typeParameters);
545-
node.parameters = asNodeArray(parameters);
563+
node.parameters = createNodeArray(parameters);
546564
node.type = type;
547565
node.body = body;
548566
return node;
@@ -2052,15 +2070,16 @@ namespace ts {
20522070
function asName(name: string | BindingName): BindingName;
20532071
function asName(name: string | PropertyName): PropertyName;
20542072
function asName(name: string | EntityName): EntityName;
2055-
function asName(name: string | Identifier | BindingName | PropertyName | QualifiedName) {
2073+
function asName(name: string | Identifier | ThisTypeNode): Identifier | ThisTypeNode;
2074+
function asName(name: string | Identifier | BindingName | PropertyName | QualifiedName | ThisTypeNode) {
20562075
return typeof name === "string" ? createIdentifier(name) : name;
20572076
}
20582077

20592078
function asExpression(value: string | number | Expression) {
20602079
return typeof value === "string" || typeof value === "number" ? createLiteral(value) : value;
20612080
}
20622081

2063-
export function asNodeArray<T extends Node>(array: T[] | undefined): NodeArray<T> | undefined {
2082+
function asNodeArray<T extends Node>(array: T[] | undefined): NodeArray<T> | undefined {
20642083
return array ? createNodeArray(array) : undefined;
20652084
}
20662085

src/compiler/types.ts

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1042,7 +1042,7 @@ namespace ts {
10421042
kind: SyntaxKind.TrueKeyword | SyntaxKind.FalseKeyword;
10431043
}
10441044

1045-
export interface ThisExpression extends PrimaryExpression, TypeNode {
1045+
export interface ThisExpression extends PrimaryExpression, KeywordTypeNode {
10461046
kind: SyntaxKind.ThisKeyword;
10471047
}
10481048

@@ -3248,12 +3248,6 @@ namespace ts {
32483248
declaration?: SignatureDeclaration;
32493249
}
32503250

3251-
export interface SignatureParts {
3252-
typeParameters: TypeParameterDeclaration[] | undefined;
3253-
parameters: ParameterDeclaration[];
3254-
type: TypeNode;
3255-
}
3256-
32573251
/* @internal */
32583252
export interface TypeMapper {
32593253
(t: TypeParameter): Type;

src/compiler/utilities.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3735,7 +3735,7 @@ namespace ts {
37353735
* of a TypeNode.
37363736
*/
37373737
export function isTypeNode(node: Node): node is TypeNode {
3738-
return node && isTypeNodeKind(node.kind);
3738+
return isTypeNodeKind(node.kind);
37393739
}
37403740

37413741
// Binding patterns

src/compiler/visitor.ts

Lines changed: 11 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,6 @@
33
/// <reference path="utilities.ts" />
44

55
namespace ts {
6-
export const nullTransformationContext: TransformationContext = {
7-
enableEmitNotification: noop,
8-
enableSubstitution: noop,
9-
endLexicalEnvironment: () => undefined,
10-
getCompilerOptions: notImplemented,
11-
getEmitHost: notImplemented,
12-
getEmitResolver: notImplemented,
13-
hoistFunctionDeclaration: noop,
14-
hoistVariableDeclaration: noop,
15-
isEmitNotificationEnabled: notImplemented,
16-
isSubstitutionEnabled: notImplemented,
17-
onEmitNode: noop,
18-
onSubstituteNode: notImplemented,
19-
readEmitHelpers: notImplemented,
20-
requestEmitHelper: noop,
21-
resumeLexicalEnvironment: noop,
22-
startLexicalEnvironment: noop,
23-
suspendLexicalEnvironment: noop
24-
};
25-
266
/**
277
* Visits a Node using the supplied visitor, possibly returning a new Node in its place.
288
*
@@ -234,7 +214,7 @@ namespace ts {
234214
const kind = node.kind;
235215

236216
// No need to visit nodes with no children.
237-
if ((kind > SyntaxKind.FirstToken && kind <= SyntaxKind.LastToken)) {
217+
if ((kind > SyntaxKind.FirstToken && kind <= SyntaxKind.LastToken) || kind === SyntaxKind.ThisType) {
238218
return node;
239219
}
240220

@@ -293,10 +273,10 @@ namespace ts {
293273

294274
case SyntaxKind.IndexSignature:
295275
return updateIndexSignatureDeclaration(<IndexSignatureDeclaration>node,
296-
visitParameterList((<IndexSignatureDeclaration>node).parameters, visitor, context, nodesVisitor),
297-
visitNode((<IndexSignatureDeclaration>node).type, visitor, isTypeNode),
298276
nodesVisitor((<IndexSignatureDeclaration>node).decorators, visitor, isDecorator),
299-
nodesVisitor((<IndexSignatureDeclaration>node).modifiers, visitor, isModifier));
277+
nodesVisitor((<IndexSignatureDeclaration>node).modifiers, visitor, isModifier),
278+
visitParameterList((<IndexSignatureDeclaration>node).parameters, visitor, context, nodesVisitor),
279+
visitNode((<IndexSignatureDeclaration>node).type, visitor, isTypeNode));
300280

301281
case SyntaxKind.Parameter:
302282
return updateParameter(<ParameterDeclaration>node,
@@ -314,13 +294,16 @@ namespace ts {
314294

315295
// Types
316296

317-
case SyntaxKind.TypePredicate:
318-
throw new Error("reached unsupported type in visitor.");
319297
case SyntaxKind.TypeReference:
320298
return updateTypeReferenceNode(<TypeReferenceNode>node,
321299
visitNode((<TypeReferenceNode>node).typeName, visitor, isEntityName),
322300
nodesVisitor((<TypeReferenceNode>node).typeArguments, visitor, isTypeNode));
323301

302+
case SyntaxKind.TypePredicate:
303+
return updateTypePredicateNode(<TypePredicateNode>node,
304+
visitNode((<TypePredicateNode>node).parameterName, visitor),
305+
visitNode((<TypePredicateNode>node).type, visitor, isTypeNode));
306+
324307
case SyntaxKind.TypeQuery:
325308
return updateTypeQueryNode((<TypeQueryNode>node), visitNode((<TypeQueryNode>node).exprName, visitor, isEntityName));
326309

@@ -339,9 +322,8 @@ namespace ts {
339322
nodesVisitor((<UnionOrIntersectionTypeNode>node).types, visitor, isTypeNode));
340323

341324
case SyntaxKind.ParenthesizedType:
342-
throw new Error("reached unsupported type in visitor.");
343-
case SyntaxKind.ThisType:
344-
throw new Error("reached unsupported type in visitor.");
325+
Debug.fail("not implemented.");
326+
345327
case SyntaxKind.TypeOperator:
346328
return updateTypeOperatorNode(<TypeOperatorNode>node, visitNode((<TypeOperatorNode>node).type, visitor, isTypeNode));
347329
case SyntaxKind.IndexedAccessType:
@@ -376,13 +358,6 @@ namespace ts {
376358
visitNode((<PropertySignature>node).type, visitor, isTypeNode),
377359
visitNode((<PropertySignature>node).initializer, visitor, isExpression));
378360

379-
case SyntaxKind.IndexSignature:
380-
return updateIndexSignatureDeclaration(<IndexSignatureDeclaration>node,
381-
visitParameterList((<IndexSignatureDeclaration>node).parameters, visitor, context, nodesVisitor),
382-
visitNode((<IndexSignatureDeclaration>node).type, visitor, isTypeNode),
383-
nodesVisitor((<IndexSignatureDeclaration>node).decorators, visitor, isDecorator),
384-
nodesVisitor((<IndexSignatureDeclaration>node).modifiers, visitor, isModifier));
385-
386361
case SyntaxKind.PropertyDeclaration:
387362
return updateProperty(<PropertyDeclaration>node,
388363
nodesVisitor((<PropertyDeclaration>node).decorators, visitor, isDecorator),

src/services/codefixes/fixAddMissingMember.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,10 @@ namespace ts.codefix {
6565
stringTypeNode,
6666
/*initializer*/ undefined);
6767
const indexSignature = createIndexSignatureDeclaration(
68-
[indexingParameter],
69-
typeNode,
7068
/*decorators*/undefined,
71-
/*modifiers*/ undefined);
69+
/*modifiers*/ undefined,
70+
[indexingParameter],
71+
typeNode);
7272

7373
const indexSignatureChangeTracker = textChanges.ChangeTracker.fromCodeFixContext(context);
7474
indexSignatureChangeTracker.insertNodeAfter(sourceFile, openBrace, indexSignature, { suffix: context.newLineCharacter });

src/services/codefixes/helpers.ts

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -230,12 +230,4 @@ namespace ts.codefix {
230230
}
231231
return undefined;
232232
}
233-
234-
function stripComments(node: Node): Node {
235-
if (node === undefined) {
236-
return node;
237-
}
238-
const strippedChildren = visitEachChild(node, stripComments, nullTransformationContext);
239-
return strippedChildren === node ? getSynthesizedClone(strippedChildren) : strippedChildren;
240-
}
241233
}

src/services/textChanges.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -528,6 +528,26 @@ namespace ts.textChanges {
528528
return skipTrivia(s, 0) === s.length;
529529
}
530530

531+
const nullTransformationContext: TransformationContext = {
532+
enableEmitNotification: noop,
533+
enableSubstitution: noop,
534+
endLexicalEnvironment: () => undefined,
535+
getCompilerOptions: notImplemented,
536+
getEmitHost: notImplemented,
537+
getEmitResolver: notImplemented,
538+
hoistFunctionDeclaration: noop,
539+
hoistVariableDeclaration: noop,
540+
isEmitNotificationEnabled: notImplemented,
541+
isSubstitutionEnabled: notImplemented,
542+
onEmitNode: noop,
543+
onSubstituteNode: notImplemented,
544+
readEmitHelpers: notImplemented,
545+
requestEmitHelper: noop,
546+
resumeLexicalEnvironment: noop,
547+
startLexicalEnvironment: noop,
548+
suspendLexicalEnvironment: noop
549+
};
550+
531551
function assignPositionsToNode(node: Node): Node {
532552
const visited = visitEachChild(node, assignPositionsToNode, nullTransformationContext, assignPositionsToNodeArray, assignPositionsToNode);
533553
// create proxy node for non synthesized nodes
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
//// interface I {
4+
//// f(i: any): i is I;
5+
//// f(): this is I;
6+
//// }
7+
////
8+
//// class C implements I {[| |]}
9+
10+
verify.rangeAfterCodeFix(`
11+
f(i: any): i is I;
12+
f(): this is I;
13+
f(i?: any) {
14+
throw new Error("Method not implemented.");
15+
}
16+
`);

0 commit comments

Comments
 (0)