Repository: lukeautry/tsoa (ts)

Issue:
Empty string among union values causes union to be resolved as 'any' instead of 'string'
Unions `type YesNo = "Yes" | "No" | ""` will have swagger generated with type object, as typeResolver produces 'any' data type.

## Sorting

* **I'm submitting a ...**
  - [x] bug report
  - [ ] feature request
  - [ ] support request

* I confirm that I
  - [x] used the [search](https://github.com/lukeautry/tsoa/search?type=Issues) to make sure that a similar issue hasn't already been submit

## Expected Behavior
Generates a swagger type enum and all its values

## Current Behavior
Generates a swagger type object

## Possible Solution
<!--- Not obligatory, but suggest a fix/reason for the bug, -->

## Steps to Reproduce
Generate swagger for `type YesNo = "Yes" | "No" | ""`

## Context (Environment)
Version of the library: 2.5.7
Version of NodeJS: 8
* Confirm you were using yarn not npm: [ ]

## Breaking change?
Potentially, as people may rely on empty strings to not produce correct swagger enum. Having empty strings in enums is very rare though.

Pull request:
Allowing enums with an empty string literal to be correctly generated in swagger
### All Submissions:

* [x] Have you followed the guidelines in our [Contributing](https://github.com/lukeautry/tsoa/tree/master/docs/CONTRIBUTING.md) document?
* [x] Have you checked to ensure there aren't other open [Pull Requests](https://github.com/lukeautry/tsoa/pulls) for the same update/change?
* [x] Have you written unit tests?
* [ ] Have you written unit tests that cover the negative cases (i.e.: if bad data is submitted, does the library respond properly)?
* [x] This PR is associated with an existing issue?

**Closing issues**
closes #522 


Patch:
diff --git a/src/metadataGeneration/typeResolver.ts b/src/metadataGeneration/typeResolver.ts
index 3e9f331f..c0cbae1f 100644
--- a/src/metadataGeneration/typeResolver.ts
+++ b/src/metadataGeneration/typeResolver.ts
@@ -394,7 +394,7 @@ export class TypeResolver {
     }
 
     const unionTypes = (literalTypes[0] as any).type.types as any[];
-    if (unionTypes.some(t => !t.literal || !t.literal.text)) {
+    if (unionTypes.some(t => !t.literal || t.literal.text === null || t.literal.text === undefined)) {
       // tagged union types can't be expressed in Swagger terms, probably
       return { dataType: 'any' };
     }


Test patch:
diff --git a/tests/fixtures/testModel.ts b/tests/fixtures/testModel.ts
index a2e8493c..8fbde3ac 100644
--- a/tests/fixtures/testModel.ts
+++ b/tests/fixtures/testModel.ts
@@ -148,7 +148,7 @@ export enum EnumStringValue {
 
 // shortened from StringLiteral to make the tslint enforced
 // alphabetical sorting cleaner
-export type StrLiteral = 'Foo' | 'Bar';
+export type StrLiteral = '' | 'Foo' | 'Bar';
 
 export interface TestSubModelContainer {
   [key: string]: TestSubModel2;
diff --git a/tests/unit/swagger/definitionsGeneration/definitions.spec.ts b/tests/unit/swagger/definitionsGeneration/definitions.spec.ts
index fe02effd..2e933c39 100644
--- a/tests/unit/swagger/definitionsGeneration/definitions.spec.ts
+++ b/tests/unit/swagger/definitionsGeneration/definitions.spec.ts
@@ -325,7 +325,8 @@ describe('Definition generation', () => {
             if (!propertySchema.enum) {
               throw new Error(`There was no 'enum' property on ${propertyName}.`);
             }
-            expect(propertySchema.enum).to.have.length(2, `for property ${propertyName}.enum`);
+            expect(propertySchema.enum).to.have.length(3, `for property ${propertyName}.enum`);
+            expect(propertySchema.enum).to.include('', `for property ${propertyName}.enum`);
             expect(propertySchema.enum).to.include('Foo', `for property ${propertyName}.enum`);
             expect(propertySchema.enum).to.include('Bar', `for property ${propertyName}.enum`);
           },
@@ -341,7 +342,8 @@ describe('Definition generation', () => {
             if (!propertySchema.items.enum) {
               throw new Error(`There was no 'enum' property on ${propertyName}.items`);
             }
-            expect(propertySchema.items.enum).to.have.length(2, `for property ${propertyName}.items.enum`);
+            expect(propertySchema.items.enum).to.have.length(3, `for property ${propertyName}.items.enum`);
+            expect(propertySchema.items.enum).to.include('', `for property ${propertyName}.items.enum`);
             expect(propertySchema.items.enum).to.include('Foo', `for property ${propertyName}.items.enum`);
             expect(propertySchema.items.enum).to.include('Bar', `for property ${propertyName}.items.enum`);
           },
diff --git a/tests/unit/swagger/schemaDetails3.spec.ts b/tests/unit/swagger/schemaDetails3.spec.ts
index 45836a8d..6663de33 100644
--- a/tests/unit/swagger/schemaDetails3.spec.ts
+++ b/tests/unit/swagger/schemaDetails3.spec.ts
@@ -395,7 +395,8 @@ describe('Definition generation for OpenAPI 3.0.0', () => {
             if (!propertySchema.enum) {
               throw new Error(`There was no 'enum' property on ${propertyName}.`);
             }
-            expect(propertySchema.enum).to.have.length(2, `for property ${propertyName}.enum`);
+            expect(propertySchema.enum).to.have.length(3, `for property ${propertyName}.enum`);
+            expect(propertySchema.enum).to.include('', `for property ${propertyName}.enum`);
             expect(propertySchema.enum).to.include('Foo', `for property ${propertyName}.enum`);
             expect(propertySchema.enum).to.include('Bar', `for property ${propertyName}.enum`);
           },
@@ -411,7 +412,8 @@ describe('Definition generation for OpenAPI 3.0.0', () => {
             if (!propertySchema.items.enum) {
               throw new Error(`There was no 'enum' property on ${propertyName}.items`);
             }
-            expect(propertySchema.items.enum).to.have.length(2, `for property ${propertyName}.items.enum`);
+            expect(propertySchema.items.enum).to.have.length(3, `for property ${propertyName}.items.enum`);
+            expect(propertySchema.items.enum).to.include('', `for property ${propertyName}.items.enum`);
             expect(propertySchema.items.enum).to.include('Foo', `for property ${propertyName}.items.enum`);
             expect(propertySchema.items.enum).to.include('Bar', `for property ${propertyName}.items.enum`);
           },