diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 9cba48a9378..9aefcc9f5d3 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -13683,6 +13683,9 @@ namespace ts { return getLiteralType(text); } newTexts.push(text); + if (every(newTexts, t => t === "") && every(newTypes, t => !!(t.flags & TypeFlags.String))) { + return stringType; + } const id = `${getTypeListId(newTypes)}|${map(newTexts, t => t.length).join(",")}|${newTexts.join("")}`; let type = templateLiteralTypes.get(id); if (!type) { @@ -21056,7 +21059,8 @@ namespace ts { return TypeFacts.None; } if (flags & TypeFlags.Instantiable) { - return getTypeFacts(getBaseConstraintOfType(type) || unknownType); + return !isPatternLiteralType(type) ? getTypeFacts(getBaseConstraintOfType(type) || unknownType) : + strictNullChecks ? TypeFacts.NonEmptyStringStrictFacts : TypeFacts.NonEmptyStringFacts; } if (flags & TypeFlags.UnionOrIntersection) { return getTypeFactsOfTypes((type).types); diff --git a/tests/baselines/reference/templateLiteralTypesPatterns.errors.txt b/tests/baselines/reference/templateLiteralTypesPatterns.errors.txt index 672e2d9b625..ee8de629218 100644 --- a/tests/baselines/reference/templateLiteralTypesPatterns.errors.txt +++ b/tests/baselines/reference/templateLiteralTypesPatterns.errors.txt @@ -347,4 +347,30 @@ tests/cases/conformance/types/literal/templateLiteralTypesPatterns.ts(160,7): er var bb: `${number}`; var bb: `${number}` | '0'; + + // Normalize `${string}` to just string + + type T2S = `${A}${B}`; + + type S10 = `${string}`; // string + type S11 = `${string}${string}${string}`; // string + type S12 = T2S; // string + + function ff1(x: `${string}-${string}`) { + let s1 = x && 42; // number + let s2 = x || 42; // `${string}-${string}` + } + + // Repro from #41651 + + export type Id = `${TId}-${TId}`; + + export class AA {} + + export abstract class BB { + abstract get(id: Id): void; + update(id: Id): void { + this.get(id!); + } + } \ No newline at end of file diff --git a/tests/baselines/reference/templateLiteralTypesPatterns.js b/tests/baselines/reference/templateLiteralTypesPatterns.js index 8dc75965dd7..c3d2758dbdc 100644 --- a/tests/baselines/reference/templateLiteralTypesPatterns.js +++ b/tests/baselines/reference/templateLiteralTypesPatterns.js @@ -174,10 +174,38 @@ let t3: `foo1` | '1foo' | 'foofoo' | `foo${string}` | 'foox' | 'xfoo' | `${numbe var bb: `${number}`; var bb: `${number}` | '0'; + +// Normalize `${string}` to just string + +type T2S = `${A}${B}`; + +type S10 = `${string}`; // string +type S11 = `${string}${string}${string}`; // string +type S12 = T2S; // string + +function ff1(x: `${string}-${string}`) { + let s1 = x && 42; // number + let s2 = x || 42; // `${string}-${string}` +} + +// Repro from #41651 + +export type Id = `${TId}-${TId}`; + +export class AA {} + +export abstract class BB { + abstract get(id: Id): void; + update(id: Id): void { + this.get(id!); + } +} //// [templateLiteralTypesPatterns.js] "use strict"; +exports.__esModule = true; +exports.BB = exports.AA = void 0; // ok var a = "/bin"; // not ok @@ -304,3 +332,22 @@ var t2; // `foo${string}` | '1foo' | 'xfoo' var t3; // `foo${string}` | xfoo' | `${number}foo` var bb; var bb; +function ff1(x) { + var s1 = x && 42; // number + var s2 = x || 42; // `${string}-${string}` +} +var AA = /** @class */ (function () { + function AA() { + } + return AA; +}()); +exports.AA = AA; +var BB = /** @class */ (function () { + function BB() { + } + BB.prototype.update = function (id) { + this.get(id); + }; + return BB; +}()); +exports.BB = BB; diff --git a/tests/baselines/reference/templateLiteralTypesPatterns.symbols b/tests/baselines/reference/templateLiteralTypesPatterns.symbols index 605543882a2..95d25249747 100644 --- a/tests/baselines/reference/templateLiteralTypesPatterns.symbols +++ b/tests/baselines/reference/templateLiteralTypesPatterns.symbols @@ -418,3 +418,70 @@ var bb: `${number}`; var bb: `${number}` | '0'; >bb : Symbol(bb, Decl(templateLiteralTypesPatterns.ts, 173, 3), Decl(templateLiteralTypesPatterns.ts, 174, 3)) +// Normalize `${string}` to just string + +type T2S = `${A}${B}`; +>T2S : Symbol(T2S, Decl(templateLiteralTypesPatterns.ts, 174, 26)) +>A : Symbol(A, Decl(templateLiteralTypesPatterns.ts, 178, 9)) +>B : Symbol(B, Decl(templateLiteralTypesPatterns.ts, 178, 26)) +>A : Symbol(A, Decl(templateLiteralTypesPatterns.ts, 178, 9)) +>B : Symbol(B, Decl(templateLiteralTypesPatterns.ts, 178, 26)) + +type S10 = `${string}`; // string +>S10 : Symbol(S10, Decl(templateLiteralTypesPatterns.ts, 178, 58)) + +type S11 = `${string}${string}${string}`; // string +>S11 : Symbol(S11, Decl(templateLiteralTypesPatterns.ts, 180, 23)) + +type S12 = T2S; // string +>S12 : Symbol(S12, Decl(templateLiteralTypesPatterns.ts, 181, 41)) +>T2S : Symbol(T2S, Decl(templateLiteralTypesPatterns.ts, 174, 26)) + +function ff1(x: `${string}-${string}`) { +>ff1 : Symbol(ff1, Decl(templateLiteralTypesPatterns.ts, 182, 31)) +>x : Symbol(x, Decl(templateLiteralTypesPatterns.ts, 184, 13)) + + let s1 = x && 42; // number +>s1 : Symbol(s1, Decl(templateLiteralTypesPatterns.ts, 185, 7)) +>x : Symbol(x, Decl(templateLiteralTypesPatterns.ts, 184, 13)) + + let s2 = x || 42; // `${string}-${string}` +>s2 : Symbol(s2, Decl(templateLiteralTypesPatterns.ts, 186, 7)) +>x : Symbol(x, Decl(templateLiteralTypesPatterns.ts, 184, 13)) +} + +// Repro from #41651 + +export type Id = `${TId}-${TId}`; +>Id : Symbol(Id, Decl(templateLiteralTypesPatterns.ts, 187, 1)) +>TA : Symbol(TA, Decl(templateLiteralTypesPatterns.ts, 191, 15)) +>TId : Symbol(TId, Decl(templateLiteralTypesPatterns.ts, 191, 18)) +>TId : Symbol(TId, Decl(templateLiteralTypesPatterns.ts, 191, 18)) +>TId : Symbol(TId, Decl(templateLiteralTypesPatterns.ts, 191, 18)) + +export class AA {} +>AA : Symbol(AA, Decl(templateLiteralTypesPatterns.ts, 191, 66)) + +export abstract class BB { +>BB : Symbol(BB, Decl(templateLiteralTypesPatterns.ts, 193, 18)) + + abstract get(id: Id): void; +>get : Symbol(BB.get, Decl(templateLiteralTypesPatterns.ts, 195, 26)) +>id : Symbol(id, Decl(templateLiteralTypesPatterns.ts, 196, 17)) +>Id : Symbol(Id, Decl(templateLiteralTypesPatterns.ts, 187, 1)) +>AA : Symbol(AA, Decl(templateLiteralTypesPatterns.ts, 191, 66)) + + update(id: Id): void { +>update : Symbol(BB.update, Decl(templateLiteralTypesPatterns.ts, 196, 35)) +>id : Symbol(id, Decl(templateLiteralTypesPatterns.ts, 197, 11)) +>Id : Symbol(Id, Decl(templateLiteralTypesPatterns.ts, 187, 1)) +>AA : Symbol(AA, Decl(templateLiteralTypesPatterns.ts, 191, 66)) + + this.get(id!); +>this.get : Symbol(BB.get, Decl(templateLiteralTypesPatterns.ts, 195, 26)) +>this : Symbol(BB, Decl(templateLiteralTypesPatterns.ts, 193, 18)) +>get : Symbol(BB.get, Decl(templateLiteralTypesPatterns.ts, 195, 26)) +>id : Symbol(id, Decl(templateLiteralTypesPatterns.ts, 197, 11)) + } +} + diff --git a/tests/baselines/reference/templateLiteralTypesPatterns.types b/tests/baselines/reference/templateLiteralTypesPatterns.types index bdfe13262d8..c8cb9320ac4 100644 --- a/tests/baselines/reference/templateLiteralTypesPatterns.types +++ b/tests/baselines/reference/templateLiteralTypesPatterns.types @@ -577,3 +577,63 @@ var bb: `${number}`; var bb: `${number}` | '0'; >bb : `${number}` +// Normalize `${string}` to just string + +type T2S = `${A}${B}`; +>T2S : `${A}${B}` + +type S10 = `${string}`; // string +>S10 : string + +type S11 = `${string}${string}${string}`; // string +>S11 : string + +type S12 = T2S; // string +>S12 : string + +function ff1(x: `${string}-${string}`) { +>ff1 : (x: `${string}-${string}`) => void +>x : `${string}-${string}` + + let s1 = x && 42; // number +>s1 : number +>x && 42 : 42 +>x : `${string}-${string}` +>42 : 42 + + let s2 = x || 42; // `${string}-${string}` +>s2 : `${string}-${string}` +>x || 42 : `${string}-${string}` +>x : `${string}-${string}` +>42 : 42 +} + +// Repro from #41651 + +export type Id = `${TId}-${TId}`; +>Id : `${TId}-${TId}` + +export class AA {} +>AA : AA + +export abstract class BB { +>BB : BB + + abstract get(id: Id): void; +>get : (id: Id) => void +>id : `${string}-${string}` + + update(id: Id): void { +>update : (id: Id) => void +>id : `${string}-${string}` + + this.get(id!); +>this.get(id!) : void +>this.get : (id: `${string}-${string}`) => void +>this : this +>get : (id: `${string}-${string}`) => void +>id! : `${string}-${string}` +>id : `${string}-${string}` + } +} + diff --git a/tests/cases/conformance/types/literal/templateLiteralTypesPatterns.ts b/tests/cases/conformance/types/literal/templateLiteralTypesPatterns.ts index b8f5fad334b..a98facd4359 100644 --- a/tests/cases/conformance/types/literal/templateLiteralTypesPatterns.ts +++ b/tests/cases/conformance/types/literal/templateLiteralTypesPatterns.ts @@ -174,3 +174,29 @@ let t3: `foo1` | '1foo' | 'foofoo' | `foo${string}` | 'foox' | 'xfoo' | `${numbe var bb: `${number}`; var bb: `${number}` | '0'; + +// Normalize `${string}` to just string + +type T2S = `${A}${B}`; + +type S10 = `${string}`; // string +type S11 = `${string}${string}${string}`; // string +type S12 = T2S; // string + +function ff1(x: `${string}-${string}`) { + let s1 = x && 42; // number + let s2 = x || 42; // `${string}-${string}` +} + +// Repro from #41651 + +export type Id = `${TId}-${TId}`; + +export class AA {} + +export abstract class BB { + abstract get(id: Id): void; + update(id: Id): void { + this.get(id!); + } +}