Skip to content

Commit 93cae12

Browse files
gclark-eightfoldlgrammel
andauthoredJun 4, 2024
fix (rsc): Fix unsafe {} type in application code for StreamableValue (#1786)
Co-authored-by: Lars Grammel <lars.grammel@gmail.com>
1 parent 4f141de commit 93cae12

File tree

5 files changed

+43
-0
lines changed

5 files changed

+43
-0
lines changed
 

Diff for: ‎.changeset/nice-fishes-hear.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'ai': patch
3+
---
4+
5+
fix(ai/rsc): Fix unsafe {} type in application code for StreamableValue

Diff for: ‎packages/core/rsc/types.test-d.ts

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { expectTypeOf } from 'vitest';
2+
3+
import type { StreamableValue } from './dist';
4+
5+
describe('StreamableValue type', () => {
6+
it('should not contain types marked with @internal after compilation', () => {
7+
expectTypeOf<StreamableValue>().not.toHaveProperty('type');
8+
expectTypeOf<StreamableValue>().not.toHaveProperty('curr');
9+
expectTypeOf<StreamableValue>().not.toHaveProperty('error');
10+
expectTypeOf<StreamableValue>().not.toHaveProperty('diff');
11+
expectTypeOf<StreamableValue>().not.toHaveProperty('next');
12+
});
13+
14+
it('should yield a type error when assigning a wrong value', () => {
15+
expectTypeOf<StreamableValue<string>>().not.toEqualTypeOf<
16+
StreamableValue<boolean>
17+
>();
18+
19+
expectTypeOf<StreamableValue<string>>().not.toEqualTypeOf<string>();
20+
21+
expectTypeOf<
22+
StreamableValue<string>
23+
>().not.toEqualTypeOf<'THIS IS NOT A STREAMABLE VALUE'>();
24+
});
25+
});

Diff for: ‎packages/core/rsc/types.ts

+7
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,9 @@ export type MutableAIState<AIState> = {
8989

9090
export type StreamablePatch = undefined | [0, string]; // Append string.
9191

92+
declare const __internal_curr: unique symbol;
93+
declare const __internal_error: unique symbol;
94+
9295
/**
9396
* StreamableValue is a value that can be streamed over the network via AI Actions.
9497
* To read the streamed values, use the `readStreamableValue` or `useStreamableValue` APIs.
@@ -114,4 +117,8 @@ export type StreamableValue<T = any, E = any> = {
114117
* @internal Use `readStreamableValue` to read the values.
115118
*/
116119
next?: Promise<StreamableValue<T, E>>;
120+
121+
// branded types to maintain type signature after internal properties are stripped.
122+
[__internal_curr]?: T;
123+
[__internal_error]?: E;
117124
};

Diff for: ‎packages/core/vitest.edge.config.js

+3
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,8 @@ export default defineConfig({
77
globals: true,
88
include: ['**/*.test.ts', '**/*.test.tsx'],
99
exclude: ['**/*.ui.test.ts', '**/*.ui.test.tsx', 'node_modules/**'],
10+
typecheck: {
11+
enabled: true,
12+
},
1013
},
1114
});

Diff for: ‎packages/core/vitest.node.config.js

+3
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,8 @@ export default defineConfig({
77
globals: true,
88
include: ['**/*.test.ts', '**/*.test.tsx'],
99
exclude: ['**/*.ui.test.ts', '**/*.ui.test.tsx', 'node_modules/**'],
10+
typecheck: {
11+
enabled: true,
12+
},
1013
},
1114
});

0 commit comments

Comments
 (0)