生成 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 } } } } }>要使用 MergeDeep,在你的 tsconfig.json 中将 compilerOptions.strictNullChecks 设置为 true。
🌐 To use MergeDeep, set compilerOptions.strictNullChecks to true in your tsconfig.json.
增强的 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 typetype 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 resultsconst { 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 argumentconst { 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 countriesWithCitiesQueryif (error) throw errorconst 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 typeson: 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