mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-06-10 18:04:18 -05:00
Make never inferences with template literal types only in special cases (#46075)
* Make 'never' inferences with template literal types only in special cases * Accept new baselines * Add regression test * Fix comment
This commit is contained in:
@@ -21939,8 +21939,16 @@ namespace ts {
|
||||
function inferToTemplateLiteralType(source: Type, target: TemplateLiteralType) {
|
||||
const matches = inferTypesFromTemplateLiteralType(source, target);
|
||||
const types = target.types;
|
||||
for (let i = 0; i < types.length; i++) {
|
||||
inferFromTypes(matches ? matches[i] : neverType, types[i]);
|
||||
// When the target template literal contains only placeholders (meaning that inference is intended to extract
|
||||
// single characters and remainder strings) and inference fails to produce matches, we want to infer 'never' for
|
||||
// each placeholder such that instantiation with the inferred value(s) produces 'never', a type for which an
|
||||
// assignment check will fail. If we make no inferences, we'll likely end up with the constraint 'string' which,
|
||||
// upon instantiation, would collapse all the placeholders to just 'string', and an assignment check might
|
||||
// succeed. That would be a pointless and confusing outcome.
|
||||
if (matches || every(target.texts, s => s.length === 0)) {
|
||||
for (let i = 0; i < types.length; i++) {
|
||||
inferFromTypes(matches ? matches[i] : neverType, types[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -419,7 +419,7 @@ type Foo<T> = T extends `*${infer S}*` ? S : never;
|
||||
>Foo : Foo<T>
|
||||
|
||||
type TF1 = Foo<any>; // never
|
||||
>TF1 : never
|
||||
>TF1 : string
|
||||
|
||||
type TF2 = Foo<string>; // never
|
||||
>TF2 : never
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
tests/cases/conformance/types/literal/templateLiteralTypes3.ts(20,19): error TS2345: Argument of type 'string' is not assignable to parameter of type 'never'.
|
||||
tests/cases/conformance/types/literal/templateLiteralTypes3.ts(20,19): error TS2345: Argument of type '"hello"' is not assignable to parameter of type '`*${string}*`'.
|
||||
tests/cases/conformance/types/literal/templateLiteralTypes3.ts(57,5): error TS2322: Type '"hello"' is not assignable to type '`*${string}*`'.
|
||||
tests/cases/conformance/types/literal/templateLiteralTypes3.ts(69,5): error TS2322: Type '"123"' is not assignable to type '`*${number}*`'.
|
||||
tests/cases/conformance/types/literal/templateLiteralTypes3.ts(71,5): error TS2322: Type '"**123**"' is not assignable to type '`*${number}*`'.
|
||||
@@ -29,7 +29,7 @@ tests/cases/conformance/types/literal/templateLiteralTypes3.ts(74,5): error TS23
|
||||
function f1<T extends string>(s: string, n: number, b: boolean, t: T) {
|
||||
let x1 = foo1('hello'); // Error
|
||||
~~~~~~~
|
||||
!!! error TS2345: Argument of type 'string' is not assignable to parameter of type 'never'.
|
||||
!!! error TS2345: Argument of type '"hello"' is not assignable to parameter of type '`*${string}*`'.
|
||||
let x2 = foo1('*hello*');
|
||||
let x3 = foo1('**hello**');
|
||||
let x4 = foo1(`*${s}*` as const);
|
||||
@@ -138,4 +138,12 @@ tests/cases/conformance/types/literal/templateLiteralTypes3.ts(74,5): error TS23
|
||||
interface ITest<P extends Prefixes, E extends AllPrefixData = PrefixData<P>> {
|
||||
blah: string;
|
||||
}
|
||||
|
||||
// Repro from #45906
|
||||
|
||||
type Schema = { a: { b: { c: number } } };
|
||||
|
||||
declare function chain<F extends keyof Schema>(field: F | `${F}.${F}`): void;
|
||||
|
||||
chain("a");
|
||||
|
||||
@@ -116,6 +116,14 @@ type PrefixData<P extends Prefixes> = `${P}:baz`;
|
||||
interface ITest<P extends Prefixes, E extends AllPrefixData = PrefixData<P>> {
|
||||
blah: string;
|
||||
}
|
||||
|
||||
// Repro from #45906
|
||||
|
||||
type Schema = { a: { b: { c: number } } };
|
||||
|
||||
declare function chain<F extends keyof Schema>(field: F | `${F}.${F}`): void;
|
||||
|
||||
chain("a");
|
||||
|
||||
|
||||
//// [templateLiteralTypes3.js]
|
||||
@@ -168,6 +176,7 @@ var templated1 = value1 + " abc";
|
||||
// Type '`${string} abc`' is not assignable to type '`${string} ${string}`'.
|
||||
var value2 = "abc";
|
||||
var templated2 = value2 + " abc";
|
||||
chain("a");
|
||||
|
||||
|
||||
//// [templateLiteralTypes3.d.ts]
|
||||
@@ -216,3 +225,11 @@ declare type PrefixData<P extends Prefixes> = `${P}:baz`;
|
||||
interface ITest<P extends Prefixes, E extends AllPrefixData = PrefixData<P>> {
|
||||
blah: string;
|
||||
}
|
||||
declare type Schema = {
|
||||
a: {
|
||||
b: {
|
||||
c: number;
|
||||
};
|
||||
};
|
||||
};
|
||||
declare function chain<F extends keyof Schema>(field: F | `${F}.${F}`): void;
|
||||
|
||||
@@ -385,3 +385,23 @@ interface ITest<P extends Prefixes, E extends AllPrefixData = PrefixData<P>> {
|
||||
>blah : Symbol(ITest.blah, Decl(templateLiteralTypes3.ts, 114, 78))
|
||||
}
|
||||
|
||||
// Repro from #45906
|
||||
|
||||
type Schema = { a: { b: { c: number } } };
|
||||
>Schema : Symbol(Schema, Decl(templateLiteralTypes3.ts, 116, 1))
|
||||
>a : Symbol(a, Decl(templateLiteralTypes3.ts, 120, 15))
|
||||
>b : Symbol(b, Decl(templateLiteralTypes3.ts, 120, 20))
|
||||
>c : Symbol(c, Decl(templateLiteralTypes3.ts, 120, 25))
|
||||
|
||||
declare function chain<F extends keyof Schema>(field: F | `${F}.${F}`): void;
|
||||
>chain : Symbol(chain, Decl(templateLiteralTypes3.ts, 120, 42))
|
||||
>F : Symbol(F, Decl(templateLiteralTypes3.ts, 122, 23))
|
||||
>Schema : Symbol(Schema, Decl(templateLiteralTypes3.ts, 116, 1))
|
||||
>field : Symbol(field, Decl(templateLiteralTypes3.ts, 122, 47))
|
||||
>F : Symbol(F, Decl(templateLiteralTypes3.ts, 122, 23))
|
||||
>F : Symbol(F, Decl(templateLiteralTypes3.ts, 122, 23))
|
||||
>F : Symbol(F, Decl(templateLiteralTypes3.ts, 122, 23))
|
||||
|
||||
chain("a");
|
||||
>chain : Symbol(chain, Decl(templateLiteralTypes3.ts, 120, 42))
|
||||
|
||||
|
||||
@@ -49,8 +49,8 @@ function f1<T extends string>(s: string, n: number, b: boolean, t: T) {
|
||||
>t : T
|
||||
|
||||
let x1 = foo1('hello'); // Error
|
||||
>x1 : never
|
||||
>foo1('hello') : never
|
||||
>x1 : string
|
||||
>foo1('hello') : string
|
||||
>foo1 : <V extends string>(arg: `*${V}*`) => V
|
||||
>'hello' : "hello"
|
||||
|
||||
@@ -379,3 +379,20 @@ interface ITest<P extends Prefixes, E extends AllPrefixData = PrefixData<P>> {
|
||||
>blah : string
|
||||
}
|
||||
|
||||
// Repro from #45906
|
||||
|
||||
type Schema = { a: { b: { c: number } } };
|
||||
>Schema : Schema
|
||||
>a : { b: { c: number;}; }
|
||||
>b : { c: number; }
|
||||
>c : number
|
||||
|
||||
declare function chain<F extends keyof Schema>(field: F | `${F}.${F}`): void;
|
||||
>chain : <F extends "a">(field: F | `${F}.${F}`) => void
|
||||
>field : F | `${F}.${F}`
|
||||
|
||||
chain("a");
|
||||
>chain("a") : void
|
||||
>chain : <F extends "a">(field: F | `${F}.${F}`) => void
|
||||
>"a" : "a"
|
||||
|
||||
|
||||
@@ -118,3 +118,11 @@ type PrefixData<P extends Prefixes> = `${P}:baz`;
|
||||
interface ITest<P extends Prefixes, E extends AllPrefixData = PrefixData<P>> {
|
||||
blah: string;
|
||||
}
|
||||
|
||||
// Repro from #45906
|
||||
|
||||
type Schema = { a: { b: { c: number } } };
|
||||
|
||||
declare function chain<F extends keyof Schema>(field: F | `${F}.${F}`): void;
|
||||
|
||||
chain("a");
|
||||
|
||||
Reference in New Issue
Block a user