Skip to content

Commit

Permalink
Treat primitive and object Intersection Type inside TemplateLiteral a…
Browse files Browse the repository at this point in the history
…s primitive
  • Loading branch information
horita-yuya committed Feb 15, 2025
1 parent 34ea32f commit da3fbd7
Show file tree
Hide file tree
Showing 7 changed files with 268 additions and 0 deletions.
15 changes: 15 additions & 0 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22913,6 +22913,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}
}

if (source.flags & TypeFlags.TemplateLiteral) {
if (target.flags & TypeFlags.StringLike) {
const resolvedPrimitiveTypes = (source as TemplateLiteralType).types.flatMap(type => {
if (type.flags & TypeFlags.Intersection && (type as IntersectionType).types.every(type => type.flags & TypeFlags.Primitive || type.flags & TypeFlags.Object)) {
return (type as IntersectionType).types.filter(t => t.flags & TypeFlags.Primitive);
}
else {
return [type];
}
});

(source as TemplateLiteralType).types = resolvedPrimitiveTypes;
}
}

// We limit alias variance probing to only object and conditional types since their alias behavior
// is more predictable than other, interned types, which may or may not have an alias depending on
// the order in which things were checked.
Expand Down
35 changes: 35 additions & 0 deletions tests/baselines/reference/brandedLiteralRevert1.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
//// [tests/cases/compiler/brandedLiteralRevert1.ts] ////

=== brandedLiteralRevert1.ts ===
// https://github.com/microsoft/TypeScript/issues/60990

type N0 = number & {
>N0 : Symbol(N0, Decl(brandedLiteralRevert1.ts, 0, 0))

test: "TEST"
>test : Symbol(test, Decl(brandedLiteralRevert1.ts, 2, 20))
}

type N1 = 3 & {
>N1 : Symbol(N1, Decl(brandedLiteralRevert1.ts, 4, 1))

test: "TEST"
>test : Symbol(test, Decl(brandedLiteralRevert1.ts, 6, 15))
}

declare let n0: N0
>n0 : Symbol(n0, Decl(brandedLiteralRevert1.ts, 10, 11))
>N0 : Symbol(N0, Decl(brandedLiteralRevert1.ts, 0, 0))

declare let n1: N1
>n1 : Symbol(n1, Decl(brandedLiteralRevert1.ts, 11, 11))
>N1 : Symbol(N1, Decl(brandedLiteralRevert1.ts, 4, 1))

let m0: `${number}` = `${n0}` // ok
>m0 : Symbol(m0, Decl(brandedLiteralRevert1.ts, 13, 3))
>n0 : Symbol(n0, Decl(brandedLiteralRevert1.ts, 10, 11))

let m1: "3" = `${n1}` // ok
>m1 : Symbol(m1, Decl(brandedLiteralRevert1.ts, 14, 3))
>n1 : Symbol(n1, Decl(brandedLiteralRevert1.ts, 11, 11))

47 changes: 47 additions & 0 deletions tests/baselines/reference/brandedLiteralRevert1.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
//// [tests/cases/compiler/brandedLiteralRevert1.ts] ////

=== brandedLiteralRevert1.ts ===
// https://github.com/microsoft/TypeScript/issues/60990

type N0 = number & {
>N0 : N0
> : ^^

test: "TEST"
>test : "TEST"
> : ^^^^^^
}

type N1 = 3 & {
>N1 : N1
> : ^^

test: "TEST"
>test : "TEST"
> : ^^^^^^
}

declare let n0: N0
>n0 : N0
> : ^^

declare let n1: N1
>n1 : N1
> : ^^

let m0: `${number}` = `${n0}` // ok
>m0 : `${number}`
> : ^^^^^^^^^^^
>`${n0}` : `${number}`
> : ^^^^^^^^^^^
>n0 : N0
> : ^^

let m1: "3" = `${n1}` // ok
>m1 : "3"
> : ^^^
>`${n1}` : `${3}`
> : ^^^^^^
>n1 : N1
> : ^^

50 changes: 50 additions & 0 deletions tests/baselines/reference/brandedLiteralRevert2.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
//// [tests/cases/compiler/brandedLiteralRevert2.ts] ////

=== brandedLiteralRevert2.ts ===
// https://github.com/microsoft/TypeScript/issues/60990

type Brand1 = number & 1 & {
>Brand1 : Symbol(Brand1, Decl(brandedLiteralRevert2.ts, 0, 0))

test: "TEST"
>test : Symbol(test, Decl(brandedLiteralRevert2.ts, 2, 28))
}

type Brand2 = "a" & {
>Brand2 : Symbol(Brand2, Decl(brandedLiteralRevert2.ts, 4, 1))

test: "TEST1"
>test : Symbol(test, Decl(brandedLiteralRevert2.ts, 6, 21))
}

let brandN1: Brand1 = 1 as Brand1
>brandN1 : Symbol(brandN1, Decl(brandedLiteralRevert2.ts, 10, 3))
>Brand1 : Symbol(Brand1, Decl(brandedLiteralRevert2.ts, 0, 0))
>Brand1 : Symbol(Brand1, Decl(brandedLiteralRevert2.ts, 0, 0))

let brandN2: Brand2 = "a" as Brand2
>brandN2 : Symbol(brandN2, Decl(brandedLiteralRevert2.ts, 11, 3))
>Brand2 : Symbol(Brand2, Decl(brandedLiteralRevert2.ts, 4, 1))
>Brand2 : Symbol(Brand2, Decl(brandedLiteralRevert2.ts, 4, 1))

let brandM11: `${number}` = `${brandN1}` // ok
>brandM11 : Symbol(brandM11, Decl(brandedLiteralRevert2.ts, 13, 3))
>brandN1 : Symbol(brandN1, Decl(brandedLiteralRevert2.ts, 10, 3))

let brandM12: "1" = `${brandN1}` // ok
>brandM12 : Symbol(brandM12, Decl(brandedLiteralRevert2.ts, 14, 3))
>brandN1 : Symbol(brandN1, Decl(brandedLiteralRevert2.ts, 10, 3))

let brandM13: `${1}` = `${brandN1}` // ok
>brandM13 : Symbol(brandM13, Decl(brandedLiteralRevert2.ts, 15, 3))
>brandN1 : Symbol(brandN1, Decl(brandedLiteralRevert2.ts, 10, 3))

let brandM21: "a" = `${brandN2}` // ok
>brandM21 : Symbol(brandM21, Decl(brandedLiteralRevert2.ts, 17, 3))
>brandN2 : Symbol(brandN2, Decl(brandedLiteralRevert2.ts, 11, 3))

let brandM22: "1a" = `${brandN1}${brandN2}` // ok
>brandM22 : Symbol(brandM22, Decl(brandedLiteralRevert2.ts, 18, 3))
>brandN1 : Symbol(brandN1, Decl(brandedLiteralRevert2.ts, 10, 3))
>brandN2 : Symbol(brandN2, Decl(brandedLiteralRevert2.ts, 11, 3))

81 changes: 81 additions & 0 deletions tests/baselines/reference/brandedLiteralRevert2.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
//// [tests/cases/compiler/brandedLiteralRevert2.ts] ////

=== brandedLiteralRevert2.ts ===
// https://github.com/microsoft/TypeScript/issues/60990

type Brand1 = number & 1 & {
>Brand1 : Brand1
> : ^^^^^^

test: "TEST"
>test : "TEST"
> : ^^^^^^
}

type Brand2 = "a" & {
>Brand2 : Brand2
> : ^^^^^^

test: "TEST1"
>test : "TEST1"
> : ^^^^^^^
}

let brandN1: Brand1 = 1 as Brand1
>brandN1 : Brand1
> : ^^^^^^
>1 as Brand1 : Brand1
> : ^^^^^^
>1 : 1
> : ^

let brandN2: Brand2 = "a" as Brand2
>brandN2 : Brand2
> : ^^^^^^
>"a" as Brand2 : Brand2
> : ^^^^^^
>"a" : "a"
> : ^^^

let brandM11: `${number}` = `${brandN1}` // ok
>brandM11 : `${number}`
> : ^^^^^^^^^^^
>`${brandN1}` : `${1}`
> : ^^^^^^
>brandN1 : Brand1
> : ^^^^^^

let brandM12: "1" = `${brandN1}` // ok
>brandM12 : "1"
> : ^^^
>`${brandN1}` : `${1}`
> : ^^^^^^
>brandN1 : Brand1
> : ^^^^^^

let brandM13: `${1}` = `${brandN1}` // ok
>brandM13 : "1"
> : ^^^
>`${brandN1}` : `${1}`
> : ^^^^^^
>brandN1 : Brand1
> : ^^^^^^

let brandM21: "a" = `${brandN2}` // ok
>brandM21 : "a"
> : ^^^
>`${brandN2}` : `${"a"}`
> : ^^^^^^^^
>brandN2 : Brand2
> : ^^^^^^

let brandM22: "1a" = `${brandN1}${brandN2}` // ok
>brandM22 : "1a"
> : ^^^^
>`${brandN1}${brandN2}` : `${1}${"a"}`
> : ^^^^^^^^^^^^
>brandN1 : Brand1
> : ^^^^^^
>brandN2 : Brand2
> : ^^^^^^

18 changes: 18 additions & 0 deletions tests/cases/compiler/brandedLiteralRevert1.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// @strict: true
// @noEmit: true

// https://github.com/microsoft/TypeScript/issues/60990

type N0 = number & {
test: "TEST"
}

type N1 = 3 & {
test: "TEST"
}

declare let n0: N0
declare let n1: N1

let m0: `${number}` = `${n0}` // ok
let m1: "3" = `${n1}` // ok
22 changes: 22 additions & 0 deletions tests/cases/compiler/brandedLiteralRevert2.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// @strict: true
// @noEmit: true

// https://github.com/microsoft/TypeScript/issues/60990

type Brand1 = number & 1 & {
test: "TEST"
}

type Brand2 = "a" & {
test: "TEST1"
}

let brandN1: Brand1 = 1 as Brand1
let brandN2: Brand2 = "a" as Brand2

let brandM11: `${number}` = `${brandN1}` // ok
let brandM12: "1" = `${brandN1}` // ok
let brandM13: `${1}` = `${brandN1}` // ok

let brandM21: "a" = `${brandN2}` // ok
let brandM22: "1a" = `${brandN1}${brandN2}` // ok

0 comments on commit da3fbd7

Please sign in to comment.