Skip to content

Item 58: Consider Codegen as an Alternative to Complex Types

要点

  • While type-level TypeScript is an impressively powerful tool, it's not always the best tool for the job.
  • For complex type manipulations, consider generating code and types as an alternative to writing type-level code. Your code generation tool can be written in ordinary TypeScript or any other language.
  • Run codegen and git diff on your continuous integration system to make sure generated code stays in sync.
  • 虽然 TypeScript 的类型层次非常强大,但并不总是最适合的工具。
  • 对于复杂的类型操作,考虑生成代码和类型作为写类型层次代码的替代方案。你的代码生成工具可以用普通的 TypeScript 或其他语言编写。
  • 在持续集成系统上运行代码生成和 git diff,以确保生成的代码与源代码保持同步。

正文

ts
async function getBooks(db: Database) {
  const result = await db.query(
    `SELECT title, author, year, publisher FROM books`
  )
  return result.rows
}

💻 playground


ts
async function getLatestBookByAuthor(db: Database, publisher: string) {
  const result = await db.query(
    `SELECT author, MAX(year) FROM books GROUP BY author WHERE publisher=$1`,
    [publisher]
  )
  return result.rows
}

💻 playground


ts
// books-queries.ts
import { sql } from '@pgtyped/runtime'
const selectLatest = sql`
    SELECT author, MAX(year)
    FROM books
    GROUP BY author
    WHERE publisher=$publisher
`

async function getLatestBookByAuthor(db: Database, publisher: string) {
  const result = await selectLatest.run({ publisher }, db)
  //    ^? const result: any[]
  return result
}

💻 playground


ts
// books-queries.types.ts
/** Types generated for queries found in "books-queries.ts" */

/** 'selectLatest' parameters type */
export interface selectLatestParams {
  publisher: string
}

/** 'selectLatest' return type */
export interface selectLatestResult {
  author: string
  year: number
}

/** 'selectLatest' query type */
export interface selectLatestQuery {
  params: selectLatestParams
  result: selectLatestResult
}

💻 playground


ts
// books-queries.ts
import { sql } from '@pgtyped/runtime'
import { selectLatestQuery } from './books-queries.types'
export const selectLatestBookByAuthor = sql<selectLatestQuery>`
    SELECT author, MAX(year)
    FROM books
    GROUP BY author
    WHERE publisher=$publisher
`

async function getLatestBookByAuthor(db: Database, publisher: string) {
  const result = await selectLatestBookByAuthor.run({ publisher }, db)
  //    ^? const result: selectLatestResult[]
  return result
}

💻 playground

Released under the MIT License.