Skip to content

Commit

Permalink
Fixed inference between type placeholders with non-string constraints…
Browse files Browse the repository at this point in the history
… in template literal types (#57808)
  • Loading branch information
Andarist authored Mar 18, 2024
1 parent 6086292 commit a46664a
Show file tree
Hide file tree
Showing 5 changed files with 175 additions and 1 deletion.
4 changes: 3 additions & 1 deletion src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25532,7 +25532,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
function inferTypesFromTemplateLiteralType(source: Type, target: TemplateLiteralType): Type[] | undefined {
return source.flags & TypeFlags.StringLiteral ? inferFromLiteralPartsToTemplateLiteral([(source as StringLiteralType).value], emptyArray, target) :
source.flags & TypeFlags.TemplateLiteral ?
arraysEqual((source as TemplateLiteralType).texts, target.texts) ? map((source as TemplateLiteralType).types, getStringLikeTypeForType) :
arraysEqual((source as TemplateLiteralType).texts, target.texts) ? map((source as TemplateLiteralType).types, (s, i) => {
return isTypeAssignableTo(getBaseConstraintOrType(s), getBaseConstraintOrType(target.types[i])) ? s : getStringLikeTypeForType(s);
}) :
inferFromLiteralPartsToTemplateLiteral((source as TemplateLiteralType).texts, (source as TemplateLiteralType).types, target) :
undefined;
}
Expand Down
34 changes: 34 additions & 0 deletions tests/baselines/reference/templateLiteralTypes7.errors.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
templateLiteralTypes7.ts(16,7): error TS2322: Type '<T extends 1 | 2 | 3>(x: `${T}`) => NMap[T]' is not assignable to type 'G2'.
Types of parameters 'x' and 'x' are incompatible.
Type '`${T}`' is not assignable to type '"1" | "2" | "3"'.
Type '"1" | "2" | "3" | "4"' is not assignable to type '"1" | "2" | "3"'.
Type '"4"' is not assignable to type '"1" | "2" | "3"'.


==== templateLiteralTypes7.ts (1 errors) ====
// https://github.com/microsoft/TypeScript/issues/57807

interface NMap {
1: 'A'
2: 'B'
3: 'C'
4: 'D'
}

declare const g: <T extends 1 | 2 | 3>(x: `${T}`) => NMap[T]

type G1 = <T extends 1 | 2 | 3>(x: `${T}`) => NMap[T]
const g1: G1 = g; // ok

type G2 = <T extends 1 | 2 | 3 | 4>(x: `${T}`) => NMap[T]
const g2: G2 = g; // error
~~
!!! error TS2322: Type '<T extends 1 | 2 | 3>(x: `${T}`) => NMap[T]' is not assignable to type 'G2'.
!!! error TS2322: Types of parameters 'x' and 'x' are incompatible.
!!! error TS2322: Type '`${T}`' is not assignable to type '"1" | "2" | "3"'.
!!! error TS2322: Type '"1" | "2" | "3" | "4"' is not assignable to type '"1" | "2" | "3"'.
!!! error TS2322: Type '"4"' is not assignable to type '"1" | "2" | "3"'.

type G3 = <T extends 1 | 2>(x: `${T}`) => NMap[T]
const g3: G3 = g; // ok

68 changes: 68 additions & 0 deletions tests/baselines/reference/templateLiteralTypes7.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
//// [tests/cases/conformance/types/literal/templateLiteralTypes7.ts] ////

=== templateLiteralTypes7.ts ===
// https://github.com/microsoft/TypeScript/issues/57807

interface NMap {
>NMap : Symbol(NMap, Decl(templateLiteralTypes7.ts, 0, 0))

1: 'A'
>1 : Symbol(NMap[1], Decl(templateLiteralTypes7.ts, 2, 16))

2: 'B'
>2 : Symbol(NMap[2], Decl(templateLiteralTypes7.ts, 3, 8))

3: 'C'
>3 : Symbol(NMap[3], Decl(templateLiteralTypes7.ts, 4, 8))

4: 'D'
>4 : Symbol(NMap[4], Decl(templateLiteralTypes7.ts, 5, 8))
}

declare const g: <T extends 1 | 2 | 3>(x: `${T}`) => NMap[T]
>g : Symbol(g, Decl(templateLiteralTypes7.ts, 9, 13))
>T : Symbol(T, Decl(templateLiteralTypes7.ts, 9, 18))
>x : Symbol(x, Decl(templateLiteralTypes7.ts, 9, 39))
>T : Symbol(T, Decl(templateLiteralTypes7.ts, 9, 18))
>NMap : Symbol(NMap, Decl(templateLiteralTypes7.ts, 0, 0))
>T : Symbol(T, Decl(templateLiteralTypes7.ts, 9, 18))

type G1 = <T extends 1 | 2 | 3>(x: `${T}`) => NMap[T]
>G1 : Symbol(G1, Decl(templateLiteralTypes7.ts, 9, 60))
>T : Symbol(T, Decl(templateLiteralTypes7.ts, 11, 11))
>x : Symbol(x, Decl(templateLiteralTypes7.ts, 11, 32))
>T : Symbol(T, Decl(templateLiteralTypes7.ts, 11, 11))
>NMap : Symbol(NMap, Decl(templateLiteralTypes7.ts, 0, 0))
>T : Symbol(T, Decl(templateLiteralTypes7.ts, 11, 11))

const g1: G1 = g; // ok
>g1 : Symbol(g1, Decl(templateLiteralTypes7.ts, 12, 5))
>G1 : Symbol(G1, Decl(templateLiteralTypes7.ts, 9, 60))
>g : Symbol(g, Decl(templateLiteralTypes7.ts, 9, 13))

type G2 = <T extends 1 | 2 | 3 | 4>(x: `${T}`) => NMap[T]
>G2 : Symbol(G2, Decl(templateLiteralTypes7.ts, 12, 17))
>T : Symbol(T, Decl(templateLiteralTypes7.ts, 14, 11))
>x : Symbol(x, Decl(templateLiteralTypes7.ts, 14, 36))
>T : Symbol(T, Decl(templateLiteralTypes7.ts, 14, 11))
>NMap : Symbol(NMap, Decl(templateLiteralTypes7.ts, 0, 0))
>T : Symbol(T, Decl(templateLiteralTypes7.ts, 14, 11))

const g2: G2 = g; // error
>g2 : Symbol(g2, Decl(templateLiteralTypes7.ts, 15, 5))
>G2 : Symbol(G2, Decl(templateLiteralTypes7.ts, 12, 17))
>g : Symbol(g, Decl(templateLiteralTypes7.ts, 9, 13))

type G3 = <T extends 1 | 2>(x: `${T}`) => NMap[T]
>G3 : Symbol(G3, Decl(templateLiteralTypes7.ts, 15, 17))
>T : Symbol(T, Decl(templateLiteralTypes7.ts, 17, 11))
>x : Symbol(x, Decl(templateLiteralTypes7.ts, 17, 28))
>T : Symbol(T, Decl(templateLiteralTypes7.ts, 17, 11))
>NMap : Symbol(NMap, Decl(templateLiteralTypes7.ts, 0, 0))
>T : Symbol(T, Decl(templateLiteralTypes7.ts, 17, 11))

const g3: G3 = g; // ok
>g3 : Symbol(g3, Decl(templateLiteralTypes7.ts, 18, 5))
>G3 : Symbol(G3, Decl(templateLiteralTypes7.ts, 15, 17))
>g : Symbol(g, Decl(templateLiteralTypes7.ts, 9, 13))

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

=== templateLiteralTypes7.ts ===
// https://github.com/microsoft/TypeScript/issues/57807

interface NMap {
1: 'A'
>1 : "A"

2: 'B'
>2 : "B"

3: 'C'
>3 : "C"

4: 'D'
>4 : "D"
}

declare const g: <T extends 1 | 2 | 3>(x: `${T}`) => NMap[T]
>g : <T extends 1 | 2 | 3>(x: `${T}`) => NMap[T]
>x : `${T}`

type G1 = <T extends 1 | 2 | 3>(x: `${T}`) => NMap[T]
>G1 : <T extends 1 | 2 | 3>(x: `${T}`) => NMap[T]
>x : `${T}`

const g1: G1 = g; // ok
>g1 : G1
>g : <T extends 1 | 2 | 3>(x: `${T}`) => NMap[T]

type G2 = <T extends 1 | 2 | 3 | 4>(x: `${T}`) => NMap[T]
>G2 : <T extends 1 | 2 | 3 | 4>(x: `${T}`) => NMap[T]
>x : `${T}`

const g2: G2 = g; // error
>g2 : G2
>g : <T extends 1 | 2 | 3>(x: `${T}`) => NMap[T]

type G3 = <T extends 1 | 2>(x: `${T}`) => NMap[T]
>G3 : <T extends 1 | 2>(x: `${T}`) => NMap[T]
>x : `${T}`

const g3: G3 = g; // ok
>g3 : G3
>g : <T extends 1 | 2 | 3>(x: `${T}`) => NMap[T]

23 changes: 23 additions & 0 deletions tests/cases/conformance/types/literal/templateLiteralTypes7.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// @strict: true
// @target: esnext
// @noEmit: true

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

interface NMap {
1: 'A'
2: 'B'
3: 'C'
4: 'D'
}

declare const g: <T extends 1 | 2 | 3>(x: `${T}`) => NMap[T]

type G1 = <T extends 1 | 2 | 3>(x: `${T}`) => NMap[T]
const g1: G1 = g; // ok

type G2 = <T extends 1 | 2 | 3 | 4>(x: `${T}`) => NMap[T]
const g2: G2 = g; // error

type G3 = <T extends 1 | 2>(x: `${T}`) => NMap[T]
const g3: G3 = g; // ok

0 comments on commit a46664a

Please sign in to comment.