Handle literal string union complete pattern for JSX attribute snippets (<input type />) (#52562)

Co-authored-by: Andrew Branch <andrewbranch@users.noreply.github.com>
This commit is contained in:
Vitaly 2023-02-04 02:40:00 +03:00 committed by GitHub
parent 2e9da1e5a1
commit c06711da1b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 26 additions and 3 deletions

View File

@ -1727,6 +1727,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
isArrayType,
isTupleType,
isArrayLikeType,
isEmptyAnonymousObjectType,
isTypeInvalidDueToUnionDiscriminant,
getExactOptionalProperties,
getAllPossiblePropertiesOfTypes,

View File

@ -4946,6 +4946,8 @@ export interface TypeChecker {
getPromisedTypeOfPromise(promise: Type, errorNode?: Node): Type | undefined;
/** @internal */
getAwaitedType(type: Type): Type | undefined;
/** @internal */
isEmptyAnonymousObjectType(type: Type): boolean;
getReturnTypeOfSignature(signature: Signature): Type;
/**
* Gets the type of a parameter at a given position in a signature.

View File

@ -218,6 +218,7 @@ import {
isStatement,
isStatic,
isString,
isStringAndEmptyAnonymousObjectIntersection,
isStringANonContextualKeyword,
isStringLiteralLike,
isStringLiteralOrTemplate,
@ -1442,7 +1443,7 @@ function createCompletionEntry(
&& !(type.flags & TypeFlags.BooleanLike)
&& !(type.flags & TypeFlags.Union && find((type as UnionType).types, type => !!(type.flags & TypeFlags.BooleanLike)))
) {
if (type.flags & TypeFlags.StringLike || (type.flags & TypeFlags.Union && every((type as UnionType).types, type => !!(type.flags & (TypeFlags.StringLike | TypeFlags.Undefined))))) {
if (type.flags & TypeFlags.StringLike || (type.flags & TypeFlags.Union && every((type as UnionType).types, type => !!(type.flags & (TypeFlags.StringLike | TypeFlags.Undefined) || isStringAndEmptyAnonymousObjectIntersection(type))))) {
// If is string like or undefined use quotes
insertText = `${escapeSnippetText(name)}=${quote(sourceFile, preferences, "$1")}`;
isSnippet = true;

View File

@ -342,6 +342,7 @@ import {
tryCast,
Type,
TypeChecker,
TypeFlags,
TypeFormatFlags,
TypeNode,
TypeOfExpression,
@ -2154,6 +2155,17 @@ export function isStringOrRegularExpressionOrTemplateLiteral(kind: SyntaxKind):
return false;
}
/** @internal */
export function isStringAndEmptyAnonymousObjectIntersection(type: Type) {
if (!type.isIntersection()) {
return false;
}
const { types, checker } = type;
return types.length === 2
&& (types[0].flags & TypeFlags.String) && checker.isEmptyAnonymousObjectType(types[1]);
}
/** @internal */
export function isPunctuation(kind: SyntaxKind): boolean {
return SyntaxKind.FirstPunctuation <= kind && kind <= SyntaxKind.LastPunctuation;

View File

@ -15,10 +15,11 @@
//// prop_h?: string;
//// prop_i?: boolean;
//// prop_j?: { p1: string; };
//// prop_string_literal_union?: 'input' | 'password' | (string & {})
//// }
//// }
//// }
////
////
//// <foo [|prop_/**/|] />
verify.completions({
@ -73,6 +74,12 @@ verify.completions({
insertText: "prop_j={$1}",
isSnippet: true,
sortText: completion.SortText.OptionalMember,
},
{
name: "prop_string_literal_union",
insertText: "prop_string_literal_union=\"$1\"",
isSnippet: true,
sortText: completion.SortText.OptionalMember,
}
],
preferences: {
@ -80,4 +87,4 @@ verify.completions({
includeCompletionsWithSnippetText: true,
includeCompletionsWithInsertText: true,
}
});
});