Skip to main content

generated types

Complete reference for every type exported by Duck Gen, with usage examples for API routes and message registries.

Overview

duck-gen emits .d.ts files that export types for API routes and message registries. This page lists every exported type with a usage example.

Loading diagram...

Import generated types from the framework entrypoint:

import type {
  // API route types
  ApiRoutes,
  RoutePath,
  RouteReq,
  RouteRes,
  RouteMethod,
  RouteMethods,
  PathsByMethod,
  DuckFetcher,
  DuckClient,
  GetBody,
  GetQuery,
  GetParams,
  GetHeaders,
  GetRes,
  GetReq,
  // Message types
  DuckgenMessageSources,
  DuckgenMessageGroup,
  DuckgenMessageKey,
  DuckgenMessageDictionary,
  DuckgenMessageDictionaryByGroup,
  DuckGenI18nMessages,
  DuckgenI18n,
  DuckgenI18nByGroup,
  DuckgenScopedI18nByGroup,
} from '@gentleduck/gen/nestjs'
import type {
  // API route types
  ApiRoutes,
  RoutePath,
  RouteReq,
  RouteRes,
  RouteMethod,
  RouteMethods,
  PathsByMethod,
  DuckFetcher,
  DuckClient,
  GetBody,
  GetQuery,
  GetParams,
  GetHeaders,
  GetRes,
  GetReq,
  // Message types
  DuckgenMessageSources,
  DuckgenMessageGroup,
  DuckgenMessageKey,
  DuckgenMessageDictionary,
  DuckgenMessageDictionaryByGroup,
  DuckGenI18nMessages,
  DuckgenI18n,
  DuckgenI18nByGroup,
  DuckgenScopedI18nByGroup,
} from '@gentleduck/gen/nestjs'

API route types

Generated from NestJS controllers.

ApiRoutes

The main route map. Each key is a route path; the value describes method, request shape, and response type.

// The generated interface looks like:
interface ApiRoutes {
  '/api/auth/signin': {
    body: SigninDto
    query: never
    params: never
    headers: never
    res: AuthSession
    method: 'POST'
  }
  '/api/users/:id': {
    body: never
    query: never
    params: { id: string }
    headers: never
    res: UserDto
    method: 'GET'
  }
}
// The generated interface looks like:
interface ApiRoutes {
  '/api/auth/signin': {
    body: SigninDto
    query: never
    params: never
    headers: never
    res: AuthSession
    method: 'POST'
  }
  '/api/users/:id': {
    body: never
    query: never
    params: { id: string }
    headers: never
    res: UserDto
    method: 'GET'
  }
}

Pass ApiRoutes as the generic when creating a Duck Query client:

import { createDuckQueryClient } from '@gentleduck/query'
import type { ApiRoutes } from '@gentleduck/gen/nestjs'
 
const client = createDuckQueryClient<ApiRoutes>({
  baseURL: 'http://localhost:3000',
})
import { createDuckQueryClient } from '@gentleduck/query'
import type { ApiRoutes } from '@gentleduck/gen/nestjs'
 
const client = createDuckQueryClient<ApiRoutes>({
  baseURL: 'http://localhost:3000',
})

RoutePath

A union of all route path strings.

type RoutePath = '/api/auth/signin' | '/api/users/:id' | '/api/users'
type RoutePath = '/api/auth/signin' | '/api/users/:id' | '/api/users'

Use it to restrict a variable or parameter to valid route paths:

function logRoute(path: RoutePath) {
  console.log(`Calling ${path}`)
}
 
logRoute('/api/auth/signin') // ok
logRoute('/api/unknown')     // error: type error
function logRoute(path: RoutePath) {
  console.log(`Calling ${path}`)
}
 
logRoute('/api/auth/signin') // ok
logRoute('/api/unknown')     // error: type error

RouteReq

The request shape for a route. An object with body, query, params, and headers, filtered to the fields that are not never for that route.

type SigninReq = RouteReq<'/api/auth/signin'>
// => { body: SigninDto }
 
type UserReq = RouteReq<'/api/users/:id'>
// => { params: { id: string } }
 
type SearchReq = RouteReq<'/api/users'>
// => { query: PaginationDto }
type SigninReq = RouteReq<'/api/auth/signin'>
// => { body: SigninDto }
 
type UserReq = RouteReq<'/api/users/:id'>
// => { params: { id: string } }
 
type SearchReq = RouteReq<'/api/users'>
// => { query: PaginationDto }

The type you'll reach for most often when building request payloads:

function buildSigninPayload(): RouteReq<'/api/auth/signin'> {
  return {
    body: {
      username: 'duck',
      password: '123456',
    },
  }
}
function buildSigninPayload(): RouteReq<'/api/auth/signin'> {
  return {
    body: {
      username: 'duck',
      password: '123456',
    },
  }
}

RouteRes

The response type for a given route path.

type SigninRes = RouteRes<'/api/auth/signin'>
// => AuthSession
 
type UserRes = RouteRes<'/api/users/:id'>
// => UserDto
type SigninRes = RouteRes<'/api/auth/signin'>
// => AuthSession
 
type UserRes = RouteRes<'/api/users/:id'>
// => UserDto

Use it to type response handlers:

function handleSignin(response: RouteRes<'/api/auth/signin'>) {
  console.log('Signed in as', response.username)
}
function handleSignin(response: RouteRes<'/api/auth/signin'>) {
  console.log('Signed in as', response.username)
}

RouteMethod

The HTTP method for a given route path.

type SigninMethod = RouteMethod<'/api/auth/signin'>
// => 'POST'
 
type UserMethod = RouteMethod<'/api/users/:id'>
// => 'GET'
type SigninMethod = RouteMethod<'/api/auth/signin'>
// => 'POST'
 
type UserMethod = RouteMethod<'/api/users/:id'>
// => 'GET'

RouteMethods

A union of all HTTP methods used across all routes.

type AllMethods = RouteMethods
// => 'GET' | 'POST' | 'PUT' | 'DELETE' | ...
type AllMethods = RouteMethods
// => 'GET' | 'POST' | 'PUT' | 'DELETE' | ...

PathsByMethod

Filters route paths by HTTP method — returns only paths using that method.

type GetPaths = PathsByMethod<'GET'>
// => '/api/users/:id' | '/api/users'
 
type PostPaths = PathsByMethod<'POST'>
// => '/api/auth/signin' | '/api/users'
type GetPaths = PathsByMethod<'GET'>
// => '/api/users/:id' | '/api/users'
 
type PostPaths = PathsByMethod<'POST'>
// => '/api/auth/signin' | '/api/users'

Useful for method-specific helpers:

async function fetchAll<P extends PathsByMethod<'GET'>>(
  client: DuckQueryClient<ApiRoutes>,
  path: P,
) {
  return client.get(path)
}
async function fetchAll<P extends PathsByMethod<'GET'>>(
  client: DuckQueryClient<ApiRoutes>,
  path: P,
) {
  return client.get(path)
}

GetBody, GetQuery, GetParams, GetHeaders

Individual type extractors for each request component:

type SigninBody = GetBody<'/api/auth/signin'>
// => SigninDto
 
type UserParams = GetParams<'/api/users/:id'>
// => { id: string }
 
type SearchQuery = GetQuery<'/api/users'>
// => PaginationDto
 
type AuthHeaders = GetHeaders<'/api/me'>
// => { authorization: string }
type SigninBody = GetBody<'/api/auth/signin'>
// => SigninDto
 
type UserParams = GetParams<'/api/users/:id'>
// => { id: string }
 
type SearchQuery = GetQuery<'/api/users'>
// => PaginationDto
 
type AuthHeaders = GetHeaders<'/api/me'>
// => { authorization: string }

GetRes

Alias for RouteRes. Pick whichever name reads better:

type SigninResponse = GetRes<'/api/auth/signin'>
// => AuthSession
type SigninResponse = GetRes<'/api/auth/signin'>
// => AuthSession

GetReq

Alias for RouteReq:

type SigninRequest = GetReq<'/api/auth/signin'>
// => { body: SigninDto }
type SigninRequest = GetReq<'/api/auth/signin'>
// => { body: SigninDto }

DuckFetcher

A typed fetcher function signature for a route path:

type Fetcher = DuckFetcher<'/api/auth/signin'>
// => (req: { body: SigninDto }) => Promise<AuthSession>
type Fetcher = DuckFetcher<'/api/auth/signin'>
// => (req: { body: SigninDto }) => Promise<AuthSession>

DuckClient

A typed client helper with request and byMethod methods:

type Client = DuckClient
// => { request: ...; byMethod: ... }
type Client = DuckClient
// => { request: ...; byMethod: ... }

Message types

Generated from @duckgen tagged constants.

DuckgenMessageSources

Maps group keys to their source types — the raw registry:

type DuckgenMessageSources = {
  auth: typeof AuthMessages       // from @duckgen messages auth
  payments: typeof PaymentMessages // from @duckgen messages payments
}
type DuckgenMessageSources = {
  auth: typeof AuthMessages       // from @duckgen messages auth
  payments: typeof PaymentMessages // from @duckgen messages payments
}

DuckgenMessageGroup

A union of all group keys:

type DuckgenMessageGroup = 'auth' | 'payments'
type DuckgenMessageGroup = 'auth' | 'payments'

Use it for group-aware functions:

function getTranslations(group: DuckgenMessageGroup, lang: string) {
  return i18n[lang].server[group]
}
function getTranslations(group: DuckgenMessageGroup, lang: string) {
  return i18n[lang].server[group]
}

DuckgenMessageKey

A union of message keys, optionally scoped to a group:

// All keys across all groups
type AllKeys = DuckgenMessageKey
// => 'AUTH_SIGNIN_SUCCESS' | 'AUTH_SIGNIN_FAILED' | 'PAYMENT_SUCCESS' | ...
 
// Keys for a specific group
type AuthKeys = DuckgenMessageKey<'auth'>
// => 'AUTH_SIGNIN_SUCCESS' | 'AUTH_SIGNIN_FAILED' | ...
// All keys across all groups
type AllKeys = DuckgenMessageKey
// => 'AUTH_SIGNIN_SUCCESS' | 'AUTH_SIGNIN_FAILED' | 'PAYMENT_SUCCESS' | ...
 
// Keys for a specific group
type AuthKeys = DuckgenMessageKey<'auth'>
// => 'AUTH_SIGNIN_SUCCESS' | 'AUTH_SIGNIN_FAILED' | ...

Type-safe error handling:

function showError(key: DuckgenMessageKey<'auth'>, lang: 'en' | 'ar') {
  const message = i18n[lang].server.AuthMessages[key]
  toast.error(message)
}
 
showError('AUTH_SIGNIN_FAILED', 'en')  // ok
showError('UNKNOWN_KEY', 'en')          // error: type error
function showError(key: DuckgenMessageKey<'auth'>, lang: 'en' | 'ar') {
  const message = i18n[lang].server.AuthMessages[key]
  toast.error(message)
}
 
showError('AUTH_SIGNIN_FAILED', 'en')  // ok
showError('UNKNOWN_KEY', 'en')          // error: type error

DuckgenMessageDictionary

A record mapping message keys to string values for a group — the shape of one translation file:

type AuthDict = DuckgenMessageDictionary<'auth'>
// => {
//     AUTH_SIGNIN_SUCCESS: string
//     AUTH_SIGNIN_FAILED: string
//     AUTH_USERNAME_INVALID: string
//     AUTH_PASSWORD_INVALID: string
//   }
type AuthDict = DuckgenMessageDictionary<'auth'>
// => {
//     AUTH_SIGNIN_SUCCESS: string
//     AUTH_SIGNIN_FAILED: string
//     AUTH_USERNAME_INVALID: string
//     AUTH_PASSWORD_INVALID: string
//   }

Use it to type translation objects:

const authEn: DuckgenMessageDictionary<'auth'> = {
  AUTH_SIGNIN_SUCCESS: 'Signed in successfully',
  AUTH_SIGNIN_FAILED: 'Sign in failed',
  AUTH_USERNAME_INVALID: 'Invalid username',
  AUTH_PASSWORD_INVALID: 'Invalid password',
}
const authEn: DuckgenMessageDictionary<'auth'> = {
  AUTH_SIGNIN_SUCCESS: 'Signed in successfully',
  AUTH_SIGNIN_FAILED: 'Sign in failed',
  AUTH_USERNAME_INVALID: 'Invalid username',
  AUTH_PASSWORD_INVALID: 'Invalid password',
}

A missing key or an unknown key triggers a TypeScript error.

DuckgenMessageDictionaryByGroup

All groups mapped to their dictionaries in one object:

type AllDicts = DuckgenMessageDictionaryByGroup
// => {
//     auth: { AUTH_SIGNIN_SUCCESS: string; ... }
//     payments: { PAYMENT_SUCCESS: string; ... }
//   }
type AllDicts = DuckgenMessageDictionaryByGroup
// => {
//     auth: { AUTH_SIGNIN_SUCCESS: string; ... }
//     payments: { PAYMENT_SUCCESS: string; ... }
//   }

DuckGenI18nMessages

Alias for DuckgenMessageDictionaryByGroup. Pick whichever name reads better:

type Messages = DuckGenI18nMessages
// Same as DuckgenMessageDictionaryByGroup
type Messages = DuckGenI18nMessages
// Same as DuckgenMessageDictionaryByGroup

DuckgenI18n

Maps language codes to message dictionaries. Takes a language union and an optional group:

type AuthI18n = DuckgenI18n<'en' | 'ar', 'auth'>
// => {
//     en: { AUTH_SIGNIN_SUCCESS: string; ... }
//     ar: { AUTH_SIGNIN_SUCCESS: string; ... }
//   }
type AuthI18n = DuckgenI18n<'en' | 'ar', 'auth'>
// => {
//     en: { AUTH_SIGNIN_SUCCESS: string; ... }
//     ar: { AUTH_SIGNIN_SUCCESS: string; ... }
//   }

DuckgenI18nByGroup

Maps language codes to all group dictionaries:

type FullI18n = DuckgenI18nByGroup<'en' | 'ar'>
// => {
//     en: { auth: { ... }; payments: { ... } }
//     ar: { auth: { ... }; payments: { ... } }
//   }
type FullI18n = DuckgenI18nByGroup<'en' | 'ar'>
// => {
//     en: { auth: { ... }; payments: { ... } }
//     ar: { auth: { ... }; payments: { ... } }
//   }

DuckgenScopedI18nByGroup

The most common i18n type. Wraps all groups under a server scope, separating server-generated messages from client-only translations:

type ScopedI18n = DuckgenScopedI18nByGroup<'en' | 'ar', DuckGenI18nMessages>
// => {
//     en: {
//       server: {
//         AuthMessages: { AUTH_SIGNIN_SUCCESS: string; ... }
//         PaymentMessages: { PAYMENT_SUCCESS: string; ... }
//       }
//     }
//     ar: {
//       server: {
//         AuthMessages: { AUTH_SIGNIN_SUCCESS: string; ... }
//         PaymentMessages: { PAYMENT_SUCCESS: string; ... }
//       }
//     }
//   }
type ScopedI18n = DuckgenScopedI18nByGroup<'en' | 'ar', DuckGenI18nMessages>
// => {
//     en: {
//       server: {
//         AuthMessages: { AUTH_SIGNIN_SUCCESS: string; ... }
//         PaymentMessages: { PAYMENT_SUCCESS: string; ... }
//       }
//     }
//     ar: {
//       server: {
//         AuthMessages: { AUTH_SIGNIN_SUCCESS: string; ... }
//         PaymentMessages: { PAYMENT_SUCCESS: string; ... }
//       }
//     }
//   }

Full usage example:

import type { DuckgenScopedI18nByGroup, DuckGenI18nMessages } from '@gentleduck/gen/nestjs'
 
type Lang = 'en' | 'ar'
type I18n = DuckgenScopedI18nByGroup<Lang, DuckGenI18nMessages>
 
const i18n: I18n = {
  en: {
    server: {
      AuthMessages: {
        AUTH_SIGNIN_SUCCESS: 'Signed in successfully',
        AUTH_SIGNIN_FAILED: 'Sign in failed',
        // ... TypeScript enforces all keys are present
      },
      PaymentMessages: {
        PAYMENT_SUCCESS: 'Payment processed',
        PAYMENT_DECLINED: 'Payment declined',
      },
    },
  },
  ar: {
    server: {
      AuthMessages: {
        AUTH_SIGNIN_SUCCESS: 'تم تسجيل الدخول بنجاح',
        AUTH_SIGNIN_FAILED: 'فشل تسجيل الدخول',
      },
      PaymentMessages: {
        PAYMENT_SUCCESS: 'تم الدفع بنجاح',
        PAYMENT_DECLINED: 'تم رفض الدفع',
      },
    },
  },
}
import type { DuckgenScopedI18nByGroup, DuckGenI18nMessages } from '@gentleduck/gen/nestjs'
 
type Lang = 'en' | 'ar'
type I18n = DuckgenScopedI18nByGroup<Lang, DuckGenI18nMessages>
 
const i18n: I18n = {
  en: {
    server: {
      AuthMessages: {
        AUTH_SIGNIN_SUCCESS: 'Signed in successfully',
        AUTH_SIGNIN_FAILED: 'Sign in failed',
        // ... TypeScript enforces all keys are present
      },
      PaymentMessages: {
        PAYMENT_SUCCESS: 'Payment processed',
        PAYMENT_DECLINED: 'Payment declined',
      },
    },
  },
  ar: {
    server: {
      AuthMessages: {
        AUTH_SIGNIN_SUCCESS: 'تم تسجيل الدخول بنجاح',
        AUTH_SIGNIN_FAILED: 'فشل تسجيل الدخول',
      },
      PaymentMessages: {
        PAYMENT_SUCCESS: 'تم الدفع بنجاح',
        PAYMENT_DECLINED: 'تم رفض الدفع',
      },
    },
  },
}

Next steps