Skip to content
REST API

生成 TypeScript 类型

How to generate types for your API and Supabase libraries.

Supabase 的 API 是从你的数据库生成的,这意味着我们可以使用数据库自省来生成类型安全的 API 定义。

🌐 Supabase APIs are generated from your database, which means that we can use database introspection to generate type-safe API definitions.

从项目仪表板生成类型 #

🌐 Generating types from project dashboard

Supabase 允许你直接从 项目仪表板 生成并下载 TypeScript 类型。

🌐 Supabase allows you to generate and download TypeScript types directly from the project dashboard.

使用 Supabase CLI 生成类型 #

🌐 Generating types using Supabase CLI

Supabase CLI 是一个单一的 Go 二进制应用,它提供了设置本地开发环境所需的一切。

🌐 The Supabase CLI is a single binary Go application that provides everything you need to setup a local development environment.

你可以通过 npm 或其他支持的包管理器安装 CLI。CLI 的最低要求版本是 v1.8.1。

🌐 You can install the CLI via npm or other supported package managers. The minimum required version of the CLI is v1.8.1.

npm i supabase@">=1.8.1" --save-dev

使用你的个人访问令牌登录:

🌐 Sign in with your Personal Access Token:

npx supabase login

在生成类型之前,确保你已经初始化了你的 Supabase 项目:

🌐 Before generating types, ensure you initialize your Supabase project:

npx supabase init

为你的项目生成类型以生成 database.types.ts 文件:

🌐 Generate types for your project to produce the database.types.ts file:

npx supabase gen types typescript --project-id "$PROJECT_REF" --schema public > database.types.ts

或者在本地开发时:

🌐 or in case of local development:

npx supabase gen types typescript --local > database.types.ts

或者在自托管实例的情况下(有关更多信息,请参见访问 Postgres:)

🌐 or in case of a self-hosted instance (see Accessing Postgres for more information):

npx supabase gen types typescript --db-url postgres://postgres.[POOLER_TENANT_ID]:[POSTGRES_PASSWORD]@[your-domain-or-ip]:5432/postgres --schema public > database.types.ts

这些类型是从你的数据库模式生成的。给定一个表 public.movies,生成的类型看起来会像这样:

🌐 These types are generated from your database schema. Given a table public.movies, the generated types will look like:

create table public.movies (
id bigint generated always as identity primary key,
name text not null,
data jsonb null
);
export type = string | number | boolean | null | { [: string]: | undefined } | []
export interface {
: {
: {
: {
: {
// the data expected from .select()
: number
: string
: | null
}
: {
// the data to be passed to .insert()
?: never // generated columns must not be supplied
: string // `not null` columns with no default must be supplied
?: | null // nullable columns can be omitted
}
: {
// the data to be passed to .update()
?: never
?: string // `not null` columns are optional on .update()
?: | null
}
}
}
}
}

使用 TypeScript 类型定义 #

🌐 Using TypeScript type definitions

你可以这样给 supabase-js 提供类型定义:

🌐 You can supply the type definitions to supabase-js like so:

import { createClient } from '@supabase/supabase-js'
import { Database } from './database.types'
const supabase = createClient<Database>(
process.env.SUPABASE_URL,
process.env.SUPABASE_PUBLISHABLE_KEY
)

表格和连接的辅助类型 #

🌐 Helper types for tables and joins

你可以使用以下辅助类型来让生成的 TypeScript 类型更容易使用。

🌐 You can use the following helper types to make the generated TypeScript types easier to use.

有时候生成的类型并不是你期望的。例如,一个视图的列可能显示为可空类型,而你原本希望它是 not null。使用 type-fest,你可以像这样覆盖类型:

🌐 Sometimes the generated types are not what you expect. For example, a view's column may show up as nullable when you expect it to be not null. Using type-fest, you can override the types like so:

export type Json = // ...
export interface Database {
// ...
}
import { MergeDeep } from 'type-fest'
import { Database as DatabaseGenerated } from './database-generated.types'
export { Json } from './database-generated.types'
// Override the type for a specific column in a view:
export type Database = MergeDeep<
DatabaseGenerated,
{
public: {
Views: {
movies_view: {
Row: {
// id is a primary key in public.movies, so it must be `not null`
id: number
}
}
}
}
}
>

增强的 JSON 字段类型推断 #

🌐 Enhanced type inference for JSON fields

从 supabase-js v2.48.0 开始,你可以为 JSON 字段定义自定义类型,并在使用 -> 和 ->> 操作符进行 JSON 选择时获得增强的类型推断。这让你在处理 JSON/JSONB 列时的代码更加类型安全和直观。

🌐 Starting from supabase-js v2.48.0, you can define custom types for JSON fields and get enhanced type inference when using JSON selectors with the -> and ->> operators. This makes your code more type-safe and intuitive when working with JSON/JSONB columns.

定义自定义 JSON 类型 #

🌐 Defining custom JSON types

你可以使用 MergeDeep 扩展你生成的数据库类型,以包含自定义的 JSON 模式:

🌐 You can extend your generated database types to include custom JSON schemas using MergeDeep:

import { MergeDeep } from 'type-fest'
import { Database as DatabaseGenerated } from './database-generated.types'
// Define your custom JSON type
type CustomJsonType = {
foo: string
bar: { baz: number }
en: 'ONE' | 'TWO' | 'THREE'
}
export type Database = MergeDeep<
DatabaseGenerated,
{
public: {
Tables: {
your_table: {
Row: {
data: CustomJsonType | null
}
// Optional: Use if you want type-checking for inserts and updates
// Insert: {
// data?: CustomJsonType | null;
// };
// Update: {
// data?: CustomJsonType | null;
// };
}
}
Views: {
your_view: {
Row: {
data: CustomJsonType | null
}
}
}
}
}
>

类型安全的 JSON 查询 #

🌐 Type-safe JSON querying

一旦你定义了自定义的 JSON 类型,TypeScript 在使用 JSON 选择器时就会自动推断出正确的类型:

🌐 Once you've defined your custom JSON types, TypeScript will automatically infer the correct types when using JSON selectors:

const res = await client.from('your_table').select('data->bar->baz, data->en, data->bar')
if (res.data) {
console.log(res.data)
// TypeScript infers the shape of your JSON data:
// [
// {
// baz: number;
// en: 'ONE' | 'TWO' | 'THREE';
// bar: { baz: number };
// }
// ]
}

此功能适用于:

🌐 This feature works with:

  • 单层 JSON 访问:data->foo
  • 嵌套 JSON 访问:data->bar->baz
  • 文本提取:data->>foo(返回字符串)
  • 混合选择,结合多个 JSON 路径

类型推断会自动处理 ->(返回 JSON)和 ->>(返回文本)操作符之间的差异,确保你的 TypeScript 类型与实际运行时行为一致。

🌐 The type inference automatically handles the difference between -> (returns JSON) and ->> (returns text) operators, ensuring your TypeScript types match the actual runtime behavior.

如果需要,你也可以覆盖单个成功响应的类型:

🌐 You can also override the type of an individual successful response if needed:

// Partial type override allows you to only override some of the properties in your results
const { data } = await supabase.from('countries').select().overrideTypes<Array<{ id: string }>>()
// For a full replacement of the original return type use the `{ merge: false }` property as second argument
const { data } = await supabase
.from('countries')
.select()
.overrideTypes<Array<{ id: string }>, { merge: false }>()
// Use it with `maybeSingle` or `single`
const { data } = await supabase.from('countries').select().single().overrideTypes<{ id: string }>()

打字速记 #

🌐 Type shorthands

生成的类型提供了访问表和枚举的快捷方式。

🌐 The generated types provide shorthands for accessing tables and enums.

import { Database, Tables, Enums } from "./database.types.ts";
// Before 😕
let movie: Database['public']['Tables']['movies']['Row'] = // ...
// After 😍
let movie: Tables<'movies'>

复杂查询的响应类型 #

🌐 Response types for complex queries

supabase-js 总是返回一个 data 对象(用于成功),以及一个 error 对象(用于请求失败)。

这些辅助类型提供了任何查询的结果类型,包括数据库连接的嵌套类型。

🌐 These helper types provide the result types from any query, including nested types for database joins.

给定如下的关于城市和国家关系的模式:

🌐 Given the following schema with a relation between cities and countries:

create table countries (
"id" serial primary key,
"name" text
);
create table cities (
"id" serial primary key,
"name" text,
"country_id" int references "countries"
);

我们可以这样获取嵌套的 CountriesWithCities 类型:

🌐 We can get the nested CountriesWithCities type like this:

import { QueryData, QueryError, QueryResult } from '@supabase/supabase-js'
const countriesWithCitiesQuery = supabase.from('countries').select(`
id,
name,
cities (
id,
name
)
`)
type CountriesWithCities = QueryData<typeof countriesWithCitiesQuery>
const { data, error } = await countriesWithCitiesQuery
if (error) throw error
const countriesWithCities: CountriesWithCities = data

使用 GitHub Actions 自动更新类型 #

🌐 Update types automatically with GitHub Actions

保持你的类型定义与数据库同步的一种方法是设置一个定期运行的 GitHub 动作。

🌐 One way to keep your type definitions in sync with your database is to set up a GitHub action that runs on a schedule.

将以下脚本添加到你的 package.json 中以使用 npm run update-types 运行它

🌐 Add the following script to your package.json to run it using npm run update-types

"update-types": "npx supabase gen types --lang=typescript --project-id \"$PROJECT_REF\" > database.types.ts"

创建一个名为 .github/workflows/update-types.yml 的文件,里面加入以下片段来定义动作以及环境变量。这个脚本会每晚把新的类型更改提交到你的仓库。

🌐 Create a file .github/workflows/update-types.yml with the following snippet to define the action along with the environment variables. This script will commit new type changes to your repo every night.

name: Update database types
on:
schedule:
# sets the action to run daily. You can modify this to run the action more or less frequently
- cron: '0 0 * * *'
jobs:
update:
runs-on: ubuntu-latest
permissions:
contents: write
env:
SUPABASE_ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }}
PROJECT_REF: <your-project-id>
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
fetch-depth: 0
- uses: actions/setup-node@v4
with:
node-version: 22
- run: npm run update-types
- name: check for file changes
id: git_status
run: |
echo "status=$(git status -s)" >> $GITHUB_OUTPUT
- name: Commit files
if: ${{contains(steps.git_status.outputs.status, ' ')}}
run: |
git add database.types.ts
git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"
git commit -m "Update database types" -a
- name: Push changes
if: ${{contains(steps.git_status.outputs.status, ' ')}}
uses: ad-m/github-push-action@master
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
branch: ${{ github.ref }}

或者,你可以使用一个社区支持的 GitHub 操作:generate-supabase-db-types-github-action。

🌐 Alternatively, you can use a community-supported GitHub action: generate-supabase-db-types-github-action.

资源 #

🌐 Resources