diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index f27a6058006e5..4b84f804ddcc1 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -16925,10 +16925,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) { @@ -17439,20 +17436,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; @@ -17702,7 +17696,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function addSpans(texts: readonly string[], types: readonly Type[]): boolean { for (let i = 0; i < types.length; i++) { - const t = types[i]; + const t = stripObjectTypeTags(types[i]); if (t.flags & (TypeFlags.Literal | TypeFlags.Null | TypeFlags.Undefined)) { text += getTemplateStringForType(t) || ""; text += texts[i + 1]; @@ -17725,6 +17719,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } + function stripObjectTypeTags(type: Type) { + if (type.flags & TypeFlags.Intersection) { + const nonObjectTypes = filter((type as IntersectionType).types, t => !(t.flags & TypeFlags.Object)); + if (nonObjectTypes !== (type as IntersectionType).types) { + return getIntersectionType(nonObjectTypes); + } + } + return type; + } + function getTemplateStringForType(type: Type) { return type.flags & TypeFlags.StringLiteral ? (type as StringLiteralType).value : type.flags & TypeFlags.NumberLiteral ? "" + (type as NumberLiteralType).value : @@ -17735,7 +17739,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; @@ -18059,13 +18062,15 @@ 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 !!(type.flags & (TypeFlags.Any | TypeFlags.String | TypeFlags.Number | TypeFlags.BigInt)) || isPatternLiteralType(type); + return !!(type.flags & (TypeFlags.Any | TypeFlags.String | TypeFlags.Number | TypeFlags.BigInt) || + isPatternLiteralType(type) || + type.flags & TypeFlags.Intersection && every((type as IntersectionType).types, isPatternLiteralType)); } 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. Assumptions are made elsewhere that pattern literal + // contain no generics. For example, pattern literal types can be key types in index signatures. return !!(type.flags & TypeFlags.TemplateLiteral) && every((type as TemplateLiteralType).types, isPatternLiteralPlaceholderType) || !!(type.flags & TypeFlags.StringMapping) && isPatternLiteralPlaceholderType((type as StringMappingType).type); } @@ -18083,12 +18088,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)) { @@ -18098,7 +18103,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 { @@ -24768,7 +24773,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 34a2835822302..d96277b936052 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -6130,7 +6130,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 */ @@ -6289,7 +6289,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 */ @@ -6316,7 +6316,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 @@ -6675,8 +6675,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/templateLiteralIntersection.types b/tests/baselines/reference/templateLiteralIntersection.types index 8f78e9df181c4..0ac35ea707064 100644 --- a/tests/baselines/reference/templateLiteralIntersection.types +++ b/tests/baselines/reference/templateLiteralIntersection.types @@ -18,7 +18,7 @@ type OriginA1 = `${A}` >OriginA1 : "a" type OriginA2 = `${MixA}` ->OriginA2 : `${MixA}` +>OriginA2 : "a" type B = `${typeof a}` >B : "a" @@ -32,23 +32,23 @@ type OriginB1 = `${B}` >OriginB1 : "a" type OriginB2 = `${MixB}` ->OriginB2 : `${MixB}` +>OriginB2 : "a" type MixC = { foo: string } & A >MixC : { foo: string; } & "a" >foo : string type OriginC = `${MixC}` ->OriginC : `${MixC}` +>OriginC : "a" type MixD = ->MixD : `${T & { foo: string; }}` +>MixD : `${T}` `${T & { foo: string }}` >foo : string type OriginD = `${MixD & { foo: string }}`; ->OriginD : `${`${"a" & { foo: string; } & { foo: string; }}` & { foo: string; }}` +>OriginD : "a" >foo : string >foo : string diff --git a/tests/baselines/reference/templateLiteralIntersection2.errors.txt b/tests/baselines/reference/templateLiteralIntersection2.errors.txt index 95dfa11417777..3e65620072625 100644 --- a/tests/baselines/reference/templateLiteralIntersection2.errors.txt +++ b/tests/baselines/reference/templateLiteralIntersection2.errors.txt @@ -1,11 +1,10 @@ -templateLiteralIntersection2.ts(7,12): error TS2345: Argument of type '"foo/bar"' is not assignable to parameter of type '`${Path}/${Path}`'. templateLiteralIntersection2.ts(20,10): error TS2345: Argument of type '""' is not assignable to parameter of type '`a${string}` & `${string}a`'. Type '""' is not assignable to type '`a${string}`'. templateLiteralIntersection2.ts(22,10): error TS2345: Argument of type '"ab"' is not assignable to parameter of type '`a${string}` & `${string}a`'. Type '"ab"' is not assignable to type '`${string}a`'. -==== templateLiteralIntersection2.ts (3 errors) ==== +==== templateLiteralIntersection2.ts (2 errors) ==== type Path = string & { _pathBrand: any }; type JoinedPath = `${Path}/${Path}`; @@ -13,8 +12,6 @@ templateLiteralIntersection2.ts(22,10): error TS2345: Argument of type '"ab"' is declare function joinedPath(p: JoinedPath): void; joinedPath("foo/bar"); - ~~~~~~~~~ -!!! error TS2345: Argument of type '"foo/bar"' is not assignable to parameter of type '`${Path}/${Path}`'. declare const somePath: Path; diff --git a/tests/baselines/reference/templateLiteralIntersection2.types b/tests/baselines/reference/templateLiteralIntersection2.types index e67e43ca3a945..3381e99669e16 100644 --- a/tests/baselines/reference/templateLiteralIntersection2.types +++ b/tests/baselines/reference/templateLiteralIntersection2.types @@ -6,15 +6,15 @@ type Path = string & { _pathBrand: any }; >_pathBrand : any type JoinedPath = `${Path}/${Path}`; ->JoinedPath : `${Path}/${Path}` +>JoinedPath : `${string}/${string}` declare function joinedPath(p: JoinedPath): void; >joinedPath : (p: JoinedPath) => void ->p : `${Path}/${Path}` +>p : `${string}/${string}` joinedPath("foo/bar"); >joinedPath("foo/bar") : void ->joinedPath : (p: `${Path}/${Path}`) => void +>joinedPath : (p: `${string}/${string}`) => void >"foo/bar" : "foo/bar" declare const somePath: Path; @@ -22,8 +22,8 @@ declare const somePath: Path; joinedPath(`${somePath}/${somePath}`); >joinedPath(`${somePath}/${somePath}`) : void ->joinedPath : (p: `${Path}/${Path}`) => void ->`${somePath}/${somePath}` : `${Path}/${Path}` +>joinedPath : (p: `${string}/${string}`) => void +>`${somePath}/${somePath}` : `${string}/${string}` >somePath : Path >somePath : Path diff --git a/tests/baselines/reference/templateLiteralIntersection3.types b/tests/baselines/reference/templateLiteralIntersection3.types index d045095001667..9ccf6aea3ee1f 100644 --- a/tests/baselines/reference/templateLiteralIntersection3.types +++ b/tests/baselines/reference/templateLiteralIntersection3.types @@ -24,19 +24,19 @@ options1[`foo/${path}`] = false; >options1[`foo/${path}`] = false : false >options1[`foo/${path}`] : boolean >options1 : { prop: number; } & { [k: string]: boolean; } ->`foo/${path}` : `foo/${Path}` +>`foo/${path}` : `foo/${string}` >path : Path >false : false // Lowercase<`foo/${Path}`> => `foo/${Lowercase}` declare const lowercasePath: Lowercase<`foo/${Path}`>; ->lowercasePath : `foo/${Lowercase<`${Path}`>}` +>lowercasePath : `foo/${Lowercase}` options1[lowercasePath] = false; >options1[lowercasePath] = false : false >options1[lowercasePath] : boolean >options1 : { prop: number; } & { [k: string]: boolean; } ->lowercasePath : `foo/${Lowercase<`${Path}`>}` +>lowercasePath : `foo/${Lowercase}` >false : false 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..617b8c7442156 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 : `${string}Downcast` | "downcast" + +conversionTest3("testDowncast"); +>conversionTest3("testDowncast") : void +>conversionTest3 : (groupName: `${string}Downcast` | "downcast") => void +>"testDowncast" : "testDowncast" + +function conversionTest4(groupName: | "downcast" | "dataDowncast" | "editingDowncast" | `${{} & string}Downcast`) {} +>conversionTest4 : (groupName: "downcast" | "dataDowncast" | "editingDowncast" | `${{} & string}Downcast`) => void +>groupName : `${string}Downcast` | "downcast" + +conversionTest4("testDowncast"); +>conversionTest4("testDowncast") : void +>conversionTest4 : (groupName: `${string}Downcast` | "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"] });