Skip to content

Commit 0308dde

Browse files
committed
add intersections
1 parent 1fa487e commit 0308dde

File tree

5 files changed

+204
-23
lines changed

5 files changed

+204
-23
lines changed

src/compiler/checker.ts

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24887,12 +24887,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2488724887

2488824888
// This like getBaseTypeOfLiteralType, but instead treats enum literals as strings/numbers instead
2488924889
// of returning their enum base type (which depends on the types of other literals in the enum).
24890-
function getBaseTypeOfLiteralTypeForComparison(type: Type): Type {
24891-
return type.flags & (TypeFlags.StringLiteral | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) ? stringType :
24890+
// use to determine if a parameter may be undefined or null (or is unknown/unconstrained)
24891+
// function getUnknownIfMaybeUnknown(type: Type) {
24892+
// return (strictNullChecks && type.flags & TypeFlags.Instantiable) ? getBaseConstraintOfType(type) ?? unknownUnionType : type;
24893+
// }
24894+
function getBaseTypeForComparison(type: Type): Type {
24895+
return type.flags & TypeFlags.Instantiable && strictNullChecks ? getBaseConstraintOfType(type) ?? unknownUnionType :
24896+
type.flags & (TypeFlags.StringLiteral | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) ? stringType :
2489224897
type.flags & (TypeFlags.NumberLiteral | TypeFlags.Enum) ? numberType :
2489324898
type.flags & TypeFlags.BigIntLiteral ? bigintType :
2489424899
type.flags & TypeFlags.BooleanLiteral ? booleanType :
24895-
type.flags & TypeFlags.Union ? mapType(type, getBaseTypeOfLiteralTypeForComparison) :
24900+
type.flags & TypeFlags.Union ? mapType(type, getBaseTypeForComparison) :
24901+
type.flags & TypeFlags.Intersection && every((type as IntersectionType).types, t => { return getBaseTypeForComparison(t) === unknownUnionType }) ? unknownUnionType :
2489624902
type;
2489724903
}
2489824904

@@ -27493,11 +27499,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2749327499
return type === unknownUnionType ? unknownType : type;
2749427500
}
2749527501

27496-
// use to determine if a parameter may be undefined or null (or is unknown/unconstrained)
27497-
function getUnknownIfMaybeUnknown(type: Type) {
27498-
return (strictNullChecks && type.flags & TypeFlags.Instantiable) ? getBaseConstraintOfType(type) || unknownUnionType : type;
27499-
}
27500-
2750127502
function getTypeWithDefault(type: Type, defaultExpression: Expression) {
2750227503
return defaultExpression ?
2750327504
getUnionType([getNonUndefinedType(type), getTypeOfExpression(defaultExpression)]) :
@@ -39682,8 +39683,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3968239683
case SyntaxKind.LessThanEqualsToken:
3968339684
case SyntaxKind.GreaterThanEqualsToken:
3968439685
if (checkForDisallowedESSymbolOperand(operator)) {
39685-
leftType = getBaseTypeOfLiteralTypeForComparison(checkNonNullType(getUnknownIfMaybeUnknown(leftType), left));
39686-
rightType = getBaseTypeOfLiteralTypeForComparison(checkNonNullType(getUnknownIfMaybeUnknown(rightType), right));
39686+
leftType = checkNonNullType(getBaseTypeForComparison(leftType), left);
39687+
rightType = checkNonNullType(getBaseTypeForComparison(rightType), right);
3968739688
reportOperatorErrorUnless((left, right) => {
3968839689
if (isTypeAny(left) || isTypeAny(right)) {
3968939690
return true;

tests/baselines/reference/unconstrainedTypeComparison.errors.txt

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,17 @@ unconstrainedTypeComparison.ts(30,12): error TS18047: 'a' is possibly 'null'.
1616
unconstrainedTypeComparison.ts(30,16): error TS18047: 'b' is possibly 'null'.
1717
unconstrainedTypeComparison.ts(34,12): error TS18049: 'a' is possibly 'null' or 'undefined'.
1818
unconstrainedTypeComparison.ts(34,16): error TS18049: 'b' is possibly 'null' or 'undefined'.
19-
unconstrainedTypeComparison.ts(45,12): error TS18047: 'a' is possibly 'null'.
20-
unconstrainedTypeComparison.ts(45,16): error TS18048: 'b' is possibly 'undefined'.
19+
unconstrainedTypeComparison.ts(38,12): error TS18049: 'x' is possibly 'null' or 'undefined'.
20+
unconstrainedTypeComparison.ts(38,16): error TS18049: 'y' is possibly 'null' or 'undefined'.
21+
unconstrainedTypeComparison.ts(42,12): error TS18049: 'x' is possibly 'null' or 'undefined'.
22+
unconstrainedTypeComparison.ts(42,16): error TS18049: 'y' is possibly 'null' or 'undefined'.
23+
unconstrainedTypeComparison.ts(46,12): error TS18049: 'x' is possibly 'null' or 'undefined'.
24+
unconstrainedTypeComparison.ts(46,16): error TS18049: 'y' is possibly 'null' or 'undefined'.
25+
unconstrainedTypeComparison.ts(61,12): error TS18047: 'a' is possibly 'null'.
26+
unconstrainedTypeComparison.ts(61,16): error TS18048: 'b' is possibly 'undefined'.
2127

2228

23-
==== unconstrainedTypeComparison.ts (20 errors) ====
29+
==== unconstrainedTypeComparison.ts (26 errors) ====
2430
function f1<T>(a: T, b: T): boolean {
2531
return a > b;
2632
~
@@ -93,6 +99,34 @@ unconstrainedTypeComparison.ts(45,16): error TS18048: 'b' is possibly 'undefined
9399
!!! error TS18049: 'b' is possibly 'null' or 'undefined'.
94100
}
95101

102+
function f10<T, U>(x: T | U, y: T | U) {
103+
return x < y;
104+
~
105+
!!! error TS18049: 'x' is possibly 'null' or 'undefined'.
106+
~
107+
!!! error TS18049: 'y' is possibly 'null' or 'undefined'.
108+
}
109+
110+
function f11<T, U extends T>(x: T | number, y: U | number) {
111+
return x < y;
112+
~
113+
!!! error TS18049: 'x' is possibly 'null' or 'undefined'.
114+
~
115+
!!! error TS18049: 'y' is possibly 'null' or 'undefined'.
116+
}
117+
118+
function f12<T, U>(x: T & U, y: T & U) {
119+
return x < y;
120+
~
121+
!!! error TS18049: 'x' is possibly 'null' or 'undefined'.
122+
~
123+
!!! error TS18049: 'y' is possibly 'null' or 'undefined'.
124+
}
125+
126+
function f13<T, U extends T>(x: T & number, y: U & number) {
127+
return x < y;
128+
}
129+
96130

97131
function compare<T>(a: T, b: T): boolean {
98132
if (a === undefined) {

tests/baselines/reference/unconstrainedTypeComparison.symbols

Lines changed: 72 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -130,27 +130,89 @@ function f9<T extends undefined | null, U extends T>(a: U, b: U): boolean {
130130
>b : Symbol(b, Decl(unconstrainedTypeComparison.ts, 32, 58))
131131
}
132132

133+
function f10<T, U>(x: T | U, y: T | U) {
134+
>f10 : Symbol(f10, Decl(unconstrainedTypeComparison.ts, 34, 1))
135+
>T : Symbol(T, Decl(unconstrainedTypeComparison.ts, 36, 13))
136+
>U : Symbol(U, Decl(unconstrainedTypeComparison.ts, 36, 15))
137+
>x : Symbol(x, Decl(unconstrainedTypeComparison.ts, 36, 19))
138+
>T : Symbol(T, Decl(unconstrainedTypeComparison.ts, 36, 13))
139+
>U : Symbol(U, Decl(unconstrainedTypeComparison.ts, 36, 15))
140+
>y : Symbol(y, Decl(unconstrainedTypeComparison.ts, 36, 28))
141+
>T : Symbol(T, Decl(unconstrainedTypeComparison.ts, 36, 13))
142+
>U : Symbol(U, Decl(unconstrainedTypeComparison.ts, 36, 15))
143+
144+
return x < y;
145+
>x : Symbol(x, Decl(unconstrainedTypeComparison.ts, 36, 19))
146+
>y : Symbol(y, Decl(unconstrainedTypeComparison.ts, 36, 28))
147+
}
148+
149+
function f11<T, U extends T>(x: T | number, y: U | number) {
150+
>f11 : Symbol(f11, Decl(unconstrainedTypeComparison.ts, 38, 1))
151+
>T : Symbol(T, Decl(unconstrainedTypeComparison.ts, 40, 13))
152+
>U : Symbol(U, Decl(unconstrainedTypeComparison.ts, 40, 15))
153+
>T : Symbol(T, Decl(unconstrainedTypeComparison.ts, 40, 13))
154+
>x : Symbol(x, Decl(unconstrainedTypeComparison.ts, 40, 29))
155+
>T : Symbol(T, Decl(unconstrainedTypeComparison.ts, 40, 13))
156+
>y : Symbol(y, Decl(unconstrainedTypeComparison.ts, 40, 43))
157+
>U : Symbol(U, Decl(unconstrainedTypeComparison.ts, 40, 15))
158+
159+
return x < y;
160+
>x : Symbol(x, Decl(unconstrainedTypeComparison.ts, 40, 29))
161+
>y : Symbol(y, Decl(unconstrainedTypeComparison.ts, 40, 43))
162+
}
163+
164+
function f12<T, U>(x: T & U, y: T & U) {
165+
>f12 : Symbol(f12, Decl(unconstrainedTypeComparison.ts, 42, 1))
166+
>T : Symbol(T, Decl(unconstrainedTypeComparison.ts, 44, 13))
167+
>U : Symbol(U, Decl(unconstrainedTypeComparison.ts, 44, 15))
168+
>x : Symbol(x, Decl(unconstrainedTypeComparison.ts, 44, 19))
169+
>T : Symbol(T, Decl(unconstrainedTypeComparison.ts, 44, 13))
170+
>U : Symbol(U, Decl(unconstrainedTypeComparison.ts, 44, 15))
171+
>y : Symbol(y, Decl(unconstrainedTypeComparison.ts, 44, 28))
172+
>T : Symbol(T, Decl(unconstrainedTypeComparison.ts, 44, 13))
173+
>U : Symbol(U, Decl(unconstrainedTypeComparison.ts, 44, 15))
174+
175+
return x < y;
176+
>x : Symbol(x, Decl(unconstrainedTypeComparison.ts, 44, 19))
177+
>y : Symbol(y, Decl(unconstrainedTypeComparison.ts, 44, 28))
178+
}
179+
180+
function f13<T, U extends T>(x: T & number, y: U & number) {
181+
>f13 : Symbol(f13, Decl(unconstrainedTypeComparison.ts, 46, 1))
182+
>T : Symbol(T, Decl(unconstrainedTypeComparison.ts, 48, 13))
183+
>U : Symbol(U, Decl(unconstrainedTypeComparison.ts, 48, 15))
184+
>T : Symbol(T, Decl(unconstrainedTypeComparison.ts, 48, 13))
185+
>x : Symbol(x, Decl(unconstrainedTypeComparison.ts, 48, 29))
186+
>T : Symbol(T, Decl(unconstrainedTypeComparison.ts, 48, 13))
187+
>y : Symbol(y, Decl(unconstrainedTypeComparison.ts, 48, 43))
188+
>U : Symbol(U, Decl(unconstrainedTypeComparison.ts, 48, 15))
189+
190+
return x < y;
191+
>x : Symbol(x, Decl(unconstrainedTypeComparison.ts, 48, 29))
192+
>y : Symbol(y, Decl(unconstrainedTypeComparison.ts, 48, 43))
193+
}
194+
133195

134196
function compare<T>(a: T, b: T): boolean {
135-
>compare : Symbol(compare, Decl(unconstrainedTypeComparison.ts, 34, 1))
136-
>T : Symbol(T, Decl(unconstrainedTypeComparison.ts, 37, 17))
137-
>a : Symbol(a, Decl(unconstrainedTypeComparison.ts, 37, 20))
138-
>T : Symbol(T, Decl(unconstrainedTypeComparison.ts, 37, 17))
139-
>b : Symbol(b, Decl(unconstrainedTypeComparison.ts, 37, 25))
140-
>T : Symbol(T, Decl(unconstrainedTypeComparison.ts, 37, 17))
197+
>compare : Symbol(compare, Decl(unconstrainedTypeComparison.ts, 50, 1))
198+
>T : Symbol(T, Decl(unconstrainedTypeComparison.ts, 53, 17))
199+
>a : Symbol(a, Decl(unconstrainedTypeComparison.ts, 53, 20))
200+
>T : Symbol(T, Decl(unconstrainedTypeComparison.ts, 53, 17))
201+
>b : Symbol(b, Decl(unconstrainedTypeComparison.ts, 53, 25))
202+
>T : Symbol(T, Decl(unconstrainedTypeComparison.ts, 53, 17))
141203

142204
if (a === undefined) {
143-
>a : Symbol(a, Decl(unconstrainedTypeComparison.ts, 37, 20))
205+
>a : Symbol(a, Decl(unconstrainedTypeComparison.ts, 53, 20))
144206
>undefined : Symbol(undefined)
145207

146208
return false;
147209
}
148210
if (b === null) {
149-
>b : Symbol(b, Decl(unconstrainedTypeComparison.ts, 37, 25))
211+
>b : Symbol(b, Decl(unconstrainedTypeComparison.ts, 53, 25))
150212

151213
return false;
152214
}
153215
return a > b;
154-
>a : Symbol(a, Decl(unconstrainedTypeComparison.ts, 37, 20))
155-
>b : Symbol(b, Decl(unconstrainedTypeComparison.ts, 37, 25))
216+
>a : Symbol(a, Decl(unconstrainedTypeComparison.ts, 53, 20))
217+
>b : Symbol(b, Decl(unconstrainedTypeComparison.ts, 53, 25))
156218
}

tests/baselines/reference/unconstrainedTypeComparison.types

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,74 @@ function f9<T extends undefined | null, U extends T>(a: U, b: U): boolean {
154154
> : ^
155155
}
156156

157+
function f10<T, U>(x: T | U, y: T | U) {
158+
>f10 : <T, U>(x: T | U, y: T | U) => boolean
159+
> : ^ ^^ ^^ ^^ ^^ ^^ ^^^^^^^^^^^^
160+
>x : T | U
161+
> : ^^^^^
162+
>y : T | U
163+
> : ^^^^^
164+
165+
return x < y;
166+
>x < y : boolean
167+
> : ^^^^^^^
168+
>x : T | U
169+
> : ^^^^^
170+
>y : T | U
171+
> : ^^^^^
172+
}
173+
174+
function f11<T, U extends T>(x: T | number, y: U | number) {
175+
>f11 : <T, U extends T>(x: T | number, y: U | number) => boolean
176+
> : ^ ^^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^^^^^^^^^^^
177+
>x : number | T
178+
> : ^^^^^^^^^^
179+
>y : number | U
180+
> : ^^^^^^^^^^
181+
182+
return x < y;
183+
>x < y : boolean
184+
> : ^^^^^^^
185+
>x : number | T
186+
> : ^^^^^^^^^^
187+
>y : number | U
188+
> : ^^^^^^^^^^
189+
}
190+
191+
function f12<T, U>(x: T & U, y: T & U) {
192+
>f12 : <T, U>(x: T & U, y: T & U) => boolean
193+
> : ^ ^^ ^^ ^^ ^^ ^^ ^^^^^^^^^^^^
194+
>x : T & U
195+
> : ^^^^^
196+
>y : T & U
197+
> : ^^^^^
198+
199+
return x < y;
200+
>x < y : boolean
201+
> : ^^^^^^^
202+
>x : T & U
203+
> : ^^^^^
204+
>y : T & U
205+
> : ^^^^^
206+
}
207+
208+
function f13<T, U extends T>(x: T & number, y: U & number) {
209+
>f13 : <T, U extends T>(x: T & number, y: U & number) => boolean
210+
> : ^ ^^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^^^^^^^^^^^
211+
>x : T & number
212+
> : ^^^^^^^^^^
213+
>y : U & number
214+
> : ^^^^^^^^^^
215+
216+
return x < y;
217+
>x < y : boolean
218+
> : ^^^^^^^
219+
>x : T & number
220+
> : ^^^^^^^^^^
221+
>y : U & number
222+
> : ^^^^^^^^^^
223+
}
224+
157225

158226
function compare<T>(a: T, b: T): boolean {
159227
>compare : <T>(a: T, b: T) => boolean

tests/cases/compiler/unconstrainedTypeComparison.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,22 @@ function f9<T extends undefined | null, U extends T>(a: U, b: U): boolean {
3838
return a > b;
3939
}
4040

41+
function f10<T, U>(x: T | U, y: T | U) {
42+
return x < y;
43+
}
44+
45+
function f11<T, U extends T>(x: T | number, y: U | number) {
46+
return x < y;
47+
}
48+
49+
function f12<T, U>(x: T & U, y: T & U) {
50+
return x < y;
51+
}
52+
53+
function f13<T, U extends T>(x: T & number, y: U & number) {
54+
return x < y;
55+
}
56+
4157

4258
function compare<T>(a: T, b: T): boolean {
4359
if (a === undefined) {

0 commit comments

Comments
 (0)