Skip to content

Commit 44bdf93

Browse files
authored
feat(contract): new type util for custom schema (#94)
* feat(contract):new type util for custom schema * map input
1 parent 43c0c87 commit 44bdf93

5 files changed

Lines changed: 70 additions & 1 deletion

File tree

packages/contract/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export * from './procedure-decorated'
1818
export * from './router'
1919
export * from './router-builder'
2020
export * from './router-client'
21+
export * from './schema-utils'
2122
export * from './types'
2223

2324
export const oc = new ContractBuilder<Record<never, never>>({
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import type { SchemaInput, SchemaOutput } from './types'
2+
import { type } from './schema-utils'
3+
4+
describe('type', () => {
5+
it('without map', () => {
6+
const schema = type<string>()
7+
8+
expectTypeOf<SchemaInput<typeof schema>>().toEqualTypeOf<string>()
9+
expectTypeOf<SchemaOutput<typeof schema>>().toEqualTypeOf<string>()
10+
})
11+
12+
it('with map', () => {
13+
const schema2 = type<string, number>((val) => {
14+
expectTypeOf(val).toEqualTypeOf<string>()
15+
16+
return Number(val)
17+
})
18+
19+
expectTypeOf<SchemaInput<typeof schema2>>().toEqualTypeOf<string>()
20+
expectTypeOf<SchemaOutput<typeof schema2>>().toEqualTypeOf<number>()
21+
22+
// @ts-expect-error - map is required when TInput !== TOutput
23+
type<string, number>()
24+
25+
// @ts-expect-error - output not match number
26+
type<string, number>(() => '123')
27+
})
28+
})
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { type } from './schema-utils'
2+
3+
describe('type', async () => {
4+
it('without map', async () => {
5+
const schema = type()
6+
const val = {}
7+
expect((await schema['~standard'].validate(val) as any).value).toBe(val)
8+
})
9+
10+
it('with map', async () => {
11+
const val = {}
12+
const check = vi.fn().mockReturnValueOnce('__mapped__')
13+
const schema = type(check)
14+
expect((await schema['~standard'].validate(val) as any).value).toBe('__mapped__')
15+
expect(check).toHaveBeenCalledWith(val)
16+
})
17+
})
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import type { IsEqual, Promisable } from '@orpc/shared'
2+
import type { StandardSchemaV1 } from '@standard-schema/spec'
3+
4+
export type TypeRest<TInput, TOutput> =
5+
| [map: (input: TInput) => Promisable<TOutput>]
6+
| (IsEqual<TInput, TOutput> extends true ? [] : never)
7+
8+
export function type<TInput, TOutput = TInput>(...[map]: TypeRest<TInput, TOutput>): StandardSchemaV1<TInput, TOutput> {
9+
return {
10+
'~standard': {
11+
vendor: 'custom',
12+
version: 1,
13+
async validate(value) {
14+
if (map) {
15+
return { value: await map(value as TInput) as TOutput }
16+
}
17+
18+
return { value: value as TOutput }
19+
},
20+
},
21+
}
22+
}

packages/server/src/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export * from './router-client'
2121
export * from './router-implementer'
2222
export * from './types'
2323
export * from './utils'
24-
export { configGlobal, fallbackToGlobalConfig, isDefinedError, ORPCError, safe } from '@orpc/contract'
24+
25+
export { configGlobal, fallbackToGlobalConfig, isDefinedError, ORPCError, safe, type } from '@orpc/contract'
2526

2627
export const os = new Builder<WELL_CONTEXT>({})

0 commit comments

Comments
 (0)