Support getting string literal completions based on a type argument constraint (#21168)

* Support getting string literal completions based on a type argument constraint

* Fix bug: look for require call before argument info

* Code review

* @sandersn code review

* Remove test cast

* Reduce completions.ts diff

* @weswigham review

* Remove getTypeArgumentConstraint's dependence on checkTypeArgumentConstraints

* Remove TODO
This commit is contained in:
Andy 2018-02-13 15:18:26 -08:00 committed by GitHub
parent f8a378a1d7
commit 8c2756fdf6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 27 additions and 5 deletions

View file

@ -299,6 +299,10 @@ namespace ts {
node = getParseTreeNode(node);
return node && tryGetThisTypeAt(node);
},
getTypeArgumentConstraint: node => {
node = getParseTreeNode(node, isTypeNode);
return node && getTypeArgumentConstraint(node);
},
};
const tupleTypes: GenericType[] = [];
@ -7356,7 +7360,7 @@ namespace ts {
type = getTypeReferenceType(node, symbol);
}
// Cache both the resolved symbol and the resolved type. The resolved symbol is needed in when we check the
// type reference in checkTypeReferenceOrExpressionWithTypeArguments.
// type reference in checkTypeReferenceNode.
links.resolvedSymbol = symbol;
links.resolvedType = type;
}
@ -20274,9 +20278,8 @@ namespace ts {
typeArguments = getEffectiveTypeArguments(node, typeParameters);
mapper = createTypeMapper(typeParameters, typeArguments);
}
const typeArgument = typeArguments[i];
result = result && checkTypeAssignableTo(
typeArgument,
typeArguments[i],
instantiateType(constraint, mapper),
node.typeArguments[i],
Diagnostics.Type_0_does_not_satisfy_the_constraint_1);
@ -20320,6 +20323,14 @@ namespace ts {
}
}
function getTypeArgumentConstraint(node: TypeNode): Type | undefined {
const typeReferenceNode = tryCast(node.parent, isTypeReferenceType);
if (!typeReferenceNode) return undefined;
const typeParameters = getTypeParametersForTypeReference(typeReferenceNode);
const constraint = getConstraintOfTypeParameter(typeParameters[typeReferenceNode.typeArguments.indexOf(node)!]);
return constraint && instantiateType(constraint, createTypeMapper(typeParameters, getEffectiveTypeArguments(typeReferenceNode, typeParameters)));
}
function checkTypeQuery(node: TypeQueryNode) {
getTypeFromTypeQueryNode(node);
}

View file

@ -2944,6 +2944,7 @@ namespace ts {
/* @internal */ resolveExternalModuleSymbol(symbol: Symbol): Symbol;
/** @param node A location where we might consider accessing `this`. Not necessarily a ThisExpression. */
/* @internal */ tryGetThisTypeAt(node: Node): Type | undefined;
/* @internal */ getTypeArgumentConstraint(node: TypeNode): Type | undefined;
}
/* @internal */

View file

@ -5940,4 +5940,9 @@ namespace ts {
return false;
}
}
/* @internal */
export function isTypeReferenceType(node: Node): node is TypeReferenceType {
return node.kind === SyntaxKind.TypeReference || node.kind === SyntaxKind.ExpressionWithTypeArguments;
}
}

View file

@ -358,8 +358,7 @@ namespace ts.Completions {
case SyntaxKind.LiteralType:
switch (node.parent.parent.kind) {
case SyntaxKind.TypeReference:
// TODO: GH#21168
return undefined;
return { kind: StringLiteralCompletionKind.Types, types: getStringLiteralTypes(typeChecker.getTypeArgumentConstraint(node.parent as LiteralTypeNode), typeChecker) };
case SyntaxKind.IndexedAccessType:
// Get all apparent property names
// i.e. interface Foo {

View file

@ -0,0 +1,6 @@
/// <reference path="fourslash.ts" />
////interface Foo { foo: string; bar: string; }
////type T = Pick<Foo, "/**/">;
verify.completionsAt("", ["foo", "bar"]);