Skip to content

Commit

Permalink
correctly infer types for application/json with charset specifier
Browse files Browse the repository at this point in the history
  • Loading branch information
Lucas Treffenstädt committed Sep 23, 2022
1 parent afde9eb commit 4d1c23e
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 4 deletions.
17 changes: 13 additions & 4 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@ export type OpenapiPaths<Paths> = {
}
}

type ApplicationJson = 'application/json' | `application/json;${string}`

type JsonResponse<T> = [T] extends [Record<string, unknown>]
? {
[K in keyof T]: K extends ApplicationJson ? T[K] : never
}[keyof T]
: unknown

export type OpArgType<OP> = OP extends {
parameters?: {
path?: infer P
Expand All @@ -23,12 +31,13 @@ export type OpArgType<OP> = OP extends {
}
// openapi 3
requestBody?: {
content: {
'application/json': infer RB
}
content: infer RB
}
}
? P & Q & (B extends Record<string, unknown> ? B[keyof B] : unknown) & RB
? P &
Q &
(B extends Record<string, unknown> ? B[keyof B] : unknown) &
JsonResponse<RB>
: Record<string, never>

type OpResponseTypes<OP> = OP extends {
Expand Down
57 changes: 57 additions & 0 deletions test/infer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,26 @@ type Op3 = Omit<paths3['/v1/account_links']['post'], 'requestBody'> & {
}
}

type Op4 = Omit<paths3['/v1/account_links']['post'], 'requestBody'> & {
requestBody: {
content: {
'application/json;charset=utf-8': paths3['/v1/account_links']['post']['requestBody']['content']['application/x-www-form-urlencoded']
}
}
responses: {
200: {
content: {
'application/json;charset=UTF-8': paths3['/v1/account_links']['post']['responses']['200']['content']['application/json']
}
}
default: {
content: {
'application/json; charset=UTF-8': paths3['/v1/account_links']['post']['responses']['default']['content']['application/json']
}
}
}
}

interface Openapi2 {
Argument: OpArgType<Op2>
Return: OpReturnType<Op2>
Expand All @@ -37,6 +57,13 @@ interface Openapi3 {
Error: Pick<OpErrorType<Op3>['data']['error'], 'type' | 'message'>
}

interface Openapi4 {
Argument: OpArgType<Op4>
Return: OpReturnType<Op4>
Default: Pick<OpDefaultReturnType<Op4>['error'], 'type' | 'message'>
Error: Pick<OpErrorType<Op4>['data']['error'], 'type' | 'message'>
}

type Same<A, B> = A extends B ? (B extends A ? true : false) : false

describe('infer', () => {
Expand Down Expand Up @@ -128,4 +155,34 @@ describe('infer', () => {
const err: Err = { data: { error: {} } } as any
expect(err.data.error.charge).toBeUndefined()
})

describe('application/json with charset', () => {
it('argument', () => {
const same: Same<Openapi4['Argument'], Openapi3['Argument']> = true
expect(same).toBe(true)

// @ts-expect-error -- missing properties
const arg: Openapi4['Argument'] = {}
expect(arg.account).toBeUndefined()
})

it('return', () => {
const same: Same<Openapi4['Return'], Openapi3['Return']> = true
expect(same).toBe(true)

// @ts-expect-error -- missing properties
const ret: Openapi4['Return'] = {}
expect(ret.url).toBeUndefined()
})

it('default', () => {
const same: Same<Openapi4['Default'], Openapi3['Default']> = true
expect(same).toBe(true)
})

it('error', () => {
const same: Same<Openapi4['Error'], Openapi3['Error']> = true
expect(same).toBe(true)
})
})
})

0 comments on commit 4d1c23e

Please sign in to comment.