# @adocasts\.com/dto 中文文档

规范地址：https://npmcn.com/package/%40adocasts.com/dto/

版本：0\.0\.10
npm 元数据更新时间：2025-06-23T01:27:39.298Z
中文译文更新时间：2026-11-06T02:09:31.103Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40adocasts.com/dto
原文对照：https://npmcn.com/package/%40adocasts.com/dto/?lang=original
项目主页：https://github.com/adocasts/package-dto#readme
源码仓库：https://github.com/adocasts/package-dto

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：69.6 kB，48 个文件
- 模块格式：ES Module
- TypeScript 类型：未声明
- Node.js 要求：\>=20\.6\.0
- 运行依赖：2 个
- peer 依赖：@adonisjs/core ^6\.2\.0，@adonisjs/lucid ^21\.1\.0
- 首次发布：2024-06-10T00:35:08.598Z
- 最新版本发布：2025-06-23T01:27:39.073Z
- 近 30 天下载量：6673（2026-10-05 至 2026-11-03，npm 官方下载统计）
- 已发布版本数：10（近 12 个月 0 个）

## 中文简介

从 Lucid 模型轻松地制作和生成 DTO

## 安装

```sh
npm install @adocasts.com/dto
```

也可以使用：`pnpm add @adocasts.com/dto`、`yarn add @adocasts.com/dto`、`bun add @adocasts.com/dto`

## README

# @ adocasts.com/dto (英语)

> 从 Lucid Models 轻松地制作和生成 DTO 和验证器

[![gh-workflow-image](https://img.shields.io/github/actions/workflow/status/adocasts/package-dto/test.yml?style=for-the-badge)](https://github.com/adocasts/package-dto/actions/workflows/test.yml "Github action") [![npm-image](https://img.shields.io/npm/v/@adocasts.com/dto/latest.svg?style=for-the-badge&logo=npm)](https://www.npmjs.com/package/@adocasts.com/dto/v/latest "npm") ![](https://img.shields.io/badge/Typescript-294E80.svg?style=for-the-badge&logo=typescript) [![license-image](https://img.shields.io/github/license/adocasts/package-dto?style=for-the-badge)](https://npmcn.com/package/%40adocasts.com/dto/LICENSE.md)

将 Lucid Models 转换为 DTO 文件可能是一个乏味的任务. 这个套装旨在让它少一点 读取您模型的属性定义并将其移植到 DTO. 会是完美的吗? 可能不会,但应该可以帮助削减 需要重复完成这项任务.

## 安装

您可以通过 Ace CLI 轻松地安装和配置 `add` 命令.

```shell
node ace add @adocasts.com/dto
```

##### 手动安装配置( C)

如果您愿意,也可以手动安装和配置

```shell
npm install @adocasts.com/dto
```

```shell
node ace configure @adocasts.com/dto
```

##### 定义 DTO 导入路径

生成的 DTO 将使用 `#dtos/*` 用于DTO内部的关系进口. 因此,我们建议在您 `package.json`

```json
"imports": {
  "#dtos/*": "./app/dtos/*.js"
}
```

## 生成 DTOs 命令

想要为您的模型生成 DTO 吗 ? 这是命令!

```shell
node ace generate:dtos
```

这将读取您所有的模型文件, 收集其属性和类型 . 然后把这些地产的种类转换成系列安全类型 及其与DTO表述的关系.

您也可以通过使用 DTO 生成验证符和 DTO `--validator` 旗帜 :

```shell
node ace generate:dtos --validator
```

```
File Tree                       Class
------------------------------------------------
└── app/
    ├── dtos/
    │   ├── account.ts          AccountDto
    │   ├── account_group.ts    AccountGroupDto
    │   ├── account_type.ts     AccountTypeDto
    │   ├── income.ts           IncomeDto
    │   ├── payee.ts            PayeeDto
    │   └── user.ts             UserDto
    └── models/
        ├── account.ts          Account
        ├── account_group.ts    AccountGroup
        ├── account_type.ts     AccountType
        ├── income.ts           Income
        ├── payee.ts            Payee
        └── user.ts             User
```

-   从定义的位置获取您的模型文件列表 `adonisrc.ts` 文件
-   将这些文件读取为纯文本, 拖放为仅属性定义
-   确定属性名称、类型、关系是否以及是否可选修改 `?`
-   将这些模型类型转换成序列化表示(目前转换非常松散)
    -   注意,目前这不包括模型属性上定义的序列化行为(如: `serializeAs`(中文(简体) )
-   从这些转换创建 DTO 属性定义
-   为每个财产编制构造器值设置符
-   收集关系所需进口物品
-   生成 DTO 文件
    -   注意, 如果一个文件已经存在于指定的 DTO 位置, 它将被跳过

## 制作 DTO 命令

要制作一个普通的DTO文件, 还是从一个单一的模型中制作一个单独的DTO? 这是命令!

要制作一个 DTO 命名 `AccountDto` 在一个位于 `dto/account.ts`,我们可以运行如下:

```shell
node ace make:dto account
```

这将检查是否有一个模型命名 `Account`。 。 。 . 如果找到一个模型,它将使用该模型的属性定义生成 `AccountDto`。 。 。 . 否则,它只会产生一个 `AccountDto` 带有空类的文件.

您也可以通过使用 DTO 生成一个验证符 `--validator` 旗帜 :

```shell
node ace make:dto account --validator
```

这将创建一个DTO和一个账户模型的验证器.

```
File Tree                       Class
------------------------------------------------
└── app/
    ├── dtos/
    │   ├── account.ts          AccountDto
    └── models/
        ├── account.ts          Account
```

### 如果没有账户模型呢?

如上所述,一个平地 `AccountDto` 类将在新的 `dto/account.ts` 文档,它看起来像下面.

```ts
export default class AccountDto {}
```

#### 指定不同的模式

如果 DTO 和 Model 名称不匹配, 您可以指定一个特定的模型, 通过 : `--model` 旗帜.

```shell
node ace make:dto account --model=main_account
```

现在,而不是寻找一个模型 命名 `Account` 它会代替 寻找 `MainAccount` 并使用它创建命名为 DTO `AccountDto`。 。 。 .

## 制作校验器命令

想做个模型的验证员吗? 此命令的工作与 `make:dto` 命令 :

```shell
node ace make:validators account
```

这将检查是否有一个模型命名 `Account`。 。 。 . 如果找到一个模型,它将使用该模型的属性定义生成 `accountValidator`。 。 。 . 否则,它只会生成一个带有空子图案的普通验证器文件.

```
File Tree                       Variable
------------------------------------------------
└── app/
    ├── validators/
    │   ├── account.ts          accountValidator
    └── models/
        ├── account.ts          Account
```

#### 指定不同的模式

就像DTO一样,你可以指定一个不同的模型:

```shell
node ace make:validators account --model=main_account
```

## 生成验证器命令

想要为您所有模型生成验证器吗 ? 此命令的作用类似 `generate:dtos`数字 :

```shell
node ace generate:validators
```

这将读取您所有的模型文件, 收集其属性和类型 . 然后把这些财产的种类转换成VineJS验证规则.

```
File Tree                       Variable
------------------------------------------------
└── app/
    ├── validators/
    │   ├── account.ts          accountValidator
    │   ├── account_group.ts    accountGroupValidator
    │   ├── account_type.ts     accountTypeValidator
    │   ├── income.ts           incomeValidator
    │   ├── payee.ts            payeeValidator
    │   └── user.ts             userValidator
    └── models/
        ├── account.ts          Account
        ├── account_group.ts    AccountGroup
        ├── account_type.ts     AccountType
        ├── income.ts           Income
        ├── payee.ts            Payee
        └── user.ts             User
```

## BaseDto 帮助器

在v0.0.4中新添加的,我们现在包括a `BaseDto` 或者说 `BaseModelDto` 考虑我们是否从模型中生成你的DTO. 这两个基地都有一个叫 `fromArray`。通过此程序,您可以在一系列源对象中通过. 然后我们绕过它们 然后把每个都传到一个新的建筑师身上 假设您将把属性 包含在您的 DTO 构造器中.

举个例子

```ts
class Test extends BaseModel {
  @column()
  declare id: number
}

class TestDto extends BaseModelDto {
  declare id: number

  constructor(instance: Test) {
    super()
    this.id = instance.id
  }
}

const tests = await Test.createMany([{ id: 1 }, { id: 2 }, { id: 3 }])

const dtoArray = TestDto.fromArray(tests)
// [TestDto, TestDto, TestDto]
```

此外, `BaseModelDto` 还包括a `fromPaginator` 帮手 这样你就可以通过一个实例 `ModelPaginator` 改为a `SimplePaginatorDto` 我们已经在这个一揽子方案中界定。 您也可以通过一个 URL 范围的开始和结束, 我们会为您生成这些 URL 在转换期间.

举个简单的例子

```ts
class Test extends BaseModel {
  @column()
  declare id: number
}

class TestDto extends BaseModelDto {
  declare id: number

  constructor(instance: Test) {
    super()
    this.id = instance.id
  }
}

const tests = await Test.createMany([{ id: 1 }, { id: 2 }, { id: 3 }])

const paginator = await Test.query().paginate(1, 2)
const paginatorDto = TestDto.fromPaginator(paginator, { start: 1, end: 2 })
/**
 * {
 *    data: TestDto[],
 *    meta: SimplePaginatorDtoMetaContract
 * }
 */

const paginationUrls = paginatorDto.meta.pagesInRange
/**
 * [
 *    {
 *      url: '/?page=1',
 *      page: 1,
 *      isActive: true
 *    },
 *    {
 *      url: '/?page=2',
 *      page: 2,
 *      isActive: false
 *    },
 * ]
 */
```

举例来说,如果您在使用Inertia之类的东西,那么您可以按此输入道具

```ts
import { SimplePaginatorDtoContract } from '@adocasts.com/dto/types'
import DifficultyDto from '#dtos/difficulty'

const props = defineProps<{
  paginated: SimplePaginatorDtoContract<DifficultyDto>
}>()

const rows = props.paginated.data
const info = props.paginated.meta
const urls = props.paginated.meta.pagesInRange
```

## 需要注意的东西

-   目前我们从模型的文件名中假定模型的名字.
-   目前没有更改 DTO 输出目录的设置
-   由于反射的限制,我们把模型读作"平正文字". 我不是TypeScript wiz, 所以,如果你知道更好的方法,我都是耳朵!
    -   既然我们读成简写
        -   目前我们忽略了装饰师和他们的选择

## 示例

所以,我们用账号作为我们的例子 在整个指南, 让我们看看这个账户模型是什么样子!

##### 账户模式

```ts
// app/models/account.ts

import { DateTime } from 'luxon'
import { BaseModel, belongsTo, column, computed, hasMany, hasOne } from '@adonisjs/lucid/orm'
import User from './user.js'
import type { BelongsTo, HasMany, HasOne } from '@adonisjs/lucid/types/relations'
import AccountType from '#models/account_type'
import Payee from '#models/payee'
import Stock from '#models/stock'
import Transaction from '#models/transaction'
import AccountTypeService from '#services/account_type_service'
import { columnCurrency } from '#start/orm/column'
import type { AccountGroupConfig } from '#config/account'

export default class Account extends BaseModel {
  // region Columns

  @column({ isPrimary: true })
  declare id: number

  @column()
  declare userId: number

  @column()
  declare accountTypeId: number

  @column()
  declare name: string

  @column()
  declare note: string

  @column.date()
  declare dateOpened: DateTime | null

  @column.date()
  declare dateClosed: DateTime | null

  @columnCurrency()
  declare balance: number

  @columnCurrency()
  declare startingBalance: number

  @column.dateTime({ autoCreate: true })
  declare createdAt: DateTime

  @column.dateTime({ autoCreate: true, autoUpdate: true })
  declare updatedAt: DateTime

  // endregion

  // region Unmapped Properties

  aggregations: Record<string, number> = {}

  // endregion

  // region Relationships

  @belongsTo(() => User)
  declare user: BelongsTo<typeof User>

  @belongsTo(() => AccountType)
  declare accountType: BelongsTo<typeof AccountType>

  @hasOne(() => Payee)
  declare payee: HasOne<typeof Payee>

  @hasMany(() => Stock)
  declare stocks: HasMany<typeof Stock>

  @hasMany(() => Transaction)
  declare transactions: HasMany<typeof Transaction>

  // endregion

  // region Computed Properties

  @computed()
  get accountGroup(): AccountGroupConfig {
    return AccountTypeService.getAccountTypeGroup(this.accountTypeId)
  }

  @computed()
  get isCreditIncrease(): boolean {
    return AccountTypeService.isCreditIncreaseById(this.accountTypeId)
  }

  @computed()
  get isBudgetable() {
    return AccountTypeService.isBudgetable(this.accountTypeId)
  }

  @computed()
  get balanceDisplay() {
    return '$' + this.balance.toLocaleString('en-US')
  }

  // endregion
}
```

有个

-   列属性
-   无效属性
-   未映射的属性, 包含默认值
-   计数器
-   关系

让我们看看,当我们生成我们的DTO!

```shell
node ace make:dto account
```

##### 账户 DTO

```ts
import { BaseModelDto } from '@adocasts.com/dto/base'
import Account from '#models/account'
import UserDto from '#dtos/user'
import AccountTypeDto from '#dtos/account_type'
import PayeeDto from '#dtos/payee'
import StockDto from '#dtos/stock'
import TransactionDto from '#dtos/transaction'
import { AccountGroupConfig } from '#config/account'

export default class AccountDto extends BaseModelDto {
  declare id: number
  declare userId: number
  declare accountTypeId: number
  declare name: string
  declare note: string
  declare dateOpened: string | null
  declare dateClosed: string | null
  declare balance: number
  declare startingBalance: number
  declare createdAt: string
  declare updatedAt: string
  aggregations: Record<string, number> = {}
  declare user: UserDto | null
  declare accountType: AccountTypeDto | null
  declare payee: PayeeDto | null
  declare stocks: StockDto[]
  declare transactions: TransactionDto[]
  declare accountGroup: AccountGroupConfig
  declare isCreditIncrease: boolean
  declare isBudgetable: boolean
  declare balanceDisplay: string

  constructor(account?: Account) {
    super()

    if (!account) return
    this.id = account.id
    this.userId = account.userId
    this.accountTypeId = account.accountTypeId
    this.name = account.name
    this.note = account.note
    this.dateOpened = account.dateOpened?.toISO()!
    this.dateClosed = account.dateClosed?.toISO()!
    this.balance = account.balance
    this.startingBalance = account.startingBalance
    this.createdAt = account.createdAt.toISO()!
    this.updatedAt = account.updatedAt.toISO()!
    this.aggregations = account.aggregations
    this.user = account.user && new UserDto(account.user)
    this.accountType = account.accountType && new AccountTypeDto(account.accountType)
    this.payee = account.payee && new PayeeDto(account.payee)
    this.stocks = StockDto.fromArray(account.stocks)
    this.transactions = TransactionDto.fromArray(account.transactions)
    this.accountGroup = account.accountGroup
    this.isCreditIncrease = account.isCreditIncrease
    this.isBudgetable = account.isBudgetable
    this.balanceDisplay = account.balanceDisplay
  }
}
```

它拥有

-   需要的进口(它将试图通过参考模型的进口来获取全部的进口)
-   从我们的模型中列属性
-   无效财产无效
-   我们模型中未显示的属性, 加上默认值
-   转换成DTO表示的关系
-   获取器及其类型,当指定。 如果推断类型, 如果变量名称开始, 类型会默认为字符串或布尔 `is`
-   上述所有项目的构造值设置器
-   帮助方法 `fromArray` 如果需要的话, 将常态化为空数组

## 示例验证器

让我们看看当我们生成一个验证器 当我们的账户模型:

```shell
node ace make:validator account
```

##### 账户验证人

```ts
import vine from '@vinejs/vine'
import Account from '#models/account'
import { AccountGroupConfig } from '#config/account'

export const accountValidator = vine.compile(
  vine.object({
    id: vine.number(),
    userId: vine.number(),
    accountTypeId: vine.number(),
    name: vine.string().trim(),
    note: vine.string().trim(),
    dateOpened: vine.string().datetime().optional(),
    dateClosed: vine.string().datetime().optional(),
    balance: vine.number(),
    startingBalance: vine.number(),
    createdAt: vine.string().datetime(),
    updatedAt: vine.string().datetime(),
    user: vine.object({}),
    accountType: vine.object({}),
    payee: vine.object({}),
    stocks: vine.array(vine.object({})),
    transactions: vine.array(vine.object({})),
    accountGroup: vine.object({}),
    isCreditIncrease: vine.boolean(),
    isBudgetable: vine.boolean(),
    balanceDisplay: vine.string().trim()
  })
)
```

其经有:

-   需要从模型进口
-   所有模型属性的验证规则
-   适当的类型转换( 如 DateTime to string (. datetime ()) )
-   无效属性的可选修改符
-   关系对象和数组验证符

## 使用生成验证器

一旦您生成了验证器, 您可以在您的控制器或路由中使用它来验证输入的数据 :

```typescript
import { accountValidator } from '#validators/account'
import { HttpContext } from '@adonisjs/core/http'

export default class AccountsController {
  async store({ request, response }: HttpContext) {
    try {
      // Validate the request data
      const data = await accountValidator.validate(request.all())

      // Create the account
      const account = await Account.create(data)

      // Return the account as a DTO
      return response.created(new AccountDto(account))
    } catch (error) {
      // Handle validation errors
      if (error.code === 'E_VALIDATION_ERROR') {
        return response.unprocessableEntity(error.messages)
      }

      throw error
    }
  }
}
```

## 常见问题

### @adocasts\.com/dto 是什么？

从 Lucid 模型轻松地制作和生成 DTO

### 如何安装 @adocasts\.com/dto？

在项目目录运行 npm install @adocasts\.com/dto，或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖：@adonisjs/core（^6\.2\.0）、@adonisjs/lucid（^21\.1\.0）。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖，Yarn 需要手动安装。

### @adocasts\.com/dto 支持 TypeScript 吗？

该包的 package\.json 没有声明类型入口。需要类型提示时，可以在 npm 上查找社区维护的 @types/adocasts\.com\_\_dto 是否存在。

### @adocasts\.com/dto 支持 ESM 还是 CommonJS？

以 ES Module 形式发布，推荐使用 import 引入。在 CommonJS 项目中，Node\.js 20\.19\+ / 22\.12\+ 可以直接 require\(\) 不含顶层 await 的 ES Module，更早的版本需要改用动态 import\(\)。

### @adocasts\.com/dto 需要什么版本的 Node\.js？

package\.json 的 engines 字段要求 Node\.js \>=20\.6\.0。版本不符时 npm 默认只给出警告，开启 engine-strict 后会拒绝安装。

### @adocasts\.com/dto 可以商用吗？

@adocasts\.com/dto 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @adocasts\.com/dto 的下载量有多少？

根据 npm 官方下载统计，@adocasts\.com/dto 在 2026/10/05 – 2026/11/03 这 30 天内被下载 6,673 次，日均约 222 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @adocasts\.com/dto 还在维护吗？

最新版本 0\.0\.10 发布于 2025/06/23（1\.4 年前）；至今共发布 10 个版本，其中过去 12 个月发布了 0 个；首次发布于 2024/06/10。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

