@@ -3,37 +3,153 @@ import { expectError, expectType } from 'tsd';
33import { propEq } from '../es' ;
44
55type Obj = {
6- union : 'foo' | 'bar' ;
7- str : string ;
8- num : number ;
9- u : undefined ;
10- n : null ;
6+ literals : 'A' | 'B' ;
7+ unions : number | string ;
8+ nullable : number | null | undefined ;
9+ optional ?: number ;
1110} ;
1211
13- // propEq(val, name, obj)
14- expectType < boolean > ( propEq ( 'foo' , 'union' , { } as Obj ) ) ;
15- // non-union string fails
16- expectError ( propEq ( 'nope' , 'union' , { } as Obj ) ) ;
17- // completely different type fails
18- expectError ( propEq ( 2 , 'union' , { } as Obj ) ) ;
19-
20- // propEq(val)(name)(obj)
21- expectType < boolean > ( propEq ( 'foo' ) ( 'union' ) ( { } as Obj ) ) ;
22- // 'nope' is inferred as 'string' here.
23- expectType < boolean > ( propEq ( 'nope' ) ( 'union' ) ( { } as Obj ) ) ;
24- // completely different type fails
25- expectError ( propEq ( 2 ) ( 'union' ) ( { } as Obj ) ) ;
26-
27- // propEq(val)(name), obj)
28- expectType < boolean > ( propEq ( 'foo' ) ( 'union' , { } as Obj ) ) ;
29- // 'nope' is inferred as 'string' here.
30- expectType < boolean > ( propEq ( 'nope' ) ( 'union' , { } as Obj ) ) ;
31- // completely different type fails
32- expectError ( propEq ( 2 ) ( 'union' , { } as Obj ) ) ;
33-
34- // propEq(val, name)(obj)
35- expectType < boolean > ( propEq ( 'foo' , 'union' ) ( { } as Obj ) ) ;
36- // 'nope' is inferred as 'string' here.
37- expectType < boolean > ( propEq ( 'nope' , 'union' ) ( { } as Obj ) ) ;
38- // completely different type fails
39- expectError ( propEq ( 2 , 'union' ) ( { } as Obj ) ) ;
12+ const obj = { } as Obj ;
13+
14+ //
15+ // literals
16+ //
17+
18+ // happy path works as expected
19+ expectType < boolean > ( propEq ( 'A' ) ( 'literals' ) ( obj ) ) ;
20+ expectType < boolean > ( propEq ( 'A' , 'literals' ) ( obj ) ) ;
21+ expectType < boolean > ( propEq ( 'A' , 'literals' , obj ) ) ;
22+
23+ // accepts any type that obj[key] can be widened too
24+ expectType < boolean > ( propEq ( 'C' ) ( 'literals' ) ( obj ) ) ;
25+ expectType < boolean > ( propEq ( 'C' , 'literals' ) ( obj ) ) ;
26+ // only propEq(val, key, obj) requests non-widened types
27+ expectError ( propEq ( 'C' , 'literals' , obj ) ) ;
28+
29+ // rejects if type cannot be widened too
30+ expectError ( propEq ( 2 ) ( 'literals' ) ( obj ) ) ;
31+ expectError ( propEq ( 2 , 'literals' ) ( obj ) ) ;
32+ expectError ( propEq ( 2 , 'literals' , obj ) ) ;
33+
34+ // manually widened also works
35+ expectType < boolean > ( propEq ( 'A' as string ) ( 'literals' ) ( obj ) ) ;
36+ expectType < boolean > ( propEq ( 'A' as string , 'literals' ) ( obj ) ) ;
37+ // only rejects for propEq(val, key, obj), `string` is too wide for 'A' | 'B'
38+ expectError ( propEq ( 'A' as string , 'literals' , obj ) ) ;
39+
40+ // rejects if key is not on obj
41+ expectError ( propEq ( 'A' ) ( 'literals' ) ( { } as Omit < Obj , 'literals' > ) ) ;
42+ expectError ( propEq ( 'A' , 'literals' ) ( { } as Omit < Obj , 'literals' > ) ) ;
43+ expectError ( propEq ( 'A' , 'literals' , { } as Omit < Obj , 'literals' > ) ) ;
44+
45+ // rejects empty object literal
46+ expectError ( propEq ( 'A' ) ( 'literals' ) ( { } ) ) ;
47+ expectError ( propEq ( 'A' , 'literals' ) ( { } ) ) ;
48+ expectError ( propEq ( 'A' , 'literals' , { } ) ) ;
49+
50+ //
51+ // unions
52+ //
53+
54+ // happy path works as expected
55+ expectType < boolean > ( propEq ( '1' ) ( 'unions' ) ( obj ) ) ;
56+ expectType < boolean > ( propEq ( '1' , 'unions' ) ( obj ) ) ;
57+ expectType < boolean > ( propEq ( '1' , 'unions' , obj ) ) ;
58+
59+ expectType < boolean > ( propEq ( 1 ) ( 'unions' ) ( obj ) ) ;
60+ expectType < boolean > ( propEq ( 1 , 'unions' ) ( obj ) ) ;
61+ expectType < boolean > ( propEq ( 1 , 'unions' , obj ) ) ;
62+
63+ // rejects if typeof val not part of union type
64+ expectError ( propEq ( true ) ( 'unions' ) ( obj ) ) ;
65+ expectError ( propEq ( true , 'unions' ) ( obj ) ) ;
66+ expectError ( propEq ( true , 'unions' , obj ) ) ;
67+
68+ // rejects if key is not on obj
69+ expectError ( propEq ( '1' ) ( 'unions' ) ( { } as Omit < Obj , 'unions' > ) ) ;
70+ expectError ( propEq ( '1' , 'unions' ) ( { } as Omit < Obj , 'unions' > ) ) ;
71+ expectError ( propEq ( '1' , 'unions' , { } as Omit < Obj , 'unions' > ) ) ;
72+
73+ // rejects empty object literal
74+ expectError ( propEq ( '1' ) ( 'unions' ) ( { } ) ) ;
75+ expectError ( propEq ( '1' , 'unions' ) ( { } ) ) ;
76+ expectError ( propEq ( '1' , 'unions' , { } ) ) ;
77+
78+ //
79+ // nullable
80+ //
81+
82+ // happy path works as expected
83+ expectType < boolean > ( propEq ( 1 ) ( 'nullable' ) ( obj ) ) ;
84+ expectType < boolean > ( propEq ( 1 , 'nullable' ) ( obj ) ) ;
85+ expectType < boolean > ( propEq ( 1 , 'nullable' , obj ) ) ;
86+
87+ expectType < boolean > ( propEq ( null ) ( 'nullable' ) ( obj ) ) ;
88+ expectType < boolean > ( propEq ( null , 'nullable' ) ( obj ) ) ;
89+ expectType < boolean > ( propEq ( null , 'nullable' , obj ) ) ;
90+
91+ expectType < boolean > ( propEq ( undefined ) ( 'nullable' ) ( obj ) ) ;
92+ expectType < boolean > ( propEq ( undefined , 'nullable' ) ( obj ) ) ;
93+ expectType < boolean > ( propEq ( undefined , 'nullable' , obj ) ) ;
94+
95+ // rejects if typeof val not part of union type
96+ expectError ( propEq ( true ) ( 'nullable' ) ( obj ) ) ;
97+ expectError ( propEq ( true , 'nullable' ) ( obj ) ) ;
98+ expectError ( propEq ( true , 'nullable' , obj ) ) ;
99+
100+ // rejects if key is not on obj
101+ expectError ( propEq ( 1 ) ( 'nullable' ) ( { } as Omit < Obj , 'nullable' > ) ) ;
102+ expectError ( propEq ( 1 , 'nullable' ) ( { } as Omit < Obj , 'nullable' > ) ) ;
103+ expectError ( propEq ( 1 , 'nullable' , { } as Omit < Obj , 'nullable' > ) ) ;
104+
105+ // rejects empty object literal
106+ expectError ( propEq ( 1 ) ( 'nullable' ) ( { } ) ) ;
107+ expectError ( propEq ( 1 , 'nullable' ) ( { } ) ) ;
108+ expectError ( propEq ( 1 , 'nullable' , { } ) ) ;
109+
110+ //
111+ // optional
112+ //
113+
114+ // happy path works as expected
115+ expectType < boolean > ( propEq ( 1 ) ( 'optional' ) ( obj ) ) ;
116+ expectType < boolean > ( propEq ( 1 , 'optional' ) ( obj ) ) ;
117+ expectType < boolean > ( propEq ( 1 , 'optional' , obj ) ) ;
118+
119+ expectType < boolean > ( propEq ( undefined ) ( 'optional' ) ( obj ) ) ;
120+ expectType < boolean > ( propEq ( undefined , 'optional' ) ( obj ) ) ;
121+ expectType < boolean > ( propEq ( undefined , 'optional' , obj ) ) ;
122+
123+ // `null` produces error for `optional`. this is expected because typescript strictNullCheck `null !== undefined`
124+ expectError ( propEq ( null ) ( 'optional' ) ( obj ) ) ;
125+ expectError ( propEq ( null , 'optional' ) ( obj ) ) ;
126+ expectError ( propEq ( null , 'optional' , obj ) ) ;
127+
128+ // rejects if typeof val not part of union type
129+ expectError ( propEq ( true ) ( 'optional' ) ( obj ) ) ;
130+ expectError ( propEq ( true , 'optional' ) ( obj ) ) ;
131+ expectError ( propEq ( true , 'optional' , obj ) ) ;
132+
133+ // rejects if key is not on obj
134+ expectError ( propEq ( 1 ) ( 'optional' ) ( { } as Omit < Obj , 'optional' > ) ) ;
135+ expectError ( propEq ( 1 , 'optional' ) ( { } as Omit < Obj , 'optional' > ) ) ;
136+ expectError ( propEq ( 1 , 'optional' , { } as Omit < Obj , 'optional' > ) ) ;
137+
138+ // rejects empty object literal literal
139+ expectError ( propEq ( 1 ) ( 'optional' ) ( { } ) ) ;
140+ expectError ( propEq ( 1 , 'optional' ) ( { } ) ) ;
141+ expectError ( propEq ( 1 , 'optional' , { } ) ) ;
142+
143+ //
144+ // other non-happy paths
145+ //
146+
147+ // rejects unknown key
148+ expectError ( propEq ( 1 ) ( 'whatever' ) ( obj ) ) ;
149+ expectError ( propEq ( 1 , 'whatever' ) ( obj ) ) ;
150+ expectError ( propEq ( 1 , 'whatever' , obj ) ) ;
151+
152+ // rejects unknown key on emptyu object literal
153+ expectError ( propEq ( 1 ) ( 'whatever' ) ( { } ) ) ;
154+ expectError ( propEq ( 1 , 'whatever' ) ( { } ) ) ;
155+ expectError ( propEq ( 1 , 'whatever' , { } ) ) ;
0 commit comments