Skip to content

Commit bb05122

Browse files
authored
Merge pull request microsoft#22197 from Microsoft/fixConditionalTypes
Conditional type fixes
2 parents 24d3035 + 9c965aa commit bb05122

15 files changed

+239
-169
lines changed

src/compiler/checker.ts

+132-101
Large diffs are not rendered by default.

src/compiler/types.ts

+16-5
Original file line numberDiff line numberDiff line change
@@ -3821,16 +3821,27 @@ namespace ts {
38213821
type: InstantiableType | UnionOrIntersectionType;
38223822
}
38233823

3824-
// T extends U ? X : Y (TypeFlags.Conditional)
3825-
export interface ConditionalType extends InstantiableType {
3824+
export interface ConditionalRoot {
3825+
node: ConditionalTypeNode;
38263826
checkType: Type;
38273827
extendsType: Type;
38283828
trueType: Type;
38293829
falseType: Type;
3830-
/* @internal */
3830+
isDistributive: boolean;
38313831
inferTypeParameters: TypeParameter[];
3832-
/* @internal */
3833-
target?: ConditionalType;
3832+
outerTypeParameters?: TypeParameter[];
3833+
instantiations?: Map<Type>;
3834+
aliasSymbol: Symbol;
3835+
aliasTypeArguments: Type[];
3836+
}
3837+
3838+
// T extends U ? X : Y (TypeFlags.Conditional)
3839+
export interface ConditionalType extends InstantiableType {
3840+
root: ConditionalRoot;
3841+
checkType: Type;
3842+
extendsType: Type;
3843+
resolvedTrueType?: Type;
3844+
resolvedFalseType?: Type;
38343845
/* @internal */
38353846
mapper?: TypeMapper;
38363847
}

tests/baselines/reference/api/tsserverlibrary.d.ts

+15-1
Original file line numberDiff line numberDiff line change
@@ -2192,11 +2192,25 @@ declare namespace ts {
21922192
interface IndexType extends InstantiableType {
21932193
type: InstantiableType | UnionOrIntersectionType;
21942194
}
2195-
interface ConditionalType extends InstantiableType {
2195+
interface ConditionalRoot {
2196+
node: ConditionalTypeNode;
21962197
checkType: Type;
21972198
extendsType: Type;
21982199
trueType: Type;
21992200
falseType: Type;
2201+
isDistributive: boolean;
2202+
inferTypeParameters: TypeParameter[];
2203+
outerTypeParameters?: TypeParameter[];
2204+
instantiations?: Map<Type>;
2205+
aliasSymbol: Symbol;
2206+
aliasTypeArguments: Type[];
2207+
}
2208+
interface ConditionalType extends InstantiableType {
2209+
root: ConditionalRoot;
2210+
checkType: Type;
2211+
extendsType: Type;
2212+
resolvedTrueType?: Type;
2213+
resolvedFalseType?: Type;
22002214
}
22012215
interface SubstitutionType extends InstantiableType {
22022216
typeParameter: TypeParameter;

tests/baselines/reference/api/typescript.d.ts

+15-1
Original file line numberDiff line numberDiff line change
@@ -2192,11 +2192,25 @@ declare namespace ts {
21922192
interface IndexType extends InstantiableType {
21932193
type: InstantiableType | UnionOrIntersectionType;
21942194
}
2195-
interface ConditionalType extends InstantiableType {
2195+
interface ConditionalRoot {
2196+
node: ConditionalTypeNode;
21962197
checkType: Type;
21972198
extendsType: Type;
21982199
trueType: Type;
21992200
falseType: Type;
2201+
isDistributive: boolean;
2202+
inferTypeParameters: TypeParameter[];
2203+
outerTypeParameters?: TypeParameter[];
2204+
instantiations?: Map<Type>;
2205+
aliasSymbol: Symbol;
2206+
aliasTypeArguments: Type[];
2207+
}
2208+
interface ConditionalType extends InstantiableType {
2209+
root: ConditionalRoot;
2210+
checkType: Type;
2211+
extendsType: Type;
2212+
resolvedTrueType?: Type;
2213+
resolvedFalseType?: Type;
22002214
}
22012215
interface SubstitutionType extends InstantiableType {
22022216
typeParameter: TypeParameter;

tests/baselines/reference/conditionalTypes1.errors.txt

+4-4
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ tests/cases/conformance/types/conditional/conditionalTypes1.ts(275,43): error TS
157157

158158
type T20 = TypeName<string | (() => void)>; // "string" | "function"
159159
type T21 = TypeName<any>; // "string" | "number" | "boolean" | "undefined" | "function" | "object"
160-
type T22 = TypeName<never>; // "string" | "number" | "boolean" | "undefined" | "function" | "object"
160+
type T22 = TypeName<never>; // never
161161
type T23 = TypeName<{}>; // "object"
162162

163163
type KnockoutObservable<T> = { object: T };
@@ -329,7 +329,7 @@ tests/cases/conformance/types/conditional/conditionalTypes1.ts(275,43): error TS
329329
type Q1 = IsString<number>; // false
330330
type Q2 = IsString<"abc">; // true
331331
type Q3 = IsString<any>; // boolean
332-
type Q4 = IsString<never>; // boolean
332+
type Q4 = IsString<never>; // never
333333

334334
type N1 = Not<false>; // true
335335
type N2 = Not<true>; // false
@@ -357,9 +357,9 @@ tests/cases/conformance/types/conditional/conditionalTypes1.ts(275,43): error TS
357357

358358
type T40 = never extends never ? true : false; // true
359359
type T41 = number extends never ? true : false; // false
360-
type T42 = never extends number ? true : false; // boolean
360+
type T42 = never extends number ? true : false; // true
361361

362-
type IsNever<T> = T extends never ? true : false;
362+
type IsNever<T> = [T] extends [never] ? true : false;
363363

364364
type T50 = IsNever<never>; // true
365365
type T51 = IsNever<number>; // false

tests/baselines/reference/conditionalTypes1.js

+6-6
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ type TypeName<T> =
6464

6565
type T20 = TypeName<string | (() => void)>; // "string" | "function"
6666
type T21 = TypeName<any>; // "string" | "number" | "boolean" | "undefined" | "function" | "object"
67-
type T22 = TypeName<never>; // "string" | "number" | "boolean" | "undefined" | "function" | "object"
67+
type T22 = TypeName<never>; // never
6868
type T23 = TypeName<{}>; // "object"
6969

7070
type KnockoutObservable<T> = { object: T };
@@ -172,7 +172,7 @@ type IsString<T> = Extends<T, string>;
172172
type Q1 = IsString<number>; // false
173173
type Q2 = IsString<"abc">; // true
174174
type Q3 = IsString<any>; // boolean
175-
type Q4 = IsString<never>; // boolean
175+
type Q4 = IsString<never>; // never
176176

177177
type N1 = Not<false>; // true
178178
type N2 = Not<true>; // false
@@ -200,9 +200,9 @@ type O9 = Or<boolean, boolean>; // boolean
200200

201201
type T40 = never extends never ? true : false; // true
202202
type T41 = number extends never ? true : false; // false
203-
type T42 = never extends number ? true : false; // boolean
203+
type T42 = never extends number ? true : false; // true
204204

205-
type IsNever<T> = T extends never ? true : false;
205+
type IsNever<T> = [T] extends [never] ? true : false;
206206

207207
type T50 = IsNever<never>; // true
208208
type T51 = IsNever<number>; // false
@@ -551,7 +551,7 @@ declare type O9 = Or<boolean, boolean>;
551551
declare type T40 = never extends never ? true : false;
552552
declare type T41 = number extends never ? true : false;
553553
declare type T42 = never extends number ? true : false;
554-
declare type IsNever<T> = T extends never ? true : false;
554+
declare type IsNever<T> = [T] extends [never] ? true : false;
555555
declare type T50 = IsNever<never>;
556556
declare type T51 = IsNever<number>;
557557
declare type T52 = IsNever<any>;
@@ -572,7 +572,7 @@ declare type T82 = Eq2<false, true>;
572572
declare type T83 = Eq2<false, false>;
573573
declare type Foo<T> = T extends string ? boolean : number;
574574
declare type Bar<T> = T extends string ? boolean : number;
575-
declare const convert: <U>(value: Foo<U>) => Foo<U>;
575+
declare const convert: <U>(value: Foo<U>) => Bar<U>;
576576
declare type Baz<T> = Foo<T>;
577577
declare const convert2: <T>(value: Foo<T>) => Foo<T>;
578578
declare function f31<T>(): void;

tests/baselines/reference/conditionalTypes1.symbols

+5-5
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ type T21 = TypeName<any>; // "string" | "number" | "boolean" | "undefined" | "f
243243
>T21 : Symbol(T21, Decl(conditionalTypes1.ts, 63, 43))
244244
>TypeName : Symbol(TypeName, Decl(conditionalTypes1.ts, 53, 43))
245245

246-
type T22 = TypeName<never>; // "string" | "number" | "boolean" | "undefined" | "function" | "object"
246+
type T22 = TypeName<never>; // never
247247
>T22 : Symbol(T22, Decl(conditionalTypes1.ts, 64, 25))
248248
>TypeName : Symbol(TypeName, Decl(conditionalTypes1.ts, 53, 43))
249249

@@ -668,7 +668,7 @@ type Q3 = IsString<any>; // boolean
668668
>Q3 : Symbol(Q3, Decl(conditionalTypes1.ts, 171, 26))
669669
>IsString : Symbol(IsString, Decl(conditionalTypes1.ts, 166, 63))
670670

671-
type Q4 = IsString<never>; // boolean
671+
type Q4 = IsString<never>; // never
672672
>Q4 : Symbol(Q4, Decl(conditionalTypes1.ts, 172, 24))
673673
>IsString : Symbol(IsString, Decl(conditionalTypes1.ts, 166, 63))
674674

@@ -762,16 +762,16 @@ type T40 = never extends never ? true : false; // true
762762
type T41 = number extends never ? true : false; // false
763763
>T41 : Symbol(T41, Decl(conditionalTypes1.ts, 199, 46))
764764

765-
type T42 = never extends number ? true : false; // boolean
765+
type T42 = never extends number ? true : false; // true
766766
>T42 : Symbol(T42, Decl(conditionalTypes1.ts, 200, 47))
767767

768-
type IsNever<T> = T extends never ? true : false;
768+
type IsNever<T> = [T] extends [never] ? true : false;
769769
>IsNever : Symbol(IsNever, Decl(conditionalTypes1.ts, 201, 47))
770770
>T : Symbol(T, Decl(conditionalTypes1.ts, 203, 13))
771771
>T : Symbol(T, Decl(conditionalTypes1.ts, 203, 13))
772772

773773
type T50 = IsNever<never>; // true
774-
>T50 : Symbol(T50, Decl(conditionalTypes1.ts, 203, 49))
774+
>T50 : Symbol(T50, Decl(conditionalTypes1.ts, 203, 53))
775775
>IsNever : Symbol(IsNever, Decl(conditionalTypes1.ts, 201, 47))
776776

777777
type T51 = IsNever<number>; // false

tests/baselines/reference/conditionalTypes1.types

+13-13
Original file line numberDiff line numberDiff line change
@@ -254,8 +254,8 @@ type T21 = TypeName<any>; // "string" | "number" | "boolean" | "undefined" | "f
254254
>T21 : "string" | "number" | "boolean" | "undefined" | "object" | "function"
255255
>TypeName : TypeName<T>
256256

257-
type T22 = TypeName<never>; // "string" | "number" | "boolean" | "undefined" | "function" | "object"
258-
>T22 : "string" | "number" | "boolean" | "undefined" | "object" | "function"
257+
type T22 = TypeName<never>; // never
258+
>T22 : never
259259
>TypeName : TypeName<T>
260260

261261
type T23 = TypeName<{}>; // "object"
@@ -741,8 +741,8 @@ type Q3 = IsString<any>; // boolean
741741
>Q3 : boolean
742742
>IsString : Extends<T, string>
743743

744-
type Q4 = IsString<never>; // boolean
745-
>Q4 : boolean
744+
type Q4 = IsString<never>; // never
745+
>Q4 : never
746746
>IsString : Extends<T, string>
747747

748748
type N1 = Not<false>; // true
@@ -865,12 +865,12 @@ type T41 = number extends never ? true : false; // false
865865
>true : true
866866
>false : false
867867

868-
type T42 = never extends number ? true : false; // boolean
869-
>T42 : boolean
868+
type T42 = never extends number ? true : false; // true
869+
>T42 : true
870870
>true : true
871871
>false : false
872872

873-
type IsNever<T> = T extends never ? true : false;
873+
type IsNever<T> = [T] extends [never] ? true : false;
874874
>IsNever : IsNever<T>
875875
>T : T
876876
>T : T
@@ -1010,8 +1010,8 @@ type Bar<T> = T extends string ? boolean : number;
10101010
>T : T
10111011

10121012
const convert = <U>(value: Foo<U>): Bar<U> => value;
1013-
>convert : <U>(value: Foo<U>) => Foo<U>
1014-
><U>(value: Foo<U>): Bar<U> => value : <U>(value: Foo<U>) => Foo<U>
1013+
>convert : <U>(value: Foo<U>) => Bar<U>
1014+
><U>(value: Foo<U>): Bar<U> => value : <U>(value: Foo<U>) => Bar<U>
10151015
>U : U
10161016
>value : Foo<U>
10171017
>Foo : Foo<T>
@@ -1095,7 +1095,7 @@ function f33<T, U>() {
10951095
>U : U
10961096

10971097
type T2 = Bar<T & U>;
1098-
>T2 : Foo<T & U>
1098+
>T2 : Bar<T & U>
10991099
>Bar : Bar<T>
11001100
>T : T
11011101
>U : U
@@ -1106,7 +1106,7 @@ function f33<T, U>() {
11061106

11071107
var z: T2;
11081108
>z : Foo<T & U>
1109-
>T2 : Foo<T & U>
1109+
>T2 : Bar<T & U>
11101110
}
11111111

11121112
// Repro from #21823
@@ -1236,7 +1236,7 @@ function f50() {
12361236
>T : T
12371237

12381238
type Omit<T extends object> = { [P in keyof T]: If<Eq<T[P], never>, never, P>; }[keyof T];
1239-
>Omit : { [P in keyof T]: (T[P] extends never ? boolean : false) extends false ? P : never; }[keyof T]
1239+
>Omit : { [P in keyof T]: (T[P] extends never ? never : false) extends false ? P : never; }[keyof T]
12401240
>T : T
12411241
>P : P
12421242
>T : T
@@ -1263,7 +1263,7 @@ function f50() {
12631263

12641264
type A = Omit<{ a: void; b: never; }>; // 'a'
12651265
>A : "a"
1266-
>Omit : { [P in keyof T]: (T[P] extends never ? boolean : false) extends false ? P : never; }[keyof T]
1266+
>Omit : { [P in keyof T]: (T[P] extends never ? never : false) extends false ? P : never; }[keyof T]
12671267
>a : void
12681268
>b : never
12691269

tests/baselines/reference/inferTypes1.errors.txt

+4-4
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ tests/cases/conformance/types/conditional/inferTypes1.ts(134,40): error TS2322:
5050
type T13 = ReturnType<(<T extends U, U extends number[]>() => T)>; // number[]
5151
type T14 = ReturnType<typeof f1>; // { a: number, b: string }
5252
type T15 = ReturnType<any>; // any
53-
type T16 = ReturnType<never>; // any
53+
type T16 = ReturnType<never>; // never
5454
type T17 = ReturnType<string>; // Error
5555
~~~~~~
5656
!!! error TS2344: Type 'string' does not satisfy the constraint '(...args: any[]) => any'.
@@ -61,7 +61,7 @@ tests/cases/conformance/types/conditional/inferTypes1.ts(134,40): error TS2322:
6161

6262
type U10 = InstanceType<typeof C>; // C
6363
type U11 = InstanceType<any>; // any
64-
type U12 = InstanceType<never>; // any
64+
type U12 = InstanceType<never>; // never
6565
type U13 = InstanceType<string>; // Error
6666
~~~~~~
6767
!!! error TS2344: Type 'string' does not satisfy the constraint 'new (...args: any[]) => any'.
@@ -72,7 +72,7 @@ tests/cases/conformance/types/conditional/inferTypes1.ts(134,40): error TS2322:
7272

7373
type ArgumentType<T extends (x: any) => any> = T extends (a: infer A) => any ? A : any;
7474

75-
type T20 = ArgumentType<() => void>; // never
75+
type T20 = ArgumentType<() => void>; // {}
7676
type T21 = ArgumentType<(x: string) => number>; // string
7777
type T22 = ArgumentType<(x?: string) => number>; // string | undefined
7878
type T23 = ArgumentType<(...args: string[]) => number>; // string
@@ -84,7 +84,7 @@ tests/cases/conformance/types/conditional/inferTypes1.ts(134,40): error TS2322:
8484
!!! error TS2344: Type 'Function' does not satisfy the constraint '(x: any) => any'.
8585
!!! error TS2344: Type 'Function' provides no match for the signature '(x: any): any'.
8686
type T26 = ArgumentType<any>; // any
87-
type T27 = ArgumentType<never>; // any
87+
type T27 = ArgumentType<never>; // never
8888

8989
type X1<T extends { x: any, y: any }> = T extends { x: infer X, y: infer Y } ? [X, Y] : any;
9090

tests/baselines/reference/inferTypes1.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -28,26 +28,26 @@ type T12 = ReturnType<(<T>() => T)>; // {}
2828
type T13 = ReturnType<(<T extends U, U extends number[]>() => T)>; // number[]
2929
type T14 = ReturnType<typeof f1>; // { a: number, b: string }
3030
type T15 = ReturnType<any>; // any
31-
type T16 = ReturnType<never>; // any
31+
type T16 = ReturnType<never>; // never
3232
type T17 = ReturnType<string>; // Error
3333
type T18 = ReturnType<Function>; // Error
3434

3535
type U10 = InstanceType<typeof C>; // C
3636
type U11 = InstanceType<any>; // any
37-
type U12 = InstanceType<never>; // any
37+
type U12 = InstanceType<never>; // never
3838
type U13 = InstanceType<string>; // Error
3939
type U14 = InstanceType<Function>; // Error
4040

4141
type ArgumentType<T extends (x: any) => any> = T extends (a: infer A) => any ? A : any;
4242

43-
type T20 = ArgumentType<() => void>; // never
43+
type T20 = ArgumentType<() => void>; // {}
4444
type T21 = ArgumentType<(x: string) => number>; // string
4545
type T22 = ArgumentType<(x?: string) => number>; // string | undefined
4646
type T23 = ArgumentType<(...args: string[]) => number>; // string
4747
type T24 = ArgumentType<(x: string, y: string) => number>; // Error
4848
type T25 = ArgumentType<Function>; // Error
4949
type T26 = ArgumentType<any>; // any
50-
type T27 = ArgumentType<never>; // any
50+
type T27 = ArgumentType<never>; // never
5151

5252
type X1<T extends { x: any, y: any }> = T extends { x: infer X, y: infer Y } ? [X, Y] : any;
5353

tests/baselines/reference/inferTypes1.symbols

+4-4
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ type T15 = ReturnType<any>; // any
106106
>T15 : Symbol(T15, Decl(inferTypes1.ts, 27, 33))
107107
>ReturnType : Symbol(ReturnType, Decl(lib.d.ts, --, --))
108108

109-
type T16 = ReturnType<never>; // any
109+
type T16 = ReturnType<never>; // never
110110
>T16 : Symbol(T16, Decl(inferTypes1.ts, 28, 27))
111111
>ReturnType : Symbol(ReturnType, Decl(lib.d.ts, --, --))
112112

@@ -128,7 +128,7 @@ type U11 = InstanceType<any>; // any
128128
>U11 : Symbol(U11, Decl(inferTypes1.ts, 33, 34))
129129
>InstanceType : Symbol(InstanceType, Decl(lib.d.ts, --, --))
130130

131-
type U12 = InstanceType<never>; // any
131+
type U12 = InstanceType<never>; // never
132132
>U12 : Symbol(U12, Decl(inferTypes1.ts, 34, 29))
133133
>InstanceType : Symbol(InstanceType, Decl(lib.d.ts, --, --))
134134

@@ -150,7 +150,7 @@ type ArgumentType<T extends (x: any) => any> = T extends (a: infer A) => any ? A
150150
>A : Symbol(A, Decl(inferTypes1.ts, 39, 66))
151151
>A : Symbol(A, Decl(inferTypes1.ts, 39, 66))
152152

153-
type T20 = ArgumentType<() => void>; // never
153+
type T20 = ArgumentType<() => void>; // {}
154154
>T20 : Symbol(T20, Decl(inferTypes1.ts, 39, 87))
155155
>ArgumentType : Symbol(ArgumentType, Decl(inferTypes1.ts, 37, 34))
156156

@@ -184,7 +184,7 @@ type T26 = ArgumentType<any>; // any
184184
>T26 : Symbol(T26, Decl(inferTypes1.ts, 46, 34))
185185
>ArgumentType : Symbol(ArgumentType, Decl(inferTypes1.ts, 37, 34))
186186

187-
type T27 = ArgumentType<never>; // any
187+
type T27 = ArgumentType<never>; // never
188188
>T27 : Symbol(T27, Decl(inferTypes1.ts, 47, 29))
189189
>ArgumentType : Symbol(ArgumentType, Decl(inferTypes1.ts, 37, 34))
190190

0 commit comments

Comments
 (0)