Skip to content

Commit ab974ca

Browse files
authored
feat: allow string enums for errors (#345)
## Why to provide better type safety and developer experience when defining error schemas. ## What changed - Added support for TypeScript enums as valid error code types in the `BaseErrorSchemaType` - Updated the `Flatten` type helper to properly handle unions containing enum-based error schemas - Tests ## Versioning - [ ] Breaking protocol change - [ ] Breaking ts/js API change
1 parent 012e38c commit ab974ca

File tree

3 files changed

+62
-4
lines changed

3 files changed

+62
-4
lines changed

__tests__/typescript-stress.test.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,12 @@ import { flattenErrorType, ProcedureErrorSchemaType } from '../router/errors';
2525
import { ReadableImpl } from '../router/streams';
2626
import { createMockTransportNetwork } from '../testUtil/fixtures/mockTransport';
2727

28+
enum TestErrorCodes {
29+
ERROR_ONE = 'ERROR_ONE',
30+
ERROR_TWO = 'ERROR_TWO',
31+
ERROR_THREE = 'ERROR_THREE',
32+
}
33+
2834
const requestData = Type.Union([
2935
Type.Object({ a: Type.Number() }),
3036
Type.Object({ c: Type.String() }),
@@ -479,6 +485,53 @@ describe('Procedure error schema', () => {
479485
);
480486
});
481487

488+
test('object with enum code', () => {
489+
acceptErrorSchema(
490+
Type.Object({
491+
code: Type.Enum(TestErrorCodes),
492+
message: Type.String(),
493+
}),
494+
);
495+
});
496+
497+
test('union containing enum-based error schemas', () => {
498+
acceptErrorSchema(
499+
Type.Union([
500+
Type.Object({
501+
code: Type.Enum(TestErrorCodes),
502+
message: Type.String(),
503+
}),
504+
Type.Object({
505+
code: Type.Literal('OTHER_ERROR'),
506+
message: Type.String(),
507+
}),
508+
]),
509+
);
510+
});
511+
512+
test('flattenErrorType with enum-based error schemas', () => {
513+
acceptErrorSchema(
514+
flattenErrorType(
515+
Type.Union([
516+
Type.Object({
517+
code: Type.Enum(TestErrorCodes),
518+
message: Type.String(),
519+
}),
520+
Type.Union([
521+
Type.Object({
522+
code: Type.Literal('ERROR_4'),
523+
message: Type.String(),
524+
}),
525+
Type.Object({
526+
code: Type.Literal('ERROR_5'),
527+
message: Type.String(),
528+
}),
529+
]),
530+
]),
531+
),
532+
);
533+
});
534+
482535
test('union of union', () => {
483536
acceptErrorSchema(
484537
flattenErrorType(

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@replit/river",
33
"description": "It's like tRPC but... with JSON Schema Support, duplex streaming and support for service multiplexing. Transport agnostic!",
4-
"version": "0.209.8",
4+
"version": "0.210.0",
55
"type": "module",
66
"exports": {
77
".": {

router/errors.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {
22
Kind,
33
Static,
4+
TEnum,
45
TLiteral,
56
TNever,
67
TObject,
@@ -32,13 +33,15 @@ export const CANCEL_CODE = 'CANCEL';
3233

3334
type TLiteralString = TLiteral<string>;
3435

36+
type TEnumString = TEnum<Record<string, string>>;
37+
3538
export type BaseErrorSchemaType =
3639
| TObject<{
37-
code: TLiteralString;
40+
code: TLiteralString | TEnumString;
3841
message: TLiteralString | TString;
3942
}>
4043
| TObject<{
41-
code: TLiteralString;
44+
code: TLiteralString | TEnumString;
4245
message: TLiteralString | TString;
4346
extras: TSchema;
4447
}>;
@@ -139,7 +142,9 @@ function isUnion(schema: TSchema): schema is TUnion {
139142
type Flatten<T> = T extends BaseErrorSchemaType
140143
? T
141144
: T extends TUnion<Array<infer U extends TSchema>>
142-
? Flatten<U>
145+
? U extends BaseErrorSchemaType
146+
? TUnion<Array<U>>
147+
: Flatten<U>
143148
: unknown;
144149

145150
/**

0 commit comments

Comments
 (0)