From c5e839314069598f65d00bba57c14b33ae0c431f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20T=C3=B8mmer=C3=A5s?= Date: Wed, 21 Dec 2022 16:07:36 +0100 Subject: [PATCH] feat: support conditionals in mapped types (#1510) Co-authored-by: Dominik Moritz fixes https://github.com/vega/ts-json-schema-generator/issues/1502 --- src/NodeParser/MappedTypeNodeParser.ts | 12 +++++----- test/valid-data-type.test.ts | 1 + .../main.ts | 9 ++++++++ .../schema.json | 22 +++++++++++++++++++ 4 files changed, 38 insertions(+), 6 deletions(-) create mode 100644 test/valid-data/type-mapped-index-as-with-conditional/main.ts create mode 100644 test/valid-data/type-mapped-index-as-with-conditional/schema.json diff --git a/src/NodeParser/MappedTypeNodeParser.ts b/src/NodeParser/MappedTypeNodeParser.ts index ef0331db2..ac9c7862f 100644 --- a/src/NodeParser/MappedTypeNodeParser.ts +++ b/src/NodeParser/MappedTypeNodeParser.ts @@ -13,7 +13,6 @@ import { ObjectProperty, ObjectType } from "../Type/ObjectType"; import { StringType } from "../Type/StringType"; import { SymbolType } from "../Type/SymbolType"; import { UnionType } from "../Type/UnionType"; -import assert from "../Utils/assert"; import { derefAnnotatedType, derefType } from "../Utils/derefType"; import { getKey } from "../Utils/nodeKey"; import { preserveAnnotation } from "../Utils/preserveAnnotation"; @@ -79,14 +78,14 @@ export class MappedTypeNodeParser implements SubNodeParser { } } - protected mapKey(node: ts.MappedTypeNode, rawKey: LiteralType, context: Context): LiteralType { + protected mapKey(node: ts.MappedTypeNode, rawKey: LiteralType, context: Context): BaseType { if (!node.nameType) { return rawKey; } const key = derefType( this.childNodeParser.createType(node.nameType, this.createSubContext(node, rawKey, context)) ); - assert(key instanceof LiteralType, "Must resolve to Literal"); + return key; } @@ -94,8 +93,9 @@ export class MappedTypeNodeParser implements SubNodeParser { return keyListType .getTypes() .filter((type): type is LiteralType => type instanceof LiteralType) - .reduce((result: ObjectProperty[], key: LiteralType) => { - const namedKey = this.mapKey(node, key, context); + .map((type) => [type, this.mapKey(node, type, context)]) + .filter((value): value is [LiteralType, LiteralType] => value[1] instanceof LiteralType) + .reduce((result: ObjectProperty[], [key, mappedKey]: [LiteralType, LiteralType]) => { const propertyType = this.childNodeParser.createType( node.type!, this.createSubContext(node, key, context) @@ -110,7 +110,7 @@ export class MappedTypeNodeParser implements SubNodeParser { } const objectProperty = new ObjectProperty( - namedKey.getValue().toString(), + mappedKey.getValue().toString(), preserveAnnotation(propertyType, newType), !node.questionToken && !hasUndefined ); diff --git a/test/valid-data-type.test.ts b/test/valid-data-type.test.ts index 44c969374..329ea0935 100644 --- a/test/valid-data-type.test.ts +++ b/test/valid-data-type.test.ts @@ -89,6 +89,7 @@ describe("valid-data-type", () => { it("type-mapped-index", assertValidSchema("type-mapped-index", "MyObject")); it("type-mapped-index-as", assertValidSchema("type-mapped-index-as", "MyObject")); it("type-mapped-index-as-template", assertValidSchema("type-mapped-index-as-template", "MyObject")); + it("type-mapped-index-as-with-conditional", assertValidSchema("type-mapped-index-as-with-conditional", "MyObject")); it("type-mapped-literal", assertValidSchema("type-mapped-literal", "MyObject")); it("type-mapped-generic", assertValidSchema("type-mapped-generic", "MyObject")); it("type-mapped-native", assertValidSchema("type-mapped-native", "MyObject")); diff --git a/test/valid-data/type-mapped-index-as-with-conditional/main.ts b/test/valid-data/type-mapped-index-as-with-conditional/main.ts new file mode 100644 index 000000000..296978409 --- /dev/null +++ b/test/valid-data/type-mapped-index-as-with-conditional/main.ts @@ -0,0 +1,9 @@ +interface Message { + id: number; + name: string; + title: string; +} + +export type MyObject = { + [K in keyof Message as Exclude]: Message[K]; +}; diff --git a/test/valid-data/type-mapped-index-as-with-conditional/schema.json b/test/valid-data/type-mapped-index-as-with-conditional/schema.json new file mode 100644 index 000000000..2f4d9703c --- /dev/null +++ b/test/valid-data/type-mapped-index-as-with-conditional/schema.json @@ -0,0 +1,22 @@ +{ + "$ref": "#/definitions/MyObject", + "$schema": "http://json-schema.org/draft-07/schema#", + "definitions": { + "MyObject": { + "additionalProperties": false, + "properties": { + "id": { + "type": "number" + }, + "name": { + "type": "string" + } + }, + "required": [ + "id", + "name" + ], + "type": "object" + } + } +}