type predicate support
This commit is contained in:
parent
a39bb0aaaa
commit
7340c4ca1e
9 changed files with 93 additions and 68 deletions
|
@ -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));
|
||||||
|
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);
|
const returnType = getReturnTypeOfSignature(signature);
|
||||||
const returnTypeNode = returnType && typeToTypeNodeHelper(returnType);
|
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);
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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 });
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -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
|
||||||
|
|
|
@ -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.");
|
||||||
|
}
|
||||||
|
`);
|
Loading…
Reference in a new issue