Skip to content

Commit a9e336f

Browse files
committed
feat: add type for inferring all variants of a transformer
1 parent 86a1ea5 commit a9e336f

File tree

2 files changed

+64
-1
lines changed

2 files changed

+64
-1
lines changed

src/types.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { type ContainerResolver } from '@adonisjs/fold'
1313
import type { Item } from './resource/item.ts'
1414
import { type Paginator } from './paginator.ts'
1515
import type { Collection } from './resource/collection.ts'
16+
import { type BaseTransformer } from './base_transformer.ts'
1617

1718
/**
1819
* Counter to increment the depth. At max we will allow fetching
@@ -434,6 +435,42 @@ export type InferData<
434435
? UnpackValues<Awaited<ReturnType<Transformer[Variant]>>, MaxDepth, Depth, false>
435436
: never
436437

438+
/**
439+
* Infers the data structure for all variant methods of a transformer class, excluding
440+
* the default 'toObject' method and base transformer methods.
441+
*
442+
* @template Transformer - The resource class to infer variant data from
443+
* @template MaxDepth - Maximum depth allowed for unpacking (defaults to -1 for unlimited)
444+
* @template Depth - Current depth level (defaults to 0)
445+
*
446+
* @example
447+
* ```typescript
448+
* class UserResource {
449+
* toObject() { return { id: 1, name: "John" } }
450+
* toSummary() { return { id: 1 } }
451+
* toProfile() { return { id: 1, name: "John", email: "john@example.com" } }
452+
* }
453+
*
454+
* type UserVariants = InferVariants<UserResource>
455+
* // Result: {
456+
* // toSummary: { id: number }
457+
* // toProfile: { id: number; name: string; email: string }
458+
* // }
459+
* ```
460+
*/
461+
export type InferVariants<Transformer, MaxDepth extends number = -1, Depth extends number = 0> = {
462+
[O in {
463+
[K in keyof Transformer]: 'toObject' extends K
464+
? never
465+
: K extends keyof BaseTransformer<any>
466+
? never
467+
: Transformer[K] extends (...args: any[]) => unknown
468+
? K
469+
: never
470+
}[keyof Transformer] &
471+
string]: InferData<Transformer, O, MaxDepth, Depth>
472+
}
473+
437474
/**
438475
* Function interface for the main serialize function that handles different data types.
439476
* Provides overloads for serializing Items, Collections, Paginators, and resource data.

tests/types.spec.ts

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import { test } from '@japa/runner'
1111
import { debug } from '../src/debug.ts'
1212
import { serialize } from '../src/serialize.ts'
13-
import { type InferData } from '../src/types.ts'
13+
import { type InferVariants, type InferData } from '../src/types.ts'
1414
import { User } from './fixtures/models/user.ts'
1515
import { Post } from './fixtures/models/posts.ts'
1616
import { Email } from './fixtures/models/email.ts'
@@ -232,4 +232,30 @@ test.group('Types | Fixtures', () => {
232232
}>()
233233
expectTypeOf(emailDataObject).toEqualTypeOf<EmailData>()
234234
})
235+
236+
test('infer all variants of a transformer', async ({ expectTypeOf }) => {
237+
const user = new User()
238+
const userTransformer = new UserTransformer(user)
239+
const userDataObject = await serialize(UserTransformer.transform(user).useVariant('basicInfo'))
240+
241+
type UserData = InferVariants<typeof userTransformer>
242+
debug('%O', userDataObject)
243+
244+
expectTypeOf<UserData>().toEqualTypeOf<{
245+
basicInfo: {
246+
id: number
247+
name: string
248+
profile?:
249+
| {
250+
id: number
251+
twitterHandle: string | null
252+
githubUsername: string | null
253+
}
254+
| null
255+
| undefined
256+
}
257+
}>()
258+
259+
expectTypeOf(userDataObject).toEqualTypeOf<UserData['basicInfo']>()
260+
})
235261
})

0 commit comments

Comments
 (0)