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);
const typeNode = typeToTypeNodeHelper(indexInfo.type);
return createIndexSignatureDeclaration(
[indexingParameter],
typeNode,
/*decorators*/ undefined,
indexInfo.isReadonly ? [createToken(SyntaxKind.ReadonlyKeyword)] : undefined);
indexInfo.isReadonly ? [createToken(SyntaxKind.ReadonlyKeyword)] : undefined,
[indexingParameter],
typeNode);
}
function signatureToSignatureDeclarationHelper(signature: Signature, kind: SyntaxKind): SignatureDeclaration {
const typeParameters = signature.typeParameters && signature.typeParameters.map(parameter => typeParameterToDeclaration(parameter));
const parameters = signature.parameters.map(parameter => symbolToParameterDeclaration(parameter));
const returnType = getReturnTypeOfSignature(signature);
const returnTypeNode = returnType && typeToTypeNodeHelper(returnType);
let returnTypeNode: TypeNode | TypePredicate;
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;
return createSignatureDeclaration(kind, typeParameters, parameters, returnTypeNodeExceptAny);

View file

@ -286,6 +286,10 @@ namespace ts {
return <KeywordTypeNode>createSynthesizedNode(kind);
}
export function createThisTypeNode() {
return <ThisTypeNode>createSynthesizedNode(SyntaxKind.ThisType);
}
export function createLiteralTypeNode(literal: Expression) {
const literalTypeNode = createSynthesizedNode(SyntaxKind.LiteralType) as LiteralTypeNode;
literalTypeNode.literal = literal;
@ -312,6 +316,20 @@ namespace ts {
: 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) {
const typeQueryNode = createSynthesizedNode(SyntaxKind.TypeQuery) as TypeQueryNode;
typeQueryNode.exprName = exprName;
@ -455,21 +473,21 @@ namespace ts {
: 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;
indexSignature.parameters = asNodeArray(parameters);
indexSignature.type = type;
indexSignature.decorators = asNodeArray(decorators);
indexSignature.modifiers = asNodeArray(modifiers);
indexSignature.parameters = createNodeArray(parameters);
indexSignature.type = type;
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
|| node.type !== type
|| node.decorators !== decorators
|| node.modifiers !== modifiers
? updateNode(createIndexSignatureDeclaration(parameters, type, decorators, modifiers), node)
? updateNode(createIndexSignatureDeclaration(decorators, modifiers, parameters, type), node)
: node;
}
@ -542,7 +560,7 @@ namespace ts {
node.name = asName(name);
node.questionToken = questionToken;
node.typeParameters = asNodeArray(typeParameters);
node.parameters = asNodeArray(parameters);
node.parameters = createNodeArray(parameters);
node.type = type;
node.body = body;
return node;
@ -2052,7 +2070,8 @@ namespace ts {
function asName(name: string | BindingName): BindingName;
function asName(name: string | PropertyName): PropertyName;
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;
}
@ -2060,7 +2079,7 @@ namespace ts {
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;
}

View file

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

View file

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

View file

@ -3,26 +3,6 @@
/// <reference path="utilities.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.
*
@ -234,7 +214,7 @@ namespace ts {
const kind = node.kind;
// 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;
}
@ -293,10 +273,10 @@ namespace ts {
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));
nodesVisitor((<IndexSignatureDeclaration>node).modifiers, visitor, isModifier),
visitParameterList((<IndexSignatureDeclaration>node).parameters, visitor, context, nodesVisitor),
visitNode((<IndexSignatureDeclaration>node).type, visitor, isTypeNode));
case SyntaxKind.Parameter:
return updateParameter(<ParameterDeclaration>node,
@ -314,13 +294,16 @@ namespace ts {
// Types
case SyntaxKind.TypePredicate:
throw new Error("reached unsupported type in visitor.");
case SyntaxKind.TypeReference:
return updateTypeReferenceNode(<TypeReferenceNode>node,
visitNode((<TypeReferenceNode>node).typeName, visitor, isEntityName),
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:
return updateTypeQueryNode((<TypeQueryNode>node), visitNode((<TypeQueryNode>node).exprName, visitor, isEntityName));
@ -339,9 +322,8 @@ namespace ts {
nodesVisitor((<UnionOrIntersectionTypeNode>node).types, visitor, isTypeNode));
case SyntaxKind.ParenthesizedType:
throw new Error("reached unsupported type in visitor.");
case SyntaxKind.ThisType:
throw new Error("reached unsupported type in visitor.");
Debug.fail("not implemented.");
case SyntaxKind.TypeOperator:
return updateTypeOperatorNode(<TypeOperatorNode>node, visitNode((<TypeOperatorNode>node).type, visitor, isTypeNode));
case SyntaxKind.IndexedAccessType:
@ -376,13 +358,6 @@ namespace ts {
visitNode((<PropertySignature>node).type, visitor, isTypeNode),
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:
return updateProperty(<PropertyDeclaration>node,
nodesVisitor((<PropertyDeclaration>node).decorators, visitor, isDecorator),

View file

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

View file

@ -230,12 +230,4 @@ namespace ts.codefix {
}
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;
}
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 {
const visited = visitEachChild(node, assignPositionsToNode, nullTransformationContext, assignPositionsToNodeArray, assignPositionsToNode);
// 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.");
}
`);