mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-04 21:53:42 -06:00
Provide string completions within unions in indexed access types (#53225)
This commit is contained in:
parent
d105b6a994
commit
ae2b4afdcb
@ -83,7 +83,6 @@ import {
|
||||
isString,
|
||||
isStringLiteral,
|
||||
isStringLiteralLike,
|
||||
isTypeReferenceNode,
|
||||
isUrl,
|
||||
JsxAttribute,
|
||||
LanguageServiceHost,
|
||||
@ -342,40 +341,10 @@ function getStringLiteralCompletionEntries(sourceFile: SourceFile, node: StringL
|
||||
switch (parent.kind) {
|
||||
case SyntaxKind.LiteralType: {
|
||||
const grandParent = walkUpParentheses(parent.parent);
|
||||
switch (grandParent.kind) {
|
||||
case SyntaxKind.ExpressionWithTypeArguments:
|
||||
case SyntaxKind.TypeReference: {
|
||||
const typeArgument = findAncestor(parent, n => n.parent === grandParent) as LiteralTypeNode;
|
||||
if (typeArgument) {
|
||||
return { kind: StringLiteralCompletionKind.Types, types: getStringLiteralTypes(typeChecker.getTypeArgumentConstraint(typeArgument)), isNewIdentifier: false };
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
case SyntaxKind.IndexedAccessType:
|
||||
// Get all apparent property names
|
||||
// i.e. interface Foo {
|
||||
// foo: string;
|
||||
// bar: string;
|
||||
// }
|
||||
// let x: Foo["/*completion position*/"]
|
||||
const { indexType, objectType } = grandParent as IndexedAccessTypeNode;
|
||||
if (!rangeContainsPosition(indexType, position)) {
|
||||
return undefined;
|
||||
}
|
||||
return stringLiteralCompletionsFromProperties(typeChecker.getTypeFromTypeNode(objectType));
|
||||
case SyntaxKind.ImportType:
|
||||
return { kind: StringLiteralCompletionKind.Paths, paths: getStringLiteralCompletionsFromModuleNames(sourceFile, node, compilerOptions, host, typeChecker, preferences) };
|
||||
case SyntaxKind.UnionType: {
|
||||
if (!isTypeReferenceNode(grandParent.parent)) {
|
||||
return undefined;
|
||||
}
|
||||
const alreadyUsedTypes = getAlreadyUsedTypesInStringLiteralUnion(grandParent as UnionTypeNode, parent as LiteralTypeNode);
|
||||
const types = getStringLiteralTypes(typeChecker.getTypeArgumentConstraint(grandParent as UnionTypeNode)).filter(t => !contains(alreadyUsedTypes, t.value));
|
||||
return { kind: StringLiteralCompletionKind.Types, types, isNewIdentifier: false };
|
||||
}
|
||||
default:
|
||||
return undefined;
|
||||
if (grandParent.kind === SyntaxKind.ImportType) {
|
||||
return { kind: StringLiteralCompletionKind.Paths, paths: getStringLiteralCompletionsFromModuleNames(sourceFile, node, compilerOptions, host, typeChecker, preferences) };
|
||||
}
|
||||
return fromUnionableLiteralType(grandParent);
|
||||
}
|
||||
case SyntaxKind.PropertyAssignment:
|
||||
if (isObjectLiteralExpression(parent.parent) && (parent as PropertyAssignment).name === node) {
|
||||
@ -443,6 +412,44 @@ function getStringLiteralCompletionEntries(sourceFile: SourceFile, node: StringL
|
||||
return fromContextualType() || fromContextualType(ContextFlags.None);
|
||||
}
|
||||
|
||||
function fromUnionableLiteralType(grandParent: Node): StringLiteralCompletionsFromTypes | StringLiteralCompletionsFromProperties | undefined {
|
||||
switch (grandParent.kind) {
|
||||
case SyntaxKind.ExpressionWithTypeArguments:
|
||||
case SyntaxKind.TypeReference: {
|
||||
const typeArgument = findAncestor(parent, n => n.parent === grandParent) as LiteralTypeNode;
|
||||
if (typeArgument) {
|
||||
return { kind: StringLiteralCompletionKind.Types, types: getStringLiteralTypes(typeChecker.getTypeArgumentConstraint(typeArgument)), isNewIdentifier: false };
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
case SyntaxKind.IndexedAccessType:
|
||||
// Get all apparent property names
|
||||
// i.e. interface Foo {
|
||||
// foo: string;
|
||||
// bar: string;
|
||||
// }
|
||||
// let x: Foo["/*completion position*/"]
|
||||
const { indexType, objectType } = grandParent as IndexedAccessTypeNode;
|
||||
if (!rangeContainsPosition(indexType, position)) {
|
||||
return undefined;
|
||||
}
|
||||
return stringLiteralCompletionsFromProperties(typeChecker.getTypeFromTypeNode(objectType));
|
||||
case SyntaxKind.UnionType: {
|
||||
const result = fromUnionableLiteralType(walkUpParentheses(grandParent.parent));
|
||||
if (!result) {
|
||||
return undefined;
|
||||
}
|
||||
const alreadyUsedTypes = getAlreadyUsedTypesInStringLiteralUnion(grandParent as UnionTypeNode, parent as LiteralTypeNode);
|
||||
if (result.kind === StringLiteralCompletionKind.Properties) {
|
||||
return { kind: StringLiteralCompletionKind.Properties, symbols: result.symbols.filter(sym => !contains(alreadyUsedTypes, sym.name)), hasIndexSignature: result.hasIndexSignature };
|
||||
}
|
||||
return { kind: StringLiteralCompletionKind.Types, types: result.types.filter(t => !contains(alreadyUsedTypes, t.value)), isNewIdentifier: false };
|
||||
}
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
function fromContextualType(contextFlags: ContextFlags = ContextFlags.Completions): StringLiteralCompletionsFromTypes | undefined {
|
||||
// Get completion for string literal from string literal type
|
||||
// i.e. var x: "hi" | "hello" = "/*completion position*/"
|
||||
|
||||
@ -0,0 +1,8 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
//// type Foo = { a: string; b: number; c: boolean; };
|
||||
//// type A = Foo["/*1*/"];
|
||||
//// type AorB = Foo["a" | "/*2*/"];
|
||||
|
||||
verify.completions({ marker: ["1"], exact: ["a", "b", "c"] });
|
||||
verify.completions({ marker: ["2"], exact: ["b", "c"] });
|
||||
Loading…
x
Reference in New Issue
Block a user