type predicate support

This commit is contained in:
Arthur Ozga 2017-03-27 11:53:44 -07:00
parent a39bb0aaaa
commit 7340c4ca1e
9 changed files with 93 additions and 68 deletions

View file

@ -2610,18 +2610,27 @@ namespace ts {
/*initializer*/ undefined); /*initializer*/ undefined);
const typeNode = typeToTypeNodeHelper(indexInfo.type); const typeNode = typeToTypeNodeHelper(indexInfo.type);
return createIndexSignatureDeclaration( return createIndexSignatureDeclaration(
[indexingParameter],
typeNode,
/*decorators*/ undefined, /*decorators*/ undefined,
indexInfo.isReadonly ? [createToken(SyntaxKind.ReadonlyKeyword)] : undefined); indexInfo.isReadonly ? [createToken(SyntaxKind.ReadonlyKeyword)] : undefined,
[indexingParameter],
typeNode);
} }
function signatureToSignatureDeclarationHelper(signature: Signature, kind: SyntaxKind): SignatureDeclaration { function signatureToSignatureDeclarationHelper(signature: Signature, kind: SyntaxKind): SignatureDeclaration {
const typeParameters = signature.typeParameters && signature.typeParameters.map(parameter => typeParameterToDeclaration(parameter)); const typeParameters = signature.typeParameters && signature.typeParameters.map(parameter => typeParameterToDeclaration(parameter));
const parameters = signature.parameters.map(parameter => symbolToParameterDeclaration(parameter)); const parameters = signature.parameters.map(parameter => symbolToParameterDeclaration(parameter));
const returnType = getReturnTypeOfSignature(signature); let returnTypeNode: TypeNode | TypePredicate;
const returnTypeNode = returnType && typeToTypeNodeHelper(returnType); if (signature.typePredicate) {
const typePredicate = signature.typePredicate;
const parameterName = typePredicate.kind === TypePredicateKind.Identifier ? createIdentifier((<IdentifierTypePredicate>typePredicate).parameterName) : createThisTypeNode();
const typeNode = typeToTypeNodeHelper(typePredicate.type);
returnTypeNode = createTypePredicateNode(parameterName, typeNode);
}
else {
const returnType = getReturnTypeOfSignature(signature);
returnTypeNode = returnType && typeToTypeNodeHelper(returnType);
}
const returnTypeNodeExceptAny = returnTypeNode && returnTypeNode.kind !== SyntaxKind.AnyKeyword ? returnTypeNode : undefined; const returnTypeNodeExceptAny = returnTypeNode && returnTypeNode.kind !== SyntaxKind.AnyKeyword ? returnTypeNode : undefined;
return createSignatureDeclaration(kind, typeParameters, parameters, returnTypeNodeExceptAny); return createSignatureDeclaration(kind, typeParameters, parameters, returnTypeNodeExceptAny);

View file

@ -286,6 +286,10 @@ namespace ts {
return <KeywordTypeNode>createSynthesizedNode(kind); return <KeywordTypeNode>createSynthesizedNode(kind);
} }
export function createThisTypeNode() {
return <ThisTypeNode>createSynthesizedNode(SyntaxKind.ThisType);
}
export function createLiteralTypeNode(literal: Expression) { export function createLiteralTypeNode(literal: Expression) {
const literalTypeNode = createSynthesizedNode(SyntaxKind.LiteralType) as LiteralTypeNode; const literalTypeNode = createSynthesizedNode(SyntaxKind.LiteralType) as LiteralTypeNode;
literalTypeNode.literal = literal; literalTypeNode.literal = literal;
@ -312,6 +316,20 @@ namespace ts {
: node; : node;
} }
export function createTypePredicateNode(parameterName: Identifier | ThisTypeNode | string, type: TypeNode) {
const typePredicateNode = createSynthesizedNode(SyntaxKind.TypePredicate) as TypePredicateNode;
typePredicateNode.parameterName = asName(parameterName);
typePredicateNode.type = type;
return typePredicateNode;
}
export function updateTypePredicateNode(node: TypePredicateNode, parameterName: Identifier | ThisTypeNode, type: TypeNode) {
return node.parameterName !== parameterName
|| node.type !== type
? updateNode(createTypePredicateNode(parameterName, type), node)
: node;
}
export function createTypeQueryNode(exprName: EntityName) { export function createTypeQueryNode(exprName: EntityName) {
const typeQueryNode = createSynthesizedNode(SyntaxKind.TypeQuery) as TypeQueryNode; const typeQueryNode = createSynthesizedNode(SyntaxKind.TypeQuery) as TypeQueryNode;
typeQueryNode.exprName = exprName; typeQueryNode.exprName = exprName;
@ -455,21 +473,21 @@ namespace ts {
: node; : node;
} }
export function createIndexSignatureDeclaration(parameters: ParameterDeclaration[], type: TypeNode, decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined): IndexSignatureDeclaration { export function createIndexSignatureDeclaration(decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, parameters: ParameterDeclaration[], type: TypeNode): IndexSignatureDeclaration {
const indexSignature = createSynthesizedNode(SyntaxKind.IndexSignature) as IndexSignatureDeclaration; const indexSignature = createSynthesizedNode(SyntaxKind.IndexSignature) as IndexSignatureDeclaration;
indexSignature.parameters = asNodeArray(parameters);
indexSignature.type = type;
indexSignature.decorators = asNodeArray(decorators); indexSignature.decorators = asNodeArray(decorators);
indexSignature.modifiers = asNodeArray(modifiers); indexSignature.modifiers = asNodeArray(modifiers);
indexSignature.parameters = createNodeArray(parameters);
indexSignature.type = type;
return indexSignature; return indexSignature;
} }
export function updateIndexSignatureDeclaration(node: IndexSignatureDeclaration, parameters: ParameterDeclaration[], type: TypeNode, decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined) { export function updateIndexSignatureDeclaration(node: IndexSignatureDeclaration, decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, parameters: ParameterDeclaration[], type: TypeNode) {
return node.parameters !== parameters return node.parameters !== parameters
|| node.type !== type || node.type !== type
|| node.decorators !== decorators || node.decorators !== decorators
|| node.modifiers !== modifiers || node.modifiers !== modifiers
? updateNode(createIndexSignatureDeclaration(parameters, type, decorators, modifiers), node) ? updateNode(createIndexSignatureDeclaration(decorators, modifiers, parameters, type), node)
: node; : node;
} }
@ -542,7 +560,7 @@ namespace ts {
node.name = asName(name); node.name = asName(name);
node.questionToken = questionToken; node.questionToken = questionToken;
node.typeParameters = asNodeArray(typeParameters); node.typeParameters = asNodeArray(typeParameters);
node.parameters = asNodeArray(parameters); node.parameters = createNodeArray(parameters);
node.type = type; node.type = type;
node.body = body; node.body = body;
return node; return node;
@ -2052,7 +2070,8 @@ namespace ts {
function asName(name: string | BindingName): BindingName; function asName(name: string | BindingName): BindingName;
function asName(name: string | PropertyName): PropertyName; function asName(name: string | PropertyName): PropertyName;
function asName(name: string | EntityName): EntityName; function asName(name: string | EntityName): EntityName;
function asName(name: string | Identifier | BindingName | PropertyName | QualifiedName) { function asName(name: string | Identifier | ThisTypeNode): Identifier | ThisTypeNode;
function asName(name: string | Identifier | BindingName | PropertyName | QualifiedName | ThisTypeNode) {
return typeof name === "string" ? createIdentifier(name) : name; return typeof name === "string" ? createIdentifier(name) : name;
} }
@ -2060,7 +2079,7 @@ namespace ts {
return typeof value === "string" || typeof value === "number" ? createLiteral(value) : value; return typeof value === "string" || typeof value === "number" ? createLiteral(value) : value;
} }
export function asNodeArray<T extends Node>(array: T[] | undefined): NodeArray<T> | undefined { function asNodeArray<T extends Node>(array: T[] | undefined): NodeArray<T> | undefined {
return array ? createNodeArray(array) : undefined; return array ? createNodeArray(array) : undefined;
} }

View file

@ -1042,7 +1042,7 @@ namespace ts {
kind: SyntaxKind.TrueKeyword | SyntaxKind.FalseKeyword; kind: SyntaxKind.TrueKeyword | SyntaxKind.FalseKeyword;
} }
export interface ThisExpression extends PrimaryExpression, TypeNode { export interface ThisExpression extends PrimaryExpression, KeywordTypeNode {
kind: SyntaxKind.ThisKeyword; kind: SyntaxKind.ThisKeyword;
} }
@ -3248,12 +3248,6 @@ namespace ts {
declaration?: SignatureDeclaration; declaration?: SignatureDeclaration;
} }
export interface SignatureParts {
typeParameters: TypeParameterDeclaration[] | undefined;
parameters: ParameterDeclaration[];
type: TypeNode;
}
/* @internal */ /* @internal */
export interface TypeMapper { export interface TypeMapper {
(t: TypeParameter): Type; (t: TypeParameter): Type;

View file

@ -3735,7 +3735,7 @@ namespace ts {
* of a TypeNode. * of a TypeNode.
*/ */
export function isTypeNode(node: Node): node is TypeNode { export function isTypeNode(node: Node): node is TypeNode {
return node && isTypeNodeKind(node.kind); return isTypeNodeKind(node.kind);
} }
// Binding patterns // Binding patterns

View file

@ -3,26 +3,6 @@
/// <reference path="utilities.ts" /> /// <reference path="utilities.ts" />
namespace ts { namespace ts {
export const nullTransformationContext: TransformationContext = {
enableEmitNotification: noop,
enableSubstitution: noop,
endLexicalEnvironment: () => undefined,
getCompilerOptions: notImplemented,
getEmitHost: notImplemented,
getEmitResolver: notImplemented,
hoistFunctionDeclaration: noop,
hoistVariableDeclaration: noop,
isEmitNotificationEnabled: notImplemented,
isSubstitutionEnabled: notImplemented,
onEmitNode: noop,
onSubstituteNode: notImplemented,
readEmitHelpers: notImplemented,
requestEmitHelper: noop,
resumeLexicalEnvironment: noop,
startLexicalEnvironment: noop,
suspendLexicalEnvironment: noop
};
/** /**
* Visits a Node using the supplied visitor, possibly returning a new Node in its place. * Visits a Node using the supplied visitor, possibly returning a new Node in its place.
* *
@ -234,7 +214,7 @@ namespace ts {
const kind = node.kind; const kind = node.kind;
// No need to visit nodes with no children. // No need to visit nodes with no children.
if ((kind > SyntaxKind.FirstToken && kind <= SyntaxKind.LastToken)) { if ((kind > SyntaxKind.FirstToken && kind <= SyntaxKind.LastToken) || kind === SyntaxKind.ThisType) {
return node; return node;
} }
@ -293,10 +273,10 @@ namespace ts {
case SyntaxKind.IndexSignature: case SyntaxKind.IndexSignature:
return updateIndexSignatureDeclaration(<IndexSignatureDeclaration>node, return updateIndexSignatureDeclaration(<IndexSignatureDeclaration>node,
visitParameterList((<IndexSignatureDeclaration>node).parameters, visitor, context, nodesVisitor),
visitNode((<IndexSignatureDeclaration>node).type, visitor, isTypeNode),
nodesVisitor((<IndexSignatureDeclaration>node).decorators, visitor, isDecorator), nodesVisitor((<IndexSignatureDeclaration>node).decorators, visitor, isDecorator),
nodesVisitor((<IndexSignatureDeclaration>node).modifiers, visitor, isModifier)); nodesVisitor((<IndexSignatureDeclaration>node).modifiers, visitor, isModifier),
visitParameterList((<IndexSignatureDeclaration>node).parameters, visitor, context, nodesVisitor),
visitNode((<IndexSignatureDeclaration>node).type, visitor, isTypeNode));
case SyntaxKind.Parameter: case SyntaxKind.Parameter:
return updateParameter(<ParameterDeclaration>node, return updateParameter(<ParameterDeclaration>node,
@ -314,13 +294,16 @@ namespace ts {
// Types // Types
case SyntaxKind.TypePredicate:
throw new Error("reached unsupported type in visitor.");
case SyntaxKind.TypeReference: case SyntaxKind.TypeReference:
return updateTypeReferenceNode(<TypeReferenceNode>node, return updateTypeReferenceNode(<TypeReferenceNode>node,
visitNode((<TypeReferenceNode>node).typeName, visitor, isEntityName), visitNode((<TypeReferenceNode>node).typeName, visitor, isEntityName),
nodesVisitor((<TypeReferenceNode>node).typeArguments, visitor, isTypeNode)); nodesVisitor((<TypeReferenceNode>node).typeArguments, visitor, isTypeNode));
case SyntaxKind.TypePredicate:
return updateTypePredicateNode(<TypePredicateNode>node,
visitNode((<TypePredicateNode>node).parameterName, visitor),
visitNode((<TypePredicateNode>node).type, visitor, isTypeNode));
case SyntaxKind.TypeQuery: case SyntaxKind.TypeQuery:
return updateTypeQueryNode((<TypeQueryNode>node), visitNode((<TypeQueryNode>node).exprName, visitor, isEntityName)); return updateTypeQueryNode((<TypeQueryNode>node), visitNode((<TypeQueryNode>node).exprName, visitor, isEntityName));
@ -339,9 +322,8 @@ namespace ts {
nodesVisitor((<UnionOrIntersectionTypeNode>node).types, visitor, isTypeNode)); nodesVisitor((<UnionOrIntersectionTypeNode>node).types, visitor, isTypeNode));
case SyntaxKind.ParenthesizedType: case SyntaxKind.ParenthesizedType:
throw new Error("reached unsupported type in visitor."); Debug.fail("not implemented.");
case SyntaxKind.ThisType:
throw new Error("reached unsupported type in visitor.");
case SyntaxKind.TypeOperator: case SyntaxKind.TypeOperator:
return updateTypeOperatorNode(<TypeOperatorNode>node, visitNode((<TypeOperatorNode>node).type, visitor, isTypeNode)); return updateTypeOperatorNode(<TypeOperatorNode>node, visitNode((<TypeOperatorNode>node).type, visitor, isTypeNode));
case SyntaxKind.IndexedAccessType: case SyntaxKind.IndexedAccessType:
@ -376,13 +358,6 @@ namespace ts {
visitNode((<PropertySignature>node).type, visitor, isTypeNode), visitNode((<PropertySignature>node).type, visitor, isTypeNode),
visitNode((<PropertySignature>node).initializer, visitor, isExpression)); visitNode((<PropertySignature>node).initializer, visitor, isExpression));
case SyntaxKind.IndexSignature:
return updateIndexSignatureDeclaration(<IndexSignatureDeclaration>node,
visitParameterList((<IndexSignatureDeclaration>node).parameters, visitor, context, nodesVisitor),
visitNode((<IndexSignatureDeclaration>node).type, visitor, isTypeNode),
nodesVisitor((<IndexSignatureDeclaration>node).decorators, visitor, isDecorator),
nodesVisitor((<IndexSignatureDeclaration>node).modifiers, visitor, isModifier));
case SyntaxKind.PropertyDeclaration: case SyntaxKind.PropertyDeclaration:
return updateProperty(<PropertyDeclaration>node, return updateProperty(<PropertyDeclaration>node,
nodesVisitor((<PropertyDeclaration>node).decorators, visitor, isDecorator), nodesVisitor((<PropertyDeclaration>node).decorators, visitor, isDecorator),

View file

@ -65,10 +65,10 @@ namespace ts.codefix {
stringTypeNode, stringTypeNode,
/*initializer*/ undefined); /*initializer*/ undefined);
const indexSignature = createIndexSignatureDeclaration( const indexSignature = createIndexSignatureDeclaration(
[indexingParameter],
typeNode,
/*decorators*/undefined, /*decorators*/undefined,
/*modifiers*/ undefined); /*modifiers*/ undefined,
[indexingParameter],
typeNode);
const indexSignatureChangeTracker = textChanges.ChangeTracker.fromCodeFixContext(context); const indexSignatureChangeTracker = textChanges.ChangeTracker.fromCodeFixContext(context);
indexSignatureChangeTracker.insertNodeAfter(sourceFile, openBrace, indexSignature, { suffix: context.newLineCharacter }); indexSignatureChangeTracker.insertNodeAfter(sourceFile, openBrace, indexSignature, { suffix: context.newLineCharacter });

View file

@ -230,12 +230,4 @@ namespace ts.codefix {
} }
return undefined; return undefined;
} }
function stripComments(node: Node): Node {
if (node === undefined) {
return node;
}
const strippedChildren = visitEachChild(node, stripComments, nullTransformationContext);
return strippedChildren === node ? getSynthesizedClone(strippedChildren) : strippedChildren;
}
} }

View file

@ -528,6 +528,26 @@ namespace ts.textChanges {
return skipTrivia(s, 0) === s.length; return skipTrivia(s, 0) === s.length;
} }
const nullTransformationContext: TransformationContext = {
enableEmitNotification: noop,
enableSubstitution: noop,
endLexicalEnvironment: () => undefined,
getCompilerOptions: notImplemented,
getEmitHost: notImplemented,
getEmitResolver: notImplemented,
hoistFunctionDeclaration: noop,
hoistVariableDeclaration: noop,
isEmitNotificationEnabled: notImplemented,
isSubstitutionEnabled: notImplemented,
onEmitNode: noop,
onSubstituteNode: notImplemented,
readEmitHelpers: notImplemented,
requestEmitHelper: noop,
resumeLexicalEnvironment: noop,
startLexicalEnvironment: noop,
suspendLexicalEnvironment: noop
};
function assignPositionsToNode(node: Node): Node { function assignPositionsToNode(node: Node): Node {
const visited = visitEachChild(node, assignPositionsToNode, nullTransformationContext, assignPositionsToNodeArray, assignPositionsToNode); const visited = visitEachChild(node, assignPositionsToNode, nullTransformationContext, assignPositionsToNodeArray, assignPositionsToNode);
// create proxy node for non synthesized nodes // create proxy node for non synthesized nodes

View file

@ -0,0 +1,16 @@
/// <reference path='fourslash.ts' />
//// interface I {
//// f(i: any): i is I;
//// f(): this is I;
//// }
////
//// class C implements I {[| |]}
verify.rangeAfterCodeFix(`
f(i: any): i is I;
f(): this is I;
f(i?: any) {
throw new Error("Method not implemented.");
}
`);