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.

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

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

🌐 Login with your Personal Access Token:

1
npx supabase login

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

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

1
npx supabase init

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

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

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

或者在本地开发时:

🌐 or in case of local development:

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

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

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

1
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:

1
create table public.movies (
2
id bigint generated always as identity primary key,
3
name text not null,
4
data jsonb null
5
);
1
export type Json = string | number | boolean | null | { [key: string]: Json | undefined } | Json[]
2
3
export interface Database {
4
public: {
5
Tables: {
6
movies: {
7
Row: {
8
// the data expected from .select()
9
id: number
10
name: string
11
data: Json | null
12
}
13
Insert: {
14
// the data to be passed to .insert()
15
id?: never // generated columns must not be supplied
16
name: string // `not null` columns with no default must be supplied
17
data?: Json | null // nullable columns can be omitted
18
}
19
Update: {
20
// the data to be passed to .update()
21
id?: never
22
name?: string // `not null` columns are optional on .update()
23
data?: Json | null
24
}
25
}
26
}
27
}
28
}

使用 TypeScript 类型定义 #

🌐 Using TypeScript type definitions

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

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

1
import { createClient } from '@supabase/supabase-js'
2
import { Database } from './database.types'
3
4
const supabase = createClient<Database>(
5
process.env.SUPABASE_URL,
6
process.env.SUPABASE_PUBLISHABLE_KEY
7
)

表格和连接的辅助类型 #

🌐 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:

1
export type Json = // ...
2
3
export interface Database {
4
// ...
5
}
1
import { MergeDeep } from 'type-fest'
2
import { Database as DatabaseGenerated } from './database-generated.types'
3
export { Json } from './database-generated.types'
4
5
// Override the type for a specific column in a view:
6
export type Database = MergeDeep<
7
DatabaseGenerated,
8
{
9
public: {
10
Views: {
11
movies_view: {
12
Row: {
13
// id is a primary key in public.movies, so it must be `not null`
14
id: number
15
}
16
}
17
}
18
}
19
}
20
>

增强的 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:

1
import { MergeDeep } from 'type-fest'
2
import { Database as DatabaseGenerated } from './database-generated.types'
3
4
// Define your custom JSON type
5
type CustomJsonType = {
6
foo: string
7
bar: { baz: number }
8
en: 'ONE' | 'TWO' | 'THREE'
9
}
10
11
export type Database = MergeDeep<
12
DatabaseGenerated,
13
{
14
public: {
15
Tables: {
16
your_table: {
17
Row: {
18
data: CustomJsonType | null
19
}
20
// Optional: Use if you want type-checking for inserts and updates
21
// Insert: {
22
// data?: CustomJsonType | null;
23
// };
24
// Update: {
25
// data?: CustomJsonType | null;
26
// };
27
}
28
}
29
Views: {
30
your_view: {
31
Row: {
32
data: CustomJsonType | null
33
}
34
}
35
}
36
}
37
}
38
>

类型安全的 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:

1
const res = await client.from('your_table').select('data->bar->baz, data->en, data->bar')
2
3
if (res.data) {
4
console.log(res.data)
5
// TypeScript infers the shape of your JSON data:
6
// [
7
// {
8
// baz: number;
9
// en: 'ONE' | 'TWO' | 'THREE';
10
// bar: { baz: number };
11
// }
12
// ]
13
}

此功能适用于:

🌐 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:

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

打字速记 #

🌐 Type shorthands

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

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

1
import { Database, Tables, Enums } from "./database.types.ts";
2
3
// Before 😕
4
let movie: Database['public']['Tables']['movies']['Row'] = // ...
5
6
// After 😍
7
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:

1
create table countries (
2
"id" serial primary key,
3
"name" text
4
);
5
6
create table cities (
7
"id" serial primary key,
8
"name" text,
9
"country_id" int references "countries"
10
);

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

🌐 We can get the nested CountriesWithCities type like this:

1
import { QueryResult, QueryData, QueryError } from '@supabase/supabase-js'
2
3
const countriesWithCitiesQuery = supabase.from('countries').select(`
4
id,
5
name,
6
cities (
7
id,
8
name
9
)
10
`)
11
type CountriesWithCities = QueryData<typeof countriesWithCitiesQuery>
12
13
const { data, error } = await countriesWithCitiesQuery
14
if (error) throw error
15
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

1
"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.

1
name: Update database types
2
3
on:
4
schedule:
5
# sets the action to run daily. You can modify this to run the action more or less frequently
6
- cron: '0 0 * * *'
7
8
jobs:
9
update:
10
runs-on: ubuntu-latest
11
permissions:
12
contents: write
13
env:
14
SUPABASE_ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }}
15
PROJECT_REF: <your-project-id>
16
steps:
17
- uses: actions/checkout@v4
18
with:
19
persist-credentials: false
20
fetch-depth: 0
21
- uses: actions/setup-node@v4
22
with:
23
node-version: 22
24
- run: npm run update-types
25
- name: check for file changes
26
id: git_status
27
run: |
28
echo "status=$(git status -s)" >> $GITHUB_OUTPUT
29
- name: Commit files
30
if: ${{contains(steps.git_status.outputs.status, ' ')}}
31
run: |
32
git add database.types.ts
33
git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com"
34
git config --local user.name "github-actions[bot]"
35
git commit -m "Update database types" -a
36
- name: Push changes
37
if: ${{contains(steps.git_status.outputs.status, ' ')}}
38
uses: ad-m/github-push-action@master
39
with:
40
github_token: ${{ secrets.GITHUB_TOKEN }}
41
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