From c020b4a4590e9deff6ffe4ed3e6acb9564ddb637 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 21 Nov 2023 19:59:36 +0000 Subject: [PATCH] Cherry-pick PR #56434 into release-5.3 Component commits: 7fa9179724 Fix support for intersections in template literal placeholder types f45b6dd712 Accept new baselines 2cf8379310 Update test ca7e9c4d1d Accept new baselines 8ab01ebf6d Update fourslash test b464619504 Add more tests per code review --- src/compiler/checker.ts | 50 +++++++++++-------- src/compiler/types.ts | 8 ++- .../templateLiteralTypesPatterns.errors.txt | 10 ++-- .../reference/templateLiteralTypesPatterns.js | 12 ++++- .../templateLiteralTypesPatterns.symbols | 26 +++++++--- .../templateLiteralTypesPatterns.types | 34 ++++++++++--- .../literal/templateLiteralTypesPatterns.ts | 8 ++- ...pletionsForOpenEndedTemplateLiteralType.ts | 2 +- 8 files changed, 101 insertions(+), 49 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 9ad699f1adcb0..77dc0e5790eac 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -16893,10 +16893,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function removeStringLiteralsMatchedByTemplateLiterals(types: Type[]) { - const templates = filter(types, t => - !!(t.flags & TypeFlags.TemplateLiteral) && - isPatternLiteralType(t) && - (t as TemplateLiteralType).types.every(t => !(t.flags & TypeFlags.Intersection) || !areIntersectedTypesAvoidingPrimitiveReduction((t as IntersectionType).types))) as TemplateLiteralType[]; + const templates = filter(types, t => !!(t.flags & TypeFlags.TemplateLiteral) && isPatternLiteralType(t)) as TemplateLiteralType[]; if (templates.length) { let i = types.length; while (i > 0) { @@ -17407,20 +17404,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return reduceLeft(types, (n, t) => n + getConstituentCount(t), 0); } - function areIntersectedTypesAvoidingPrimitiveReduction(types: Type[], primitiveFlags = TypeFlags.String | TypeFlags.Number | TypeFlags.BigInt): boolean { - if (types.length !== 2) { - return false; - } - const [t1, t2] = types; - return !!(t1.flags & primitiveFlags) && t2 === emptyTypeLiteralType || !!(t2.flags & primitiveFlags) && t1 === emptyTypeLiteralType; - } - function getTypeFromIntersectionTypeNode(node: IntersectionTypeNode): Type { const links = getNodeLinks(node); if (!links.resolvedType) { const aliasSymbol = getAliasSymbolForTypeNode(node); const types = map(node.types, getTypeFromTypeNode); - const noSupertypeReduction = areIntersectedTypesAvoidingPrimitiveReduction(types); + // We perform no supertype reduction for X & {} or {} & X, where X is one of string, number, bigint, + // or a pattern literal template type. This enables union types like "a" | "b" | string & {} or + // "aa" | "ab" | `a${string}` which preserve the literal types for purposes of statement completion. + const emptyIndex = types.length === 2 ? types.indexOf(emptyTypeLiteralType) : -1; + const t = emptyIndex >= 0 ? types[1 - emptyIndex] : unknownType; + const noSupertypeReduction = !!(t.flags & (TypeFlags.String | TypeFlags.Number | TypeFlags.BigInt) || t.flags & TypeFlags.TemplateLiteral && isPatternLiteralType(t)); links.resolvedType = getIntersectionType(types, aliasSymbol, getTypeArgumentsForAliasSymbol(aliasSymbol), noSupertypeReduction); } return links.resolvedType; @@ -17703,7 +17697,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function createTemplateLiteralType(texts: readonly string[], types: readonly Type[]) { const type = createType(TypeFlags.TemplateLiteral) as TemplateLiteralType; - type.objectFlags = getPropagatingFlagsOfTypes(types, /*excludeKinds*/ TypeFlags.Nullable); type.texts = texts; type.types = types; return type; @@ -18028,12 +18021,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function isPatternLiteralPlaceholderType(type: Type): boolean { if (type.flags & TypeFlags.Intersection) { - return !isGenericType(type) && some((type as IntersectionType).types, t => !!(t.flags & (TypeFlags.Literal | TypeFlags.Nullable)) || isPatternLiteralPlaceholderType(t)); + // Return true if the intersection consists of one or more placeholders and zero or + // more object type tags. + let seenPlaceholder = false; + for (const t of (type as IntersectionType).types) { + if (t.flags & (TypeFlags.Literal | TypeFlags.Nullable) || isPatternLiteralPlaceholderType(t)) { + seenPlaceholder = true; + } + else if (!(t.flags & TypeFlags.Object)) { + return false; + } + } + return seenPlaceholder; } return !!(type.flags & (TypeFlags.Any | TypeFlags.String | TypeFlags.Number | TypeFlags.BigInt)) || isPatternLiteralType(type); } function isPatternLiteralType(type: Type) { + // A pattern literal type is a template literal or a string mapping type that contains only + // non-generic pattern literal placeholders. return !!(type.flags & TypeFlags.TemplateLiteral) && every((type as TemplateLiteralType).types, isPatternLiteralPlaceholderType) || !!(type.flags & TypeFlags.StringMapping) && isPatternLiteralPlaceholderType((type as StringMappingType).type); } @@ -18051,12 +18057,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getGenericObjectFlags(type: Type): ObjectFlags { - if (type.flags & (TypeFlags.UnionOrIntersection | TypeFlags.TemplateLiteral)) { - if (!((type as UnionOrIntersectionType | TemplateLiteralType).objectFlags & ObjectFlags.IsGenericTypeComputed)) { - (type as UnionOrIntersectionType | TemplateLiteralType).objectFlags |= ObjectFlags.IsGenericTypeComputed | - reduceLeft((type as UnionOrIntersectionType | TemplateLiteralType).types, (flags, t) => flags | getGenericObjectFlags(t), 0); + if (type.flags & (TypeFlags.UnionOrIntersection)) { + if (!((type as UnionOrIntersectionType).objectFlags & ObjectFlags.IsGenericTypeComputed)) { + (type as UnionOrIntersectionType).objectFlags |= ObjectFlags.IsGenericTypeComputed | + reduceLeft((type as UnionOrIntersectionType).types, (flags, t) => flags | getGenericObjectFlags(t), 0); } - return (type as UnionOrIntersectionType | TemplateLiteralType).objectFlags & ObjectFlags.IsGenericType; + return (type as UnionOrIntersectionType).objectFlags & ObjectFlags.IsGenericType; } if (type.flags & TypeFlags.Substitution) { if (!((type as SubstitutionType).objectFlags & ObjectFlags.IsGenericTypeComputed)) { @@ -18066,7 +18072,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return (type as SubstitutionType).objectFlags & ObjectFlags.IsGenericType; } return (type.flags & TypeFlags.InstantiableNonPrimitive || isGenericMappedType(type) || isGenericTupleType(type) ? ObjectFlags.IsGenericObjectType : 0) | - (type.flags & (TypeFlags.InstantiableNonPrimitive | TypeFlags.Index | TypeFlags.StringMapping) && !isPatternLiteralType(type) ? ObjectFlags.IsGenericIndexType : 0); + (type.flags & (TypeFlags.InstantiableNonPrimitive | TypeFlags.Index | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) && !isPatternLiteralType(type) ? ObjectFlags.IsGenericIndexType : 0); } function getSimplifiedType(type: Type, writing: boolean): Type { @@ -24734,7 +24740,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { objectFlags & ObjectFlags.Anonymous && type.symbol && type.symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.TypeLiteral | SymbolFlags.ObjectLiteral) && type.symbol.declarations || objectFlags & (ObjectFlags.Mapped | ObjectFlags.ReverseMapped | ObjectFlags.ObjectRestType | ObjectFlags.InstantiationExpressionType) ) || - type.flags & (TypeFlags.UnionOrIntersection | TypeFlags.TemplateLiteral) && !(type.flags & TypeFlags.EnumLiteral) && !isNonGenericTopLevelType(type) && some((type as UnionOrIntersectionType | TemplateLiteralType).types, couldContainTypeVariables)); + type.flags & TypeFlags.UnionOrIntersection && !(type.flags & TypeFlags.EnumLiteral) && !isNonGenericTopLevelType(type) && some((type as UnionOrIntersectionType).types, couldContainTypeVariables)); if (type.flags & TypeFlags.ObjectFlagsType) { (type as ObjectFlagsType).objectFlags |= ObjectFlags.CouldContainTypeVariablesComputed | (result ? ObjectFlags.CouldContainTypeVariables : 0); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index c33cafe7136c6..7821c32218eb8 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -6129,7 +6129,7 @@ export const enum TypeFlags { Instantiable = InstantiableNonPrimitive | InstantiablePrimitive, StructuredOrInstantiable = StructuredType | Instantiable, /** @internal */ - ObjectFlagsType = Any | Nullable | Never | Object | Union | Intersection | TemplateLiteral, + ObjectFlagsType = Any | Nullable | Never | Object | Union | Intersection, /** @internal */ Simplifiable = IndexedAccess | Conditional, /** @internal */ @@ -6288,7 +6288,7 @@ export const enum ObjectFlags { /** @internal */ IdenticalBaseTypeExists = 1 << 26, // has a defined cachedEquivalentBaseType member - // Flags that require TypeFlags.UnionOrIntersection, TypeFlags.Substitution, or TypeFlags.TemplateLiteral + // Flags that require TypeFlags.UnionOrIntersection or TypeFlags.Substitution /** @internal */ IsGenericTypeComputed = 1 << 21, // IsGenericObjectType flag has been computed /** @internal */ @@ -6315,7 +6315,7 @@ export const enum ObjectFlags { } /** @internal */ -export type ObjectFlagsType = NullableType | ObjectType | UnionType | IntersectionType | TemplateLiteralType; +export type ObjectFlagsType = NullableType | ObjectType | UnionType | IntersectionType; // Object types (TypeFlags.ObjectType) // dprint-ignore @@ -6674,8 +6674,6 @@ export interface ConditionalType extends InstantiableType { } export interface TemplateLiteralType extends InstantiableType { - /** @internal */ - objectFlags: ObjectFlags; texts: readonly string[]; // Always one element longer than types types: readonly Type[]; // Always at least one element } diff --git a/tests/baselines/reference/templateLiteralTypesPatterns.errors.txt b/tests/baselines/reference/templateLiteralTypesPatterns.errors.txt index cd82afc83981b..3ead220eb04cd 100644 --- a/tests/baselines/reference/templateLiteralTypesPatterns.errors.txt +++ b/tests/baselines/reference/templateLiteralTypesPatterns.errors.txt @@ -55,7 +55,7 @@ templateLiteralTypesPatterns.ts(129,9): error TS2345: Argument of type '"1.1e-10 templateLiteralTypesPatterns.ts(140,1): error TS2322: Type '`a${string}`' is not assignable to type '`a${number}`'. templateLiteralTypesPatterns.ts(141,1): error TS2322: Type '"bno"' is not assignable to type '`a${any}`'. templateLiteralTypesPatterns.ts(160,7): error TS2322: Type '"anything"' is not assignable to type '`${number} ${number}`'. -templateLiteralTypesPatterns.ts(211,5): error TS2345: Argument of type '"abcTest"' is not assignable to parameter of type '`${`a${string}` & `${string}a`}Test`'. +templateLiteralTypesPatterns.ts(215,5): error TS2345: Argument of type '"abcTest"' is not assignable to parameter of type '`${`a${string}` & `${string}a`}Test`'. ==== templateLiteralTypesPatterns.ts (58 errors) ==== @@ -376,10 +376,14 @@ templateLiteralTypesPatterns.ts(211,5): error TS2345: Argument of type '"abcTest } // repro from https://github.com/microsoft/TypeScript/issues/54177#issuecomment-1538436654 - function conversionTest(groupName: | "downcast" | "dataDowncast" | "editingDowncast" | `${string & {}}Downcast`) {} + function conversionTest(groupName: | "downcast" | "dataDowncast" | "editingDowncast" | `${string}Downcast` & {}) {} conversionTest("testDowncast"); - function conversionTest2(groupName: | "downcast" | "dataDowncast" | "editingDowncast" | `${{} & string}Downcast`) {} + function conversionTest2(groupName: | "downcast" | "dataDowncast" | "editingDowncast" | {} & `${string}Downcast`) {} conversionTest2("testDowncast"); + function conversionTest3(groupName: | "downcast" | "dataDowncast" | "editingDowncast" | `${string & {}}Downcast`) {} + conversionTest3("testDowncast"); + function conversionTest4(groupName: | "downcast" | "dataDowncast" | "editingDowncast" | `${{} & string}Downcast`) {} + conversionTest4("testDowncast"); function foo(str: `${`a${string}` & `${string}a`}Test`) {} foo("abaTest"); // ok diff --git a/tests/baselines/reference/templateLiteralTypesPatterns.js b/tests/baselines/reference/templateLiteralTypesPatterns.js index d66c794e287a8..8741dda63c2cc 100644 --- a/tests/baselines/reference/templateLiteralTypesPatterns.js +++ b/tests/baselines/reference/templateLiteralTypesPatterns.js @@ -204,10 +204,14 @@ export abstract class BB { } // repro from https://github.com/microsoft/TypeScript/issues/54177#issuecomment-1538436654 -function conversionTest(groupName: | "downcast" | "dataDowncast" | "editingDowncast" | `${string & {}}Downcast`) {} +function conversionTest(groupName: | "downcast" | "dataDowncast" | "editingDowncast" | `${string}Downcast` & {}) {} conversionTest("testDowncast"); -function conversionTest2(groupName: | "downcast" | "dataDowncast" | "editingDowncast" | `${{} & string}Downcast`) {} +function conversionTest2(groupName: | "downcast" | "dataDowncast" | "editingDowncast" | {} & `${string}Downcast`) {} conversionTest2("testDowncast"); +function conversionTest3(groupName: | "downcast" | "dataDowncast" | "editingDowncast" | `${string & {}}Downcast`) {} +conversionTest3("testDowncast"); +function conversionTest4(groupName: | "downcast" | "dataDowncast" | "editingDowncast" | `${{} & string}Downcast`) {} +conversionTest4("testDowncast"); function foo(str: `${`a${string}` & `${string}a`}Test`) {} foo("abaTest"); // ok @@ -367,6 +371,10 @@ function conversionTest(groupName) { } conversionTest("testDowncast"); function conversionTest2(groupName) { } conversionTest2("testDowncast"); +function conversionTest3(groupName) { } +conversionTest3("testDowncast"); +function conversionTest4(groupName) { } +conversionTest4("testDowncast"); function foo(str) { } foo("abaTest"); // ok foo("abcTest"); // error diff --git a/tests/baselines/reference/templateLiteralTypesPatterns.symbols b/tests/baselines/reference/templateLiteralTypesPatterns.symbols index cc508d2680959..67158ff6db1cd 100644 --- a/tests/baselines/reference/templateLiteralTypesPatterns.symbols +++ b/tests/baselines/reference/templateLiteralTypesPatterns.symbols @@ -488,27 +488,41 @@ export abstract class BB { } // repro from https://github.com/microsoft/TypeScript/issues/54177#issuecomment-1538436654 -function conversionTest(groupName: | "downcast" | "dataDowncast" | "editingDowncast" | `${string & {}}Downcast`) {} +function conversionTest(groupName: | "downcast" | "dataDowncast" | "editingDowncast" | `${string}Downcast` & {}) {} >conversionTest : Symbol(conversionTest, Decl(templateLiteralTypesPatterns.ts, 200, 1)) >groupName : Symbol(groupName, Decl(templateLiteralTypesPatterns.ts, 203, 24)) conversionTest("testDowncast"); >conversionTest : Symbol(conversionTest, Decl(templateLiteralTypesPatterns.ts, 200, 1)) -function conversionTest2(groupName: | "downcast" | "dataDowncast" | "editingDowncast" | `${{} & string}Downcast`) {} +function conversionTest2(groupName: | "downcast" | "dataDowncast" | "editingDowncast" | {} & `${string}Downcast`) {} >conversionTest2 : Symbol(conversionTest2, Decl(templateLiteralTypesPatterns.ts, 204, 31)) >groupName : Symbol(groupName, Decl(templateLiteralTypesPatterns.ts, 205, 25)) conversionTest2("testDowncast"); >conversionTest2 : Symbol(conversionTest2, Decl(templateLiteralTypesPatterns.ts, 204, 31)) +function conversionTest3(groupName: | "downcast" | "dataDowncast" | "editingDowncast" | `${string & {}}Downcast`) {} +>conversionTest3 : Symbol(conversionTest3, Decl(templateLiteralTypesPatterns.ts, 206, 32)) +>groupName : Symbol(groupName, Decl(templateLiteralTypesPatterns.ts, 207, 25)) + +conversionTest3("testDowncast"); +>conversionTest3 : Symbol(conversionTest3, Decl(templateLiteralTypesPatterns.ts, 206, 32)) + +function conversionTest4(groupName: | "downcast" | "dataDowncast" | "editingDowncast" | `${{} & string}Downcast`) {} +>conversionTest4 : Symbol(conversionTest4, Decl(templateLiteralTypesPatterns.ts, 208, 32)) +>groupName : Symbol(groupName, Decl(templateLiteralTypesPatterns.ts, 209, 25)) + +conversionTest4("testDowncast"); +>conversionTest4 : Symbol(conversionTest4, Decl(templateLiteralTypesPatterns.ts, 208, 32)) + function foo(str: `${`a${string}` & `${string}a`}Test`) {} ->foo : Symbol(foo, Decl(templateLiteralTypesPatterns.ts, 206, 32)) ->str : Symbol(str, Decl(templateLiteralTypesPatterns.ts, 208, 13)) +>foo : Symbol(foo, Decl(templateLiteralTypesPatterns.ts, 210, 32)) +>str : Symbol(str, Decl(templateLiteralTypesPatterns.ts, 212, 13)) foo("abaTest"); // ok ->foo : Symbol(foo, Decl(templateLiteralTypesPatterns.ts, 206, 32)) +>foo : Symbol(foo, Decl(templateLiteralTypesPatterns.ts, 210, 32)) foo("abcTest"); // error ->foo : Symbol(foo, Decl(templateLiteralTypesPatterns.ts, 206, 32)) +>foo : Symbol(foo, Decl(templateLiteralTypesPatterns.ts, 210, 32)) diff --git a/tests/baselines/reference/templateLiteralTypesPatterns.types b/tests/baselines/reference/templateLiteralTypesPatterns.types index d9fbfeec9d8b2..d63799df57018 100644 --- a/tests/baselines/reference/templateLiteralTypesPatterns.types +++ b/tests/baselines/reference/templateLiteralTypesPatterns.types @@ -636,22 +636,40 @@ export abstract class BB { } // repro from https://github.com/microsoft/TypeScript/issues/54177#issuecomment-1538436654 -function conversionTest(groupName: | "downcast" | "dataDowncast" | "editingDowncast" | `${string & {}}Downcast`) {} ->conversionTest : (groupName: "downcast" | "dataDowncast" | "editingDowncast" | `${string & {}}Downcast`) => void ->groupName : `${string & {}}Downcast` | "downcast" | "dataDowncast" | "editingDowncast" +function conversionTest(groupName: | "downcast" | "dataDowncast" | "editingDowncast" | `${string}Downcast` & {}) {} +>conversionTest : (groupName: "downcast" | "dataDowncast" | "editingDowncast" | `${string}Downcast` & {}) => void +>groupName : (`${string}Downcast` & {}) | "downcast" | "dataDowncast" | "editingDowncast" conversionTest("testDowncast"); >conversionTest("testDowncast") : void ->conversionTest : (groupName: `${string & {}}Downcast` | "downcast" | "dataDowncast" | "editingDowncast") => void +>conversionTest : (groupName: (`${string}Downcast` & {}) | "downcast" | "dataDowncast" | "editingDowncast") => void >"testDowncast" : "testDowncast" -function conversionTest2(groupName: | "downcast" | "dataDowncast" | "editingDowncast" | `${{} & string}Downcast`) {} ->conversionTest2 : (groupName: "downcast" | "dataDowncast" | "editingDowncast" | `${{} & string}Downcast`) => void ->groupName : "downcast" | "dataDowncast" | "editingDowncast" | `${{} & string}Downcast` +function conversionTest2(groupName: | "downcast" | "dataDowncast" | "editingDowncast" | {} & `${string}Downcast`) {} +>conversionTest2 : (groupName: "downcast" | "dataDowncast" | "editingDowncast" | {} & `${string}Downcast`) => void +>groupName : "downcast" | "dataDowncast" | "editingDowncast" | ({} & `${string}Downcast`) conversionTest2("testDowncast"); >conversionTest2("testDowncast") : void ->conversionTest2 : (groupName: "downcast" | "dataDowncast" | "editingDowncast" | `${{} & string}Downcast`) => void +>conversionTest2 : (groupName: "downcast" | "dataDowncast" | "editingDowncast" | ({} & `${string}Downcast`)) => void +>"testDowncast" : "testDowncast" + +function conversionTest3(groupName: | "downcast" | "dataDowncast" | "editingDowncast" | `${string & {}}Downcast`) {} +>conversionTest3 : (groupName: "downcast" | "dataDowncast" | "editingDowncast" | `${string & {}}Downcast`) => void +>groupName : "downcast" | `${string & {}}Downcast` + +conversionTest3("testDowncast"); +>conversionTest3("testDowncast") : void +>conversionTest3 : (groupName: "downcast" | `${string & {}}Downcast`) => void +>"testDowncast" : "testDowncast" + +function conversionTest4(groupName: | "downcast" | "dataDowncast" | "editingDowncast" | `${{} & string}Downcast`) {} +>conversionTest4 : (groupName: "downcast" | "dataDowncast" | "editingDowncast" | `${{} & string}Downcast`) => void +>groupName : "downcast" | `${{} & string}Downcast` + +conversionTest4("testDowncast"); +>conversionTest4("testDowncast") : void +>conversionTest4 : (groupName: "downcast" | `${{} & string}Downcast`) => void >"testDowncast" : "testDowncast" function foo(str: `${`a${string}` & `${string}a`}Test`) {} diff --git a/tests/cases/conformance/types/literal/templateLiteralTypesPatterns.ts b/tests/cases/conformance/types/literal/templateLiteralTypesPatterns.ts index aeb05ead7ccca..00d36bd722a29 100644 --- a/tests/cases/conformance/types/literal/templateLiteralTypesPatterns.ts +++ b/tests/cases/conformance/types/literal/templateLiteralTypesPatterns.ts @@ -202,10 +202,14 @@ export abstract class BB { } // repro from https://github.com/microsoft/TypeScript/issues/54177#issuecomment-1538436654 -function conversionTest(groupName: | "downcast" | "dataDowncast" | "editingDowncast" | `${string & {}}Downcast`) {} +function conversionTest(groupName: | "downcast" | "dataDowncast" | "editingDowncast" | `${string}Downcast` & {}) {} conversionTest("testDowncast"); -function conversionTest2(groupName: | "downcast" | "dataDowncast" | "editingDowncast" | `${{} & string}Downcast`) {} +function conversionTest2(groupName: | "downcast" | "dataDowncast" | "editingDowncast" | {} & `${string}Downcast`) {} conversionTest2("testDowncast"); +function conversionTest3(groupName: | "downcast" | "dataDowncast" | "editingDowncast" | `${string & {}}Downcast`) {} +conversionTest3("testDowncast"); +function conversionTest4(groupName: | "downcast" | "dataDowncast" | "editingDowncast" | `${{} & string}Downcast`) {} +conversionTest4("testDowncast"); function foo(str: `${`a${string}` & `${string}a`}Test`) {} foo("abaTest"); // ok diff --git a/tests/cases/fourslash/stringLiteralCompletionsForOpenEndedTemplateLiteralType.ts b/tests/cases/fourslash/stringLiteralCompletionsForOpenEndedTemplateLiteralType.ts index 92c02a23a2854..c5472fab365ad 100644 --- a/tests/cases/fourslash/stringLiteralCompletionsForOpenEndedTemplateLiteralType.ts +++ b/tests/cases/fourslash/stringLiteralCompletionsForOpenEndedTemplateLiteralType.ts @@ -1,6 +1,6 @@ /// -//// function conversionTest(groupName: | "downcast" | "dataDowncast" | "editingDowncast" | `${string & {}}Downcast`) {} +//// function conversionTest(groupName: | "downcast" | "dataDowncast" | "editingDowncast" | `${string}Downcast` & {}) {} //// conversionTest("/**/"); verify.completions({ marker: "", exact: ["downcast", "dataDowncast", "editingDowncast"] });