mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Unwrap NoInfer types when narrowing (#58292)
This commit is contained in:
@@ -29479,6 +29479,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
}
|
||||
|
||||
function getNarrowableTypeForReference(type: Type, reference: Node, checkMode?: CheckMode) {
|
||||
if (isNoInferType(type)) {
|
||||
type = (type as SubstitutionType).baseType;
|
||||
}
|
||||
// When the type of a reference is or contains an instantiable type with a union type constraint, and
|
||||
// when the reference is in a constraint position (where it is known we'll obtain the apparent type) or
|
||||
// has a contextual type containing no top-level instantiables (meaning constraints will determine
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
//// [tests/cases/compiler/narrowingNoInfer1.ts] ////
|
||||
|
||||
=== narrowingNoInfer1.ts ===
|
||||
// https://github.com/microsoft/TypeScript/issues/58266
|
||||
|
||||
type TaggedA = { _tag: "a" };
|
||||
>TaggedA : Symbol(TaggedA, Decl(narrowingNoInfer1.ts, 0, 0))
|
||||
>_tag : Symbol(_tag, Decl(narrowingNoInfer1.ts, 2, 16))
|
||||
|
||||
type TaggedB = { _tag: "b" };
|
||||
>TaggedB : Symbol(TaggedB, Decl(narrowingNoInfer1.ts, 2, 29))
|
||||
>_tag : Symbol(_tag, Decl(narrowingNoInfer1.ts, 3, 16))
|
||||
|
||||
type TaggedUnion = TaggedA | TaggedB;
|
||||
>TaggedUnion : Symbol(TaggedUnion, Decl(narrowingNoInfer1.ts, 3, 29))
|
||||
>TaggedA : Symbol(TaggedA, Decl(narrowingNoInfer1.ts, 0, 0))
|
||||
>TaggedB : Symbol(TaggedB, Decl(narrowingNoInfer1.ts, 2, 29))
|
||||
|
||||
const m: { result: NoInfer<TaggedUnion> }[] = [];
|
||||
>m : Symbol(m, Decl(narrowingNoInfer1.ts, 7, 5))
|
||||
>result : Symbol(result, Decl(narrowingNoInfer1.ts, 7, 10))
|
||||
>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --))
|
||||
>TaggedUnion : Symbol(TaggedUnion, Decl(narrowingNoInfer1.ts, 3, 29))
|
||||
|
||||
function map<A, B>(items: readonly A[], f: (a: NoInfer<A>) => B) {
|
||||
>map : Symbol(map, Decl(narrowingNoInfer1.ts, 7, 49))
|
||||
>A : Symbol(A, Decl(narrowingNoInfer1.ts, 9, 13))
|
||||
>B : Symbol(B, Decl(narrowingNoInfer1.ts, 9, 15))
|
||||
>items : Symbol(items, Decl(narrowingNoInfer1.ts, 9, 19))
|
||||
>A : Symbol(A, Decl(narrowingNoInfer1.ts, 9, 13))
|
||||
>f : Symbol(f, Decl(narrowingNoInfer1.ts, 9, 39))
|
||||
>a : Symbol(a, Decl(narrowingNoInfer1.ts, 9, 44))
|
||||
>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --))
|
||||
>A : Symbol(A, Decl(narrowingNoInfer1.ts, 9, 13))
|
||||
>B : Symbol(B, Decl(narrowingNoInfer1.ts, 9, 15))
|
||||
|
||||
return items.map(f);
|
||||
>items.map : Symbol(ReadonlyArray.map, Decl(lib.es5.d.ts, --, --))
|
||||
>items : Symbol(items, Decl(narrowingNoInfer1.ts, 9, 19))
|
||||
>map : Symbol(ReadonlyArray.map, Decl(lib.es5.d.ts, --, --))
|
||||
>f : Symbol(f, Decl(narrowingNoInfer1.ts, 9, 39))
|
||||
}
|
||||
|
||||
const something = map(m, (_) =>
|
||||
>something : Symbol(something, Decl(narrowingNoInfer1.ts, 13, 5))
|
||||
>map : Symbol(map, Decl(narrowingNoInfer1.ts, 7, 49))
|
||||
>m : Symbol(m, Decl(narrowingNoInfer1.ts, 7, 5))
|
||||
>_ : Symbol(_, Decl(narrowingNoInfer1.ts, 13, 26))
|
||||
|
||||
_.result._tag === "a" ? { ..._, result: _.result } : null,
|
||||
>_.result._tag : Symbol(_tag, Decl(narrowingNoInfer1.ts, 2, 16), Decl(narrowingNoInfer1.ts, 3, 16))
|
||||
>_.result : Symbol(result, Decl(narrowingNoInfer1.ts, 7, 10))
|
||||
>_ : Symbol(_, Decl(narrowingNoInfer1.ts, 13, 26))
|
||||
>result : Symbol(result, Decl(narrowingNoInfer1.ts, 7, 10))
|
||||
>_tag : Symbol(_tag, Decl(narrowingNoInfer1.ts, 2, 16), Decl(narrowingNoInfer1.ts, 3, 16))
|
||||
>_ : Symbol(_, Decl(narrowingNoInfer1.ts, 13, 26))
|
||||
>result : Symbol(result, Decl(narrowingNoInfer1.ts, 14, 33))
|
||||
>_.result : Symbol(result, Decl(narrowingNoInfer1.ts, 7, 10))
|
||||
>_ : Symbol(_, Decl(narrowingNoInfer1.ts, 13, 26))
|
||||
>result : Symbol(result, Decl(narrowingNoInfer1.ts, 7, 10))
|
||||
|
||||
);
|
||||
|
||||
declare function test2<T1, T2>(a: T1, b: T2, cb: (thing: NoInfer<T1> | NoInfer<T2>) => void): void;
|
||||
>test2 : Symbol(test2, Decl(narrowingNoInfer1.ts, 15, 2))
|
||||
>T1 : Symbol(T1, Decl(narrowingNoInfer1.ts, 17, 23))
|
||||
>T2 : Symbol(T2, Decl(narrowingNoInfer1.ts, 17, 26))
|
||||
>a : Symbol(a, Decl(narrowingNoInfer1.ts, 17, 31))
|
||||
>T1 : Symbol(T1, Decl(narrowingNoInfer1.ts, 17, 23))
|
||||
>b : Symbol(b, Decl(narrowingNoInfer1.ts, 17, 37))
|
||||
>T2 : Symbol(T2, Decl(narrowingNoInfer1.ts, 17, 26))
|
||||
>cb : Symbol(cb, Decl(narrowingNoInfer1.ts, 17, 44))
|
||||
>thing : Symbol(thing, Decl(narrowingNoInfer1.ts, 17, 50))
|
||||
>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --))
|
||||
>T1 : Symbol(T1, Decl(narrowingNoInfer1.ts, 17, 23))
|
||||
>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --))
|
||||
>T2 : Symbol(T2, Decl(narrowingNoInfer1.ts, 17, 26))
|
||||
|
||||
test2({ type: 'a' as const }, { type: 'b' as const }, (thing) => {
|
||||
>test2 : Symbol(test2, Decl(narrowingNoInfer1.ts, 15, 2))
|
||||
>type : Symbol(type, Decl(narrowingNoInfer1.ts, 19, 7))
|
||||
>const : Symbol(const)
|
||||
>type : Symbol(type, Decl(narrowingNoInfer1.ts, 19, 31))
|
||||
>const : Symbol(const)
|
||||
>thing : Symbol(thing, Decl(narrowingNoInfer1.ts, 19, 55))
|
||||
|
||||
if (thing.type === "a") {
|
||||
>thing.type : Symbol(type, Decl(narrowingNoInfer1.ts, 19, 7), Decl(narrowingNoInfer1.ts, 19, 31))
|
||||
>thing : Symbol(thing, Decl(narrowingNoInfer1.ts, 19, 55))
|
||||
>type : Symbol(type, Decl(narrowingNoInfer1.ts, 19, 7), Decl(narrowingNoInfer1.ts, 19, 31))
|
||||
|
||||
thing;
|
||||
>thing : Symbol(thing, Decl(narrowingNoInfer1.ts, 19, 55))
|
||||
|
||||
} else {
|
||||
thing;
|
||||
>thing : Symbol(thing, Decl(narrowingNoInfer1.ts, 19, 55))
|
||||
}
|
||||
});
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
//// [tests/cases/compiler/narrowingNoInfer1.ts] ////
|
||||
|
||||
=== narrowingNoInfer1.ts ===
|
||||
// https://github.com/microsoft/TypeScript/issues/58266
|
||||
|
||||
type TaggedA = { _tag: "a" };
|
||||
>TaggedA : TaggedA
|
||||
> : ^^^^^^^
|
||||
>_tag : "a"
|
||||
> : ^^^
|
||||
|
||||
type TaggedB = { _tag: "b" };
|
||||
>TaggedB : TaggedB
|
||||
> : ^^^^^^^
|
||||
>_tag : "b"
|
||||
> : ^^^
|
||||
|
||||
type TaggedUnion = TaggedA | TaggedB;
|
||||
>TaggedUnion : TaggedUnion
|
||||
> : ^^^^^^^^^^^
|
||||
|
||||
const m: { result: NoInfer<TaggedUnion> }[] = [];
|
||||
>m : { result: NoInfer<TaggedUnion>; }[]
|
||||
> : ^^^^^^^^^^ ^^^^^
|
||||
>result : NoInfer<TaggedUnion>
|
||||
> : ^^^^^^^^^^^^^^^^^^^^
|
||||
>[] : never[]
|
||||
> : ^^^^^^^
|
||||
|
||||
function map<A, B>(items: readonly A[], f: (a: NoInfer<A>) => B) {
|
||||
>map : <A, B>(items: readonly A[], f: (a: NoInfer<A>) => B) => B[]
|
||||
> : ^ ^^ ^^ ^^ ^^ ^^ ^^^^^^^^
|
||||
>items : readonly A[]
|
||||
> : ^^^^^^^^^^^^
|
||||
>f : (a: NoInfer<A>) => B
|
||||
> : ^ ^^ ^^^^^
|
||||
>a : NoInfer<A>
|
||||
> : ^^^^^^^^^^
|
||||
|
||||
return items.map(f);
|
||||
>items.map(f) : B[]
|
||||
> : ^^^
|
||||
>items.map : <U>(callbackfn: (value: A, index: number, array: readonly A[]) => U, thisArg?: any) => U[]
|
||||
> : ^^^^ ^^^ ^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^ ^^^ ^^^^^^
|
||||
>items : readonly A[]
|
||||
> : ^^^^^^^^^^^^
|
||||
>map : <U>(callbackfn: (value: A, index: number, array: readonly A[]) => U, thisArg?: any) => U[]
|
||||
> : ^^^^ ^^^ ^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^ ^^^ ^^^^^^
|
||||
>f : (a: NoInfer<A>) => B
|
||||
> : ^ ^^ ^^^^^
|
||||
}
|
||||
|
||||
const something = map(m, (_) =>
|
||||
>something : ({ result: TaggedA; } | null)[]
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
>map(m, (_) => _.result._tag === "a" ? { ..._, result: _.result } : null,) : ({ result: TaggedA; } | null)[]
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
>map : <A, B>(items: readonly A[], f: (a: NoInfer<A>) => B) => B[]
|
||||
> : ^ ^^ ^^ ^^ ^^ ^^ ^^^^^^^^
|
||||
>m : { result: NoInfer<TaggedUnion>; }[]
|
||||
> : ^^^^^^^^^^ ^^^^^
|
||||
>(_) => _.result._tag === "a" ? { ..._, result: _.result } : null : (_: NoInfer<{ result: NoInfer<TaggedUnion>; }>) => { result: TaggedA; } | null
|
||||
> : ^ ^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
>_ : NoInfer<{ result: NoInfer<TaggedUnion>; }>
|
||||
> : ^^^^^^^^^^^^^^^^^^ ^^^^
|
||||
|
||||
_.result._tag === "a" ? { ..._, result: _.result } : null,
|
||||
>_.result._tag === "a" ? { ..._, result: _.result } : null : { result: TaggedA; } | null
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
>_.result._tag === "a" : boolean
|
||||
> : ^^^^^^^
|
||||
>_.result._tag : "a" | "b"
|
||||
> : ^^^^^^^^^
|
||||
>_.result : TaggedUnion
|
||||
> : ^^^^^^^^^^^
|
||||
>_ : { result: NoInfer<TaggedUnion>; }
|
||||
> : ^^^^^^^^^^ ^^^
|
||||
>result : TaggedUnion
|
||||
> : ^^^^^^^^^^^
|
||||
>_tag : "a" | "b"
|
||||
> : ^^^^^^^^^
|
||||
>"a" : "a"
|
||||
> : ^^^
|
||||
>{ ..._, result: _.result } : { result: TaggedA; }
|
||||
> : ^^^^^^^^^^^^^^^^^^^^
|
||||
>_ : { result: NoInfer<TaggedUnion>; }
|
||||
> : ^^^^^^^^^^ ^^^
|
||||
>result : TaggedA
|
||||
> : ^^^^^^^
|
||||
>_.result : TaggedA
|
||||
> : ^^^^^^^
|
||||
>_ : { result: NoInfer<TaggedUnion>; }
|
||||
> : ^^^^^^^^^^ ^^^
|
||||
>result : TaggedA
|
||||
> : ^^^^^^^
|
||||
|
||||
);
|
||||
|
||||
declare function test2<T1, T2>(a: T1, b: T2, cb: (thing: NoInfer<T1> | NoInfer<T2>) => void): void;
|
||||
>test2 : <T1, T2>(a: T1, b: T2, cb: (thing: NoInfer<T1> | NoInfer<T2>) => void) => void
|
||||
> : ^ ^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^^^^
|
||||
>a : T1
|
||||
> : ^^
|
||||
>b : T2
|
||||
> : ^^
|
||||
>cb : (thing: NoInfer<T1> | NoInfer<T2>) => void
|
||||
> : ^ ^^ ^^^^^
|
||||
>thing : NoInfer<T1> | NoInfer<T2>
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
test2({ type: 'a' as const }, { type: 'b' as const }, (thing) => {
|
||||
>test2({ type: 'a' as const }, { type: 'b' as const }, (thing) => { if (thing.type === "a") { thing; } else { thing; }}) : void
|
||||
> : ^^^^
|
||||
>test2 : <T1, T2>(a: T1, b: T2, cb: (thing: NoInfer<T1> | NoInfer<T2>) => void) => void
|
||||
> : ^ ^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^^^^
|
||||
>{ type: 'a' as const } : { type: "a"; }
|
||||
> : ^^^^^^^^^^^^^^
|
||||
>type : "a"
|
||||
> : ^^^
|
||||
>'a' as const : "a"
|
||||
> : ^^^
|
||||
>'a' : "a"
|
||||
> : ^^^
|
||||
>{ type: 'b' as const } : { type: "b"; }
|
||||
> : ^^^^^^^^^^^^^^
|
||||
>type : "b"
|
||||
> : ^^^
|
||||
>'b' as const : "b"
|
||||
> : ^^^
|
||||
>'b' : "b"
|
||||
> : ^^^
|
||||
>(thing) => { if (thing.type === "a") { thing; } else { thing; }} : (thing: NoInfer<{ type: "a"; }> | NoInfer<{ type: "b"; }>) => void
|
||||
> : ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
>thing : NoInfer<{ type: "a"; }> | NoInfer<{ type: "b"; }>
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
if (thing.type === "a") {
|
||||
>thing.type === "a" : boolean
|
||||
> : ^^^^^^^
|
||||
>thing.type : "a" | "b"
|
||||
> : ^^^^^^^^^
|
||||
>thing : NoInfer<{ type: "a"; }> | NoInfer<{ type: "b"; }>
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
>type : "a" | "b"
|
||||
> : ^^^^^^^^^
|
||||
>"a" : "a"
|
||||
> : ^^^
|
||||
|
||||
thing;
|
||||
>thing : NoInfer<{ type: "a"; }>
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
} else {
|
||||
thing;
|
||||
>thing : NoInfer<{ type: "b"; }>
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
}
|
||||
});
|
||||
|
||||
@@ -460,12 +460,12 @@ class OkClass<T> {
|
||||
> : ^
|
||||
|
||||
return this._value; // ok
|
||||
>this._value : NoInfer<T>
|
||||
> : ^^^^^^^^^^
|
||||
>this._value : T
|
||||
> : ^
|
||||
>this : this
|
||||
> : ^^^^
|
||||
>_value : NoInfer<T>
|
||||
> : ^^^^^^^^^^
|
||||
>_value : T
|
||||
> : ^
|
||||
}
|
||||
}
|
||||
class OkClass2<T> {
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
// @strict: true
|
||||
// @noEmit: true
|
||||
|
||||
// https://github.com/microsoft/TypeScript/issues/58266
|
||||
|
||||
type TaggedA = { _tag: "a" };
|
||||
type TaggedB = { _tag: "b" };
|
||||
|
||||
type TaggedUnion = TaggedA | TaggedB;
|
||||
|
||||
const m: { result: NoInfer<TaggedUnion> }[] = [];
|
||||
|
||||
function map<A, B>(items: readonly A[], f: (a: NoInfer<A>) => B) {
|
||||
return items.map(f);
|
||||
}
|
||||
|
||||
const something = map(m, (_) =>
|
||||
_.result._tag === "a" ? { ..._, result: _.result } : null,
|
||||
);
|
||||
|
||||
declare function test2<T1, T2>(a: T1, b: T2, cb: (thing: NoInfer<T1> | NoInfer<T2>) => void): void;
|
||||
|
||||
test2({ type: 'a' as const }, { type: 'b' as const }, (thing) => {
|
||||
if (thing.type === "a") {
|
||||
thing;
|
||||
} else {
|
||||
thing;
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user