@@ -17,6 +17,52 @@ import {
17
17
} from './utils' ;
18
18
import type { StreamablePatch , StreamableValue } from './types' ;
19
19
20
+ // It's necessary to define the type manually here, otherwise TypeScript compiler
21
+ // will not be able to infer the correct return type as it's circular.
22
+ type StreamableUIWrapper = {
23
+ /**
24
+ * The value of the streamable UI. This can be returned from a Server Action and received by the client.
25
+ */
26
+ readonly value : React . ReactNode ;
27
+
28
+ /**
29
+ * This method updates the current UI node. It takes a new UI node and replaces the old one.
30
+ */
31
+ update ( value : React . ReactNode ) : StreamableUIWrapper ;
32
+
33
+ /**
34
+ * This method is used to append a new UI node to the end of the old one.
35
+ * Once appended a new UI node, the previous UI node cannot be updated anymore.
36
+ *
37
+ * @example
38
+ * ```jsx
39
+ * const ui = createStreamableUI(<div>hello</div>)
40
+ * ui.append(<div>world</div>)
41
+ *
42
+ * // The UI node will be:
43
+ * // <>
44
+ * // <div>hello</div>
45
+ * // <div>world</div>
46
+ * // </>
47
+ * ```
48
+ */
49
+ append ( value : React . ReactNode ) : StreamableUIWrapper ;
50
+
51
+ /**
52
+ * This method is used to signal that there is an error in the UI stream.
53
+ * It will be thrown on the client side and caught by the nearest error boundary component.
54
+ */
55
+ error ( error : any ) : StreamableUIWrapper ;
56
+
57
+ /**
58
+ * This method marks the UI node as finalized. You can either call it without any parameters or with a new UI node as the final state.
59
+ * Once called, the UI node cannot be updated or appended anymore.
60
+ *
61
+ * This method is always **required** to be called, otherwise the response will be stuck in a loading state.
62
+ */
63
+ done ( ...args : [ React . ReactNode ] | [ ] ) : StreamableUIWrapper ;
64
+ } ;
65
+
20
66
/**
21
67
* Create a piece of changable UI that can be streamed to the client.
22
68
* On the client side, it can be rendered as a normal React node.
@@ -47,14 +93,8 @@ function createStreamableUI(initialValue?: React.ReactNode) {
47
93
}
48
94
warnUnclosedStream ( ) ;
49
95
50
- const streamable = {
51
- /**
52
- * The value of the streamable UI. This can be returned from a Server Action and received by the client.
53
- */
96
+ const streamable : StreamableUIWrapper = {
54
97
value : row ,
55
- /**
56
- * This method updates the current UI node. It takes a new UI node and replaces the old one.
57
- */
58
98
update ( value : React . ReactNode ) {
59
99
assertStream ( '.update()' ) ;
60
100
@@ -75,22 +115,6 @@ function createStreamableUI(initialValue?: React.ReactNode) {
75
115
76
116
return streamable ;
77
117
} ,
78
- /**
79
- * This method is used to append a new UI node to the end of the old one.
80
- * Once appended a new UI node, the previous UI node cannot be updated anymore.
81
- *
82
- * @example
83
- * ```jsx
84
- * const ui = createStreamableUI(<div>hello</div>)
85
- * ui.append(<div>world</div>)
86
- *
87
- * // The UI node will be:
88
- * // <>
89
- * // <div>hello</div>
90
- * // <div>world</div>
91
- * // </>
92
- * ```
93
- */
94
118
append ( value : React . ReactNode ) {
95
119
assertStream ( '.append()' ) ;
96
120
@@ -105,10 +129,6 @@ function createStreamableUI(initialValue?: React.ReactNode) {
105
129
106
130
return streamable ;
107
131
} ,
108
- /**
109
- * This method is used to signal that there is an error in the UI stream.
110
- * It will be thrown on the client side and caught by the nearest error boundary component.
111
- */
112
132
error ( error : any ) {
113
133
assertStream ( '.error()' ) ;
114
134
@@ -120,12 +140,6 @@ function createStreamableUI(initialValue?: React.ReactNode) {
120
140
121
141
return streamable ;
122
142
} ,
123
- /**
124
- * This method marks the UI node as finalized. You can either call it without any parameters or with a new UI node as the final state.
125
- * Once called, the UI node cannot be updated or appended anymore.
126
- *
127
- * This method is always **required** to be called, otherwise the response will be stuck in a loading state.
128
- */
129
143
done ( ...args : [ ] | [ React . ReactNode ] ) {
130
144
assertStream ( '.done()' ) ;
131
145
@@ -209,6 +223,59 @@ function createStreamableValue<T = any, E = any>(
209
223
return streamableValue ;
210
224
}
211
225
226
+ // It's necessary to define the type manually here, otherwise TypeScript compiler
227
+ // will not be able to infer the correct return type as it's circular.
228
+ type StreamableValueWrapper < T , E > = {
229
+ /**
230
+ * The value of the streamable. This can be returned from a Server Action and
231
+ * received by the client. To read the streamed values, use the
232
+ * `readStreamableValue` or `useStreamableValue` APIs.
233
+ */
234
+ readonly value : StreamableValue < T , E > ;
235
+
236
+ /**
237
+ * This method updates the current value with a new one.
238
+ */
239
+ update ( value : T ) : StreamableValueWrapper < T , E > ;
240
+
241
+ /**
242
+ * This method is used to append a delta string to the current value. It
243
+ * requires the current value of the streamable to be a string.
244
+ *
245
+ * @example
246
+ * ```jsx
247
+ * const streamable = createStreamableValue('hello');
248
+ * streamable.append(' world');
249
+ *
250
+ * // The value will be 'hello world'
251
+ * ```
252
+ */
253
+ append ( value : T ) : StreamableValueWrapper < T , E > ;
254
+
255
+ /**
256
+ * This method is used to signal that there is an error in the value stream.
257
+ * It will be thrown on the client side when consumed via
258
+ * `readStreamableValue` or `useStreamableValue`.
259
+ */
260
+ error ( error : any ) : StreamableValueWrapper < T , E > ;
261
+
262
+ /**
263
+ * This method marks the value as finalized. You can either call it without
264
+ * any parameters or with a new value as the final state.
265
+ * Once called, the value cannot be updated or appended anymore.
266
+ *
267
+ * This method is always **required** to be called, otherwise the response
268
+ * will be stuck in a loading state.
269
+ */
270
+ done ( ...args : [ T ] | [ ] ) : StreamableValueWrapper < T , E > ;
271
+
272
+ /**
273
+ * @internal This is an internal lock to prevent the value from being
274
+ * updated by the user.
275
+ */
276
+ [ STREAMABLE_VALUE_INTERNAL_LOCK ] : boolean ;
277
+ } ;
278
+
212
279
function createStreamableValueImpl < T = any , E = any > ( initialValue ?: T ) {
213
280
let closed = false ;
214
281
let locked = false ;
@@ -286,25 +353,13 @@ function createStreamableValueImpl<T = any, E = any>(initialValue?: T) {
286
353
currentValue = value ;
287
354
}
288
355
289
- const streamable = {
290
- /**
291
- * @internal This is an internal lock to prevent the value from being
292
- * updated by the user.
293
- */
356
+ const streamable : StreamableValueWrapper < T , E > = {
294
357
set [ STREAMABLE_VALUE_INTERNAL_LOCK ] ( state : boolean ) {
295
358
locked = state ;
296
359
} ,
297
- /**
298
- * The value of the streamable. This can be returned from a Server Action and
299
- * received by the client. To read the streamed values, use the
300
- * `readStreamableValue` or `useStreamableValue` APIs.
301
- */
302
360
get value ( ) {
303
361
return createWrapped ( true ) ;
304
362
} ,
305
- /**
306
- * This method updates the current value with a new one.
307
- */
308
363
update ( value : T ) {
309
364
assertStream ( '.update()' ) ;
310
365
@@ -319,18 +374,6 @@ function createStreamableValueImpl<T = any, E = any>(initialValue?: T) {
319
374
320
375
return streamable ;
321
376
} ,
322
- /**
323
- * This method is used to append a delta string to the current value. It
324
- * requires the current value of the streamable to be a string.
325
- *
326
- * @example
327
- * ```jsx
328
- * const streamable = createStreamableValue('hello');
329
- * streamable.append(' world');
330
- *
331
- * // The value will be 'hello world'
332
- * ```
333
- */
334
377
append ( value : T ) {
335
378
assertStream ( '.append()' ) ;
336
379
@@ -366,11 +409,6 @@ function createStreamableValueImpl<T = any, E = any>(initialValue?: T) {
366
409
367
410
return streamable ;
368
411
} ,
369
- /**
370
- * This method is used to signal that there is an error in the value stream.
371
- * It will be thrown on the client side when consumed via
372
- * `readStreamableValue` or `useStreamableValue`.
373
- */
374
412
error ( error : any ) {
375
413
assertStream ( '.error()' ) ;
376
414
@@ -385,14 +423,6 @@ function createStreamableValueImpl<T = any, E = any>(initialValue?: T) {
385
423
386
424
return streamable ;
387
425
} ,
388
- /**
389
- * This method marks the value as finalized. You can either call it without
390
- * any parameters or with a new value as the final state.
391
- * Once called, the value cannot be updated or appended anymore.
392
- *
393
- * This method is always **required** to be called, otherwise the response
394
- * will be stuck in a loading state.
395
- */
396
426
done ( ...args : [ ] | [ T ] ) {
397
427
assertStream ( '.done()' ) ;
398
428
0 commit comments