生成 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.
1npm i supabase@">=1.8.1" --save-dev使用你的个人访问令牌登录:
🌐 Login with your Personal Access Token:
1npx supabase login在生成类型之前,确保你已经初始化了你的 Supabase 项目:
🌐 Before generating types, ensure you initialize your Supabase project:
1npx supabase init为你的项目生成类型以生成 database.types.ts 文件:
🌐 Generate types for your project to produce the database.types.ts file:
1npx supabase gen types typescript --project-id "$PROJECT_REF" --schema public > database.types.ts或者在本地开发时:
🌐 or in case of local development:
1npx supabase gen types typescript --local > database.types.ts或者在自托管实例的情况下(有关更多信息,请参见访问 Postgres:)
🌐 or in case of a self-hosted instance (see Accessing Postgres for more information):
1npx 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:
1create table public.movies (2 id bigint generated always as identity primary key,3 name text not null,4 data jsonb null5);1export type Json = string | number | boolean | null | { [key: string]: Json | undefined } | Json[]23export interface Database {4 public: {5 Tables: {6 movies: {7 Row: {8 // the data expected from .select()9 id: number10 name: string11 data: Json | null12 }13 Insert: {14 // the data to be passed to .insert()15 id?: never // generated columns must not be supplied16 name: string // `not null` columns with no default must be supplied17 data?: Json | null // nullable columns can be omitted18 }19 Update: {20 // the data to be passed to .update()21 id?: never22 name?: string // `not null` columns are optional on .update()23 data?: Json | null24 }25 }26 }27 }28}使用 TypeScript 类型定义 #
🌐 Using TypeScript type definitions
你可以这样给 supabase-js 提供类型定义:
🌐 You can supply the type definitions to supabase-js like so:
1import { createClient } from '@supabase/supabase-js'2import { Database } from './database.types'34const supabase = createClient<Database>(5 process.env.SUPABASE_URL,6 process.env.SUPABASE_PUBLISHABLE_KEY7)表格和连接的辅助类型 #
🌐 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:
1export type Json = // ...23export interface Database {4 // ...5}1import { MergeDeep } from 'type-fest'2import { Database as DatabaseGenerated } from './database-generated.types'3export { Json } from './database-generated.types'45// Override the type for a specific column in a view:6export 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: number15 }16 }17 }18 }19 }20>要使用 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:
1import { MergeDeep } from 'type-fest'2import { Database as DatabaseGenerated } from './database-generated.types'34// Define your custom JSON type5type CustomJsonType = {6 foo: string7 bar: { baz: number }8 en: 'ONE' | 'TWO' | 'THREE'9}1011export type Database = MergeDeep<12 DatabaseGenerated,13 {14 public: {15 Tables: {16 your_table: {17 Row: {18 data: CustomJsonType | null19 }20 // Optional: Use if you want type-checking for inserts and updates21 // 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 | null33 }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:
1const res = await client.from('your_table').select('data->bar->baz, data->en, data->bar')23if (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 results2const { 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 argument4const { data } = await supabase5 .from('countries')6 .select()7 .overrideTypes<Array<{ id: string }>, { merge: false }>()8// Use it with `maybeSingle` or `single`9const { data } = await supabase.from('countries').select().single().overrideTypes<{ id: string }>()打字速记 #
🌐 Type shorthands
生成的类型提供了访问表和枚举的快捷方式。
🌐 The generated types provide shorthands for accessing tables and enums.
1import { Database, Tables, Enums } from "./database.types.ts";23// Before 😕4let movie: Database['public']['Tables']['movies']['Row'] = // ...56// After 😍7let 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:
1create table countries (2 "id" serial primary key,3 "name" text4);56create 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:
1import { QueryResult, QueryData, QueryError } from '@supabase/supabase-js'23const countriesWithCitiesQuery = supabase.from('countries').select(`4 id,5 name,6 cities (7 id,8 name9 )10`)11type CountriesWithCities = QueryData<typeof countriesWithCitiesQuery>1213const { data, error } = await countriesWithCitiesQuery14if (error) throw error15const 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.
1name: Update database types23on:4 schedule:5 # sets the action to run daily. You can modify this to run the action more or less frequently6 - cron: '0 0 * * *'78jobs:9 update:10 runs-on: ubuntu-latest11 permissions:12 contents: write13 env:14 SUPABASE_ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }}15 PROJECT_REF: <your-project-id>16 steps:17 - uses: actions/checkout@v418 with:19 persist-credentials: false20 fetch-depth: 021 - uses: actions/setup-node@v422 with:23 node-version: 2224 - run: npm run update-types25 - name: check for file changes26 id: git_status27 run: |28 echo "status=$(git status -s)" >> $GITHUB_OUTPUT29 - name: Commit files30 if: ${{contains(steps.git_status.outputs.status, ' ')}}31 run: |32 git add database.types.ts33 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" -a36 - name: Push changes37 if: ${{contains(steps.git_status.outputs.status, ' ')}}38 uses: ad-m/github-push-action@master39 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