Repository: nestjs/swagger
Pull request #2647 (2023-10-03 22:45:51)

fix(): Derive enum types correctly when defined as an array #2615
If an enum property is decorated with `isArray: true`, its type should be derived from the type of the enum item, rather than as an `array`.

## PR Checklist
Please check if your PR fulfills the following requirements:

- [x] The commit message follows our guidelines: https://github.com/nestjs/nest/blob/master/CONTRIBUTING.md
- [x] Tests for the changes have been added (for bug fixes / features)
- [ ] Docs have been added / updated (for bug fixes / features)


## PR Type
What kind of change does this PR introduce?

<!-- Please check the one that applies to this PR using "x". -->
- [x] Bugfix
- [ ] Feature
- [ ] Code style update (formatting, local variables)
- [ ] Refactoring (no functional changes, no api changes)
- [ ] Build related changes
- [ ] CI related changes
- [ ] Other... Please describe:

## What is the current behavior?
<!-- Please describe the current behavior that you are modifying, or link to a relevant issue. -->

Issue Number: https://github.com/nestjs/swagger/issues/2615


## What is the new behavior?
Enum schemas should now use the type of enum itself, regardless of whether it was declared as an array or not.

## Does this PR introduce a breaking change?
- [ ] Yes
- [x] No

<!-- If this PR contains a breaking change, please describe the impact and migration path for existing applications below. -->


## Other information



Patch:
diff --git a/lib/services/schema-object-factory.ts b/lib/services/schema-object-factory.ts
index 7120a5de..a9ef89cd 100644
--- a/lib/services/schema-object-factory.ts
+++ b/lib/services/schema-object-factory.ts
@@ -300,8 +300,14 @@ export class SchemaObjectFactory {
     const $ref = getSchemaPath(enumName);
 
     if (!(enumName in schemas)) {
+      const enumType: string = (
+        metadata.isArray
+        ? metadata.items['type']
+        : metadata.type
+      ) ?? 'string';
+
       schemas[enumName] = {
-        type: metadata.type as string ?? 'string',
+        type: enumType,
         enum:
           metadata.isArray && metadata.items
             ? metadata.items['enum']


Test patch:
diff --git a/test/services/schema-object-factory.spec.ts b/test/services/schema-object-factory.spec.ts
index 0e6f8138..f8126359 100644
--- a/test/services/schema-object-factory.spec.ts
+++ b/test/services/schema-object-factory.spec.ts
@@ -32,6 +32,12 @@ describe('SchemaObjectFactory', () => {
       Neighboard = 'neighboard'
     }
 
+    enum Ranking {
+      First = 1,
+      Second = 2,
+      Third = 3
+    }
+
     class CreatePersonDto {
       @ApiProperty()
       name: string;
@@ -42,21 +48,36 @@ describe('SchemaObjectFactory', () => {
     class Person {
       @ApiProperty({ enum: Role, enumName: 'Role' })
       role: Role;
+
       @ApiProperty({ enum: Role, enumName: 'Role', isArray: true })
       roles: Role[];
+
+      @ApiProperty({ enum: Group, enumName: 'Group', isArray: true })
+      groups: Group[];
+
+      @ApiProperty({ enum: Ranking, enumName: 'Ranking', isArray: true })
+      rankings: Ranking[];
     }
 
     it('should explore enum', () => {
       const schemas: Record<string, SchemasObject> = {};
       schemaObjectFactory.exploreModelSchema(Person, schemas);
 
-      expect(Object.keys(schemas)).toHaveLength(2);
+      expect(Object.keys(schemas)).toHaveLength(4);
 
       expect(schemas).toHaveProperty('Role');
       expect(schemas.Role).toEqual({
         type: 'string',
         enum: ['admin', 'user']
       });
+      expect(schemas.Group).toEqual({
+        type: 'string',
+        enum: ['user', 'guest', 'family', 'neighboard']
+      });
+      expect(schemas.Ranking).toEqual({
+        type: 'number',
+        enum: [1, 2, 3]
+      });
       expect(schemas).toHaveProperty('Person');
       expect(schemas.Person).toEqual({
         type: 'object',
@@ -69,14 +90,25 @@ describe('SchemaObjectFactory', () => {
             items: {
               $ref: '#/components/schemas/Role'
             }
+          },
+          groups: {
+            type: 'array',
+            items: {
+              $ref: '#/components/schemas/Group'
+            }
+          },
+          rankings: {
+            type: 'array',
+            items: {
+              $ref: '#/components/schemas/Ranking'
+            }
           }
         },
-        required: ['role', 'roles']
+        required: ['role', 'roles', 'groups', 'rankings']
       });
-
       schemaObjectFactory.exploreModelSchema(CreatePersonDto, schemas);
 
-      expect(Object.keys(schemas)).toHaveLength(3);
+      expect(Object.keys(schemas)).toHaveLength(5);
       expect(schemas).toHaveProperty('CreatePersonDto');
       expect(schemas.CreatePersonDto).toEqual({
         type: 'object',
@@ -276,9 +308,9 @@ describe('SchemaObjectFactory', () => {
         isArray: false
       };
       const schemas = {};
-      
+
       schemaObjectFactory.createEnumSchemaType('field', metadata, schemas);
-      
+
       expect(schemas).toEqual({ MyEnum: { enum: [1, 2, 3], type: 'number' } });
     });
   });