如何在TypeScript中为含索引签名的类添加Swagger ApiProperty装饰器?
问题:为动态键的类添加Swagger装饰器报错
我有一个用作响应类型的类,该类可包含任意表示conversationId的键,对应值为该对话的最后一条Message。基础类代码如下:
import { Message } from "./message.dto"; export class LastConversationMessages{ [conversationId: string]: Message; }
尝试用ApiProperty装饰该类时无法生效,代码如下:
import { Message } from "./message.dto"; import {ApiProperty} from "@nestjs/swagger"; export class LastConversationMessages{ @ApiProperty({ additionalProperties: { type: Message } }) [conversationId: string]: Message; }
运行时报错:Decorators are not valid here,请问该如何解决?
解决方案
在NestJS Swagger体系中,@ApiProperty装饰器仅支持类的具体属性,无法直接作用于索引签名。要描述这种动态键值对结构,需要通过@ApiExtraModels结合响应装饰器的schema配置来实现,具体步骤如下:
- 确保
Message类被Swagger识别
如果Message类还未添加Swagger装饰,先给它加上@ApiExtraModels(若已添加可跳过):
import { ApiExtraModels, ApiProperty } from '@nestjs/swagger'; @ApiExtraModels(Message) export class Message { @ApiProperty() id: string; @ApiProperty() content: string; // 其他Message字段及装饰器 }
- 在控制器响应中定义动态结构
直接在控制器的响应装饰器里配置schema,无需给LastConversationMessages添加无效装饰:
import { Controller, Get } from '@nestjs/common'; import { ApiOkResponse, getSchemaPath } from '@nestjs/swagger'; import { Message } from './message.dto'; @Controller('conversations') export class ConversationsController { @Get('last-messages') @ApiOkResponse({ schema: { type: 'object', additionalProperties: { $ref: getSchemaPath(Message), }, description: '键为conversationId,值为对应对话的最后一条消息' }, }) getLastConversationMessages(): Record<string, Message> { // 业务逻辑实现 return {}; } }
- 保留类类型的替代方案
如果需要保留LastConversationMessages作为类型标记,可给类添加@ApiExtraModels,再在响应中引用:
import { ApiExtraModels } from '@nestjs/swagger'; import { Message } from './message.dto'; @ApiExtraModels(LastConversationMessages) export class LastConversationMessages { [conversationId: string]: Message; }
控制器中配置响应:
@ApiOkResponse({ schema: { $ref: getSchemaPath(LastConversationMessages), type: 'object', additionalProperties: { $ref: getSchemaPath(Message), }, }, })
核心逻辑是通过Swagger schema的additionalProperties字段,明确描述动态键值对的类型规则,替代直接装饰索引签名的无效操作。
内容的提问来源于stack exchange,提问作者michal pavlik
相关产品推荐
相关产品推荐

