Fixed inference between type placeholders with non-string constraints in template literal types (#57808)

This commit is contained in:
Mateusz Burzyński 2024-03-18 21:52:57 +01:00 committed by GitHub
parent 6086292f66
commit a46664ac64
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 175 additions and 1 deletions

View File

@ -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;
}

View File

@ -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

View File

@ -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))

View File

@ -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]

View File

@ -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