Skip to content

Commit

Permalink
feat: support conditionals in mapped types (#1510)
Browse files Browse the repository at this point in the history
Co-authored-by: Dominik Moritz <domoritz@gmail.com>
fixes #1502
  • Loading branch information
flugg authored Dec 21, 2022
1 parent 888f691 commit c5e8393
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 6 deletions.
12 changes: 6 additions & 6 deletions src/NodeParser/MappedTypeNodeParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -79,23 +78,24 @@ 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;
}

protected getProperties(node: ts.MappedTypeNode, keyListType: UnionType, context: Context): ObjectProperty[] {
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)
Expand All @@ -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
);
Expand Down
1 change: 1 addition & 0 deletions test/valid-data-type.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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"));
Expand Down
9 changes: 9 additions & 0 deletions test/valid-data/type-mapped-index-as-with-conditional/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
interface Message {
id: number;
name: string;
title: string;
}

export type MyObject = {
[K in keyof Message as Exclude<K, "title">]: Message[K];
};
22 changes: 22 additions & 0 deletions test/valid-data/type-mapped-index-as-with-conditional/schema.json
Original file line number Diff line number Diff line change
@@ -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"
}
}
}

0 comments on commit c5e8393

Please sign in to comment.