生成 TypeScript 接口
在 Payload 中构建自定义功能时,比如 插件、钩子、访问控制函数、自定义视图、GraphQL 查询/变更或其他任何功能,你可能会需要从 Payload 配置动态生成自己的 TypeScript 类型。
类型生成脚本
在 Payload 项目中运行以下命令,根据你的 Payload 配置生成类型:
payload generate:types
当你需要重新生成类型时,可以随时运行此命令,然后直接在 Payload 代码中使用这些类型。
禁用 declare 声明
默认情况下,generate:types
会在你的类型文件中添加一个 declare
声明,这会在 Payload 中自动启用类型推断。
但是,如果你在其他仓库中使用 payload-types.ts
文件,最好禁用这个 declare
声明,这样在使用 Payload 类型但没有安装 Payload 的项目中就不会出现 TS 错误。
// payload.config.ts
{
// ...
typescript: {
declare: false, // 如果不设置,默认为 true
},
}
如果禁用了 declare
模式,你需要手动在代码中添加 declare
声明,以便 Payload 类型能够被识别。以下示例展示了如何在 payload.config.ts
文件中声明你的类型:
import { Config } from './payload-types'
declare module 'payload' {
export interface GeneratedTypes extends Config {}
}
自定义输出文件路径
你可以通过在 Payload 配置中添加属性来指定类型生成的位置:
// payload.config.ts
{
// ...
typescript: {
// 默认值为: path.resolve(__dirname, './payload-types.ts')
outputFile: path.resolve(__dirname, './generated-types.ts'),
},
}
上述示例将你的类型文件 generated-types.ts
生成在 Payload 配置文件同级目录下。
自定义生成类型
Payload 基于 JSON schema 生成你的类型。你可以通过向 typescript.schema
传递函数来扩展该 JSON schema,从而扩展生成的类型:
// payload.config.ts
{
// ...
typescript: {
schema: [
({ jsonSchema }) => {
// 在此处修改 JSON schema
jsonSchema.definitions.Test = {
type: 'object',
properties: {
title: { type: 'string' },
content: { type: 'string' },
},
required: ['title', 'content'],
}
return jsonSchema
},
]
}
}
// 这将在你的 payload-types.ts 中生成以下类型:
export interface Test {
title: string
content: string
}
该函数接收现有的 JSON schema 作为参数,并返回修改后的 JSON schema。对于希望生成自己类型的插件来说,这个功能会很有用。
使用示例
例如,我们来看以下这个简单的 Payload 配置:
import type { Config } from 'payload'
const config: Config = {
serverURL: process.env.NEXT_PUBLIC_SERVER_URL,
admin: {
user: 'users',
},
collections: [
{
slug: 'users',
fields: [
{
name: 'name',
type: 'text',
required: true,
},
],
},
{
slug: 'posts',
admin: {
useAsTitle: 'title',
},
fields: [
{
name: 'title',
type: 'text',
},
{
name: 'author',
type: 'relationship',
relationTo: 'users',
},
],
},
],
}
通过生成类型,我们将得到一个包含以下两个 TypeScript 接口的文件:
export interface User {
id: string
name: string
email?: string
resetPasswordToken?: string
resetPasswordExpiration?: string
loginAttempts?: number
lockUntil?: string
}
export interface Post {
id: string
title?: string
author?: string | User
}
自定义字段接口
对于 array
、block
、group
和命名 tab
字段,你可以生成顶层可复用的接口。以下是一个 group 字段配置示例:
{
type: 'group',
name: 'meta',
interfaceName: 'SharedMeta', <-- 这里!!
fields: [
{
name: 'title',
type: 'text',
},
{
name: 'description',
type: 'text',
},
],
}
这将生成:
// 一个顶层可复用的接口!!
export interface SharedMeta {
title?: string
description?: string
}
// 在集合接口中的使用示例
export interface Collection1 {
// ...其他字段
meta?: SharedMeta
}
命名冲突警告
由于这些类型会被提升到顶层,你需要注意可能发生的命名冲突。例如,如果你有一个名为 Meta
的集合,同时又创建了一个名为 Meta
的接口,它们就会发生冲突。建议通过在接口名称后追加字段类型来限定作用域,例如使用 MetaGroup
或类似的命名方式。
使用你的类型
现在你的类型已经生成,Payload 的 Local API 将会具备类型提示。通常用户会希望在前端代码中使用这些类型,我们推荐使用 Payload 生成类型文件,然后将其复制到前端代码库中。这是将你的类型引入前端代码库的最简单方法。
添加 npm 脚本
重要提示
Payload 需要能够找到你的配置才能生成类型定义。
Payload 会自动尝试定位你的配置文件,但有时可能无法找到。例如,如果你在 /src
目录或类似结构中工作,你需要通过环境变量手动告诉 Payload 在哪里查找你的配置。如果这种情况适用于你,可以创建一个 npm 脚本来简化类型生成过程。
要添加一个 npm 脚本来生成类型并告诉 Payload 在哪里查找配置,请打开你的 package.json
并将 scripts
属性更新为以下内容:
{
"scripts": {
"generate:types": "PAYLOAD_CONFIG_PATH=src/payload.config.ts payload generate:types",
},
}
现在你可以运行 pnpm generate:types
来轻松生成类型定义。