1
1
import { expectTypeOf } from 'expect-type' ;
2
2
import { resolve , invokeBlock } from '@glint/template' ;
3
- import { AcceptsBlocks } from '@glint/template/-private' ;
4
3
import { ComponentKeyword } from '@glint/template/-private/keywords' ;
4
+ import TestComponent from '../test-component' ;
5
5
6
6
const componentKeyword = resolve ( { } as ComponentKeyword ) ;
7
7
8
- declare const TestComponent : ( args : {
9
- value : string ;
10
- } ) => AcceptsBlocks < {
11
- default ?: [ string ] ;
12
- inverse ?: [ ] ;
13
- } > ;
8
+ class StringComponent extends TestComponent < { value : string } , { default ?: [ string ] } > { }
14
9
15
- const NoopCurriedTestComponent = componentKeyword ( { } , TestComponent ) ;
16
- const ValueCurriedTestComponent = componentKeyword ( { value : 'hello' } , TestComponent ) ;
10
+ const NoopCurriedStringComponent = componentKeyword ( { } , StringComponent ) ;
11
+ const ValueCurriedStringComponent = componentKeyword ( { value : 'hello' } , StringComponent ) ;
17
12
18
13
// Invoking the noop-curried component
19
- invokeBlock ( resolve ( NoopCurriedTestComponent ) ( { value : 'hello' } ) , { } ) ;
14
+ invokeBlock ( resolve ( NoopCurriedStringComponent ) ( { value : 'hello' } ) , { } ) ;
20
15
21
16
// @ts -expect-error: Invoking the curried component but forgetting `value`
22
- resolve ( NoopCurriedTestComponent ) ( { } ) ;
17
+ resolve ( NoopCurriedStringComponent ) ( { } ) ;
23
18
24
19
// @ts -expect-error: Invoking the curried component with an invalid value
25
- resolve ( NoopCurriedTestComponent ) ( { value : 123 } ) ;
20
+ resolve ( NoopCurriedStringComponent ) ( { value : 123 } ) ;
26
21
27
22
// Invoking the noop-curried component with a valid block
28
- invokeBlock ( resolve ( NoopCurriedTestComponent ) ( { value : 'hello' } ) , {
23
+ invokeBlock ( resolve ( NoopCurriedStringComponent ) ( { value : 'hello' } ) , {
29
24
default ( ...args ) {
30
25
expectTypeOf ( args ) . toEqualTypeOf < [ string ] > ( ) ;
31
26
} ,
32
27
} ) ;
33
28
34
29
// Invoking the noop-curried component with an invalid block
35
- invokeBlock ( resolve ( NoopCurriedTestComponent ) ( { value : 'hello' } ) , {
30
+ invokeBlock ( resolve ( NoopCurriedStringComponent ) ( { value : 'hello' } ) , {
36
31
default ( ) {
37
32
/* nothing */
38
33
} ,
@@ -43,16 +38,153 @@ invokeBlock(resolve(NoopCurriedTestComponent)({ value: 'hello' }), {
43
38
} ) ;
44
39
45
40
// Invoking the curried-with-value component with no value
46
- invokeBlock ( resolve ( ValueCurriedTestComponent ) ( { } ) , { } ) ;
41
+ invokeBlock ( resolve ( ValueCurriedStringComponent ) ( { } ) , { } ) ;
47
42
48
43
// Invoking the curried-with-value component with a valid value
49
- invokeBlock ( resolve ( ValueCurriedTestComponent ) ( { value : 'hi' } ) , { } ) ;
44
+ invokeBlock ( resolve ( ValueCurriedStringComponent ) ( { value : 'hi' } ) , { } ) ;
50
45
51
46
// @ts -expect-error: Invoking the curred-with-value component with an invalid value
52
- invokeBlock ( resolve ( ValueCurriedTestComponent ) ( { value : 123 } ) , { } ) ;
47
+ invokeBlock ( resolve ( ValueCurriedStringComponent ) ( { value : 123 } ) , { } ) ;
53
48
54
49
// @ts -expect-error: Attempting to curry a nonexistent arg
55
- componentKeyword ( { foo : true } , TestComponent ) ;
50
+ componentKeyword ( { foo : true } , StringComponent ) ;
56
51
57
52
// @ts -expect-error: Attempting to curry an arg with the wrong type
58
- componentKeyword ( { value : 123 } , TestComponent ) ;
53
+ componentKeyword ( { value : 123 } , StringComponent ) ;
54
+
55
+ class ParametricComponent < T > extends TestComponent <
56
+ { values : Array < T > ; optional ?: string } ,
57
+ { default ?: [ T , number ] }
58
+ > { }
59
+
60
+ const NoopCurriedParametricComponent = componentKeyword ( { } , ParametricComponent ) ;
61
+
62
+ // The only way to fix a type parameter as part of using the component keyword is to
63
+ // say ahead of time the type you're trying to bind it as.
64
+ const BoundParametricComponent = ParametricComponent as new ( ) => ParametricComponent < string > ;
65
+
66
+ const RequiredValueCurriedParametricComponent = componentKeyword (
67
+ { values : [ 'hello' ] } ,
68
+ BoundParametricComponent
69
+ ) ;
70
+
71
+ const OptionalValueCurriedParametricComponent = componentKeyword (
72
+ { optional : 'hi' } ,
73
+ ParametricComponent
74
+ ) ;
75
+
76
+ // Invoking the noop-curried component with number values
77
+ invokeBlock ( resolve ( NoopCurriedParametricComponent ) ( { values : [ 1 , 2 , 3 ] } ) , {
78
+ default ( value ) {
79
+ expectTypeOf ( value ) . toEqualTypeOf < number > ( ) ;
80
+ } ,
81
+ } ) ;
82
+
83
+ // Invoking the noop-curried component with string values
84
+ invokeBlock ( resolve ( NoopCurriedParametricComponent ) ( { values : [ 'hello' ] } ) , {
85
+ default ( value ) {
86
+ expectTypeOf ( value ) . toEqualTypeOf < string > ( ) ;
87
+ } ,
88
+ } ) ;
89
+
90
+ invokeBlock (
91
+ resolve ( NoopCurriedParametricComponent ) (
92
+ // @ts -expect-error: missing required arg `values`
93
+ { }
94
+ ) ,
95
+ { }
96
+ ) ;
97
+
98
+ invokeBlock (
99
+ resolve ( NoopCurriedParametricComponent ) (
100
+ // @ts -expect-error: wrong type for `values`
101
+ { values : 'hello' }
102
+ ) ,
103
+ { }
104
+ ) ;
105
+
106
+ invokeBlock (
107
+ resolve ( NoopCurriedParametricComponent ) ( {
108
+ values : [ 1 , 2 , 3 ] ,
109
+ // @ts -expect-error: extra arg
110
+ extra : 'uh oh' ,
111
+ } ) ,
112
+ { }
113
+ ) ;
114
+
115
+ // Invoking the curred component with no additional args
116
+ invokeBlock ( resolve ( RequiredValueCurriedParametricComponent ) ( { } ) , {
117
+ default ( value ) {
118
+ expectTypeOf ( value ) . toEqualTypeOf < string > ( ) ;
119
+ } ,
120
+ } ) ;
121
+
122
+ // Invoking the curred component and overriding the given arg
123
+ invokeBlock ( resolve ( RequiredValueCurriedParametricComponent ) ( { values : [ 'ok' ] } ) , {
124
+ default ( value ) {
125
+ expectTypeOf ( value ) . toEqualTypeOf < string > ( ) ;
126
+ } ,
127
+ } ) ;
128
+
129
+ invokeBlock (
130
+ resolve ( RequiredValueCurriedParametricComponent ) ( {
131
+ // @ts -expect-error: wrong type for arg override
132
+ values : [ 1 , 2 , 3 ] ,
133
+ } ) ,
134
+ { }
135
+ ) ;
136
+
137
+ invokeBlock (
138
+ resolve ( RequiredValueCurriedParametricComponent ) ( {
139
+ // @ts -expect-error: extra arg
140
+ extra : 'bad' ,
141
+ } ) ,
142
+ { }
143
+ ) ;
144
+
145
+ // Invoking the curried component, supplying missing required args
146
+ invokeBlock ( resolve ( OptionalValueCurriedParametricComponent ) ( { values : [ 1 , 2 , 3 ] } ) , {
147
+ default ( value ) {
148
+ expectTypeOf ( value ) . toEqualTypeOf < number > ( ) ;
149
+ } ,
150
+ } ) ;
151
+
152
+ invokeBlock (
153
+ resolve ( OptionalValueCurriedParametricComponent ) (
154
+ // @ts -expect-error: missing required arg `values`
155
+ { }
156
+ ) ,
157
+ { }
158
+ ) ;
159
+
160
+ // {{component (component BoundParametricComponent values=(array "hello")) optional="hi"}}
161
+ const DoubleCurriedComponent = componentKeyword (
162
+ { optional : 'hi' } ,
163
+ RequiredValueCurriedParametricComponent
164
+ ) ;
165
+
166
+ // Invoking the component with no args
167
+ invokeBlock ( resolve ( DoubleCurriedComponent ) ( { } ) , {
168
+ default ( value ) {
169
+ expectTypeOf ( value ) . toEqualTypeOf < string > ( ) ;
170
+ } ,
171
+ } ) ;
172
+
173
+ // Invoking the component overriding an arg correctly
174
+ invokeBlock ( resolve ( DoubleCurriedComponent ) ( { values : [ 'a' , 'b' ] } ) , { } ) ;
175
+
176
+ invokeBlock (
177
+ resolve ( DoubleCurriedComponent ) ( {
178
+ // @ts -expect-error: invalid arg override
179
+ values : [ 1 , 2 , 3 ] ,
180
+ } ) ,
181
+ { }
182
+ ) ;
183
+
184
+ invokeBlock (
185
+ resolve ( DoubleCurriedComponent ) ( {
186
+ // @ts -expect-error: unexpected args
187
+ foo : 'bar' ,
188
+ } ) ,
189
+ { }
190
+ ) ;
0 commit comments