Repository: pmcelhaney/counterfact
Pull request #190 (2022-09-10 16:21:11)

115 all properties are treated as required
- schema object properties are optional by default
- When encoding JSON schema in TypeScript, mark object properties as optional unless they are required
- add changeset for optional properties



Patch:
diff --git a/.changeset/eighty-dogs-judge.md b/.changeset/eighty-dogs-judge.md
new file mode 100644
index 0000000..a54a7a8
--- /dev/null
+++ b/.changeset/eighty-dogs-judge.md
@@ -0,0 +1,5 @@
+---
+"counterfact": minor
+---
+
+when encoding JSON schema in TypeScript, mark object properties as optional unless they are required
diff --git a/src/typescript-generator/schema-type-coder.js b/src/typescript-generator/schema-type-coder.js
index 3f4c1cf..49df72f 100644
--- a/src/typescript-generator/schema-type-coder.js
+++ b/src/typescript-generator/schema-type-coder.js
@@ -31,7 +31,13 @@ export class SchemaTypeCoder extends Coder {
     const properties = Object.keys(data.properties ?? {}).map((name) => {
       const property = this.requirement.select(`properties/${name}`);
 
-      return `${name}: ${new SchemaTypeCoder(property).write(script)}`;
+      const isRequired =
+        data.required?.includes(name) || property.data.required;
+      const optionalFlag = isRequired ? "" : "?";
+
+      return `${name}${optionalFlag}: ${new SchemaTypeCoder(property).write(
+        script
+      )}`;
     });
 
     if (data.additionalProperties) {


Test patch:
diff --git a/test/typescript-generator/__snapshots__/end-to-end.test.js.snap b/test/typescript-generator/__snapshots__/end-to-end.test.js.snap
index 1b3d1a1..707bfd9 100644
--- a/test/typescript-generator/__snapshots__/end-to-end.test.js.snap
+++ b/test/typescript-generator/__snapshots__/end-to-end.test.js.snap
@@ -177,7 +177,7 @@ Map {
                 },
                 "exports": Map {
                   "Pet" => Object {
-                    "code": "{id: number,name: string,category: Category,photoUrls: Array<string>,tags: Array<Tag>,status: string}",
+                    "code": "{id?: number,name: string,category?: Category,photoUrls: Array<string>,tags?: Array<Tag>,status?: string}",
                     "done": true,
                     "id": "SchemaTypeCoder@undefined",
                     "isType": true,
@@ -197,7 +197,7 @@ Map {
                       },
                       "exports": Map {
                         "Category" => Object {
-                          "code": "{id: number,name: string}",
+                          "code": "{id?: number,name?: string}",
                           "done": true,
                           "id": "SchemaTypeCoder@undefined",
                           "isType": true,
@@ -225,7 +225,7 @@ Map {
                       },
                       "exports": Map {
                         "Tag" => Object {
-                          "code": "{id: number,name: string}",
+                          "code": "{id?: number,name?: string}",
                           "done": true,
                           "id": "SchemaTypeCoder@undefined",
                           "isType": true,
@@ -442,7 +442,7 @@ Map {
                 },
                 "exports": Map {
                   "Pet" => Object {
-                    "code": "{id: number,name: string,category: Category,photoUrls: Array<string>,tags: Array<Tag>,status: string}",
+                    "code": "{id?: number,name: string,category?: Category,photoUrls: Array<string>,tags?: Array<Tag>,status?: string}",
                     "done": true,
                     "id": "SchemaTypeCoder@undefined",
                     "isType": true,
@@ -462,7 +462,7 @@ Map {
                       },
                       "exports": Map {
                         "Category" => Object {
-                          "code": "{id: number,name: string}",
+                          "code": "{id?: number,name?: string}",
                           "done": true,
                           "id": "SchemaTypeCoder@undefined",
                           "isType": true,
@@ -490,7 +490,7 @@ Map {
                       },
                       "exports": Map {
                         "Tag" => Object {
-                          "code": "{id: number,name: string}",
+                          "code": "{id?: number,name?: string}",
                           "done": true,
                           "id": "SchemaTypeCoder@undefined",
                           "isType": true,
@@ -712,7 +712,7 @@ Map {
           },
           "exports": Map {
             "Pet" => Object {
-              "code": "{id: number,name: string,category: Category,photoUrls: Array<string>,tags: Array<Tag>,status: string}",
+              "code": "{id?: number,name: string,category?: Category,photoUrls: Array<string>,tags?: Array<Tag>,status?: string}",
               "done": true,
               "id": "SchemaTypeCoder@undefined",
               "isType": true,
@@ -732,7 +732,7 @@ Map {
                 },
                 "exports": Map {
                   "Category" => Object {
-                    "code": "{id: number,name: string}",
+                    "code": "{id?: number,name?: string}",
                     "done": true,
                     "id": "SchemaTypeCoder@undefined",
                     "isType": true,
@@ -760,7 +760,7 @@ Map {
                 },
                 "exports": Map {
                   "Tag" => Object {
-                    "code": "{id: number,name: string}",
+                    "code": "{id?: number,name?: string}",
                     "done": true,
                     "id": "SchemaTypeCoder@undefined",
                     "isType": true,
@@ -933,7 +933,7 @@ Map {
                 },
                 "exports": Map {
                   "Pet" => Object {
-                    "code": "{id: number,name: string,category: Category,photoUrls: Array<string>,tags: Array<Tag>,status: string}",
+                    "code": "{id?: number,name: string,category?: Category,photoUrls: Array<string>,tags?: Array<Tag>,status?: string}",
                     "done": true,
                     "id": "SchemaTypeCoder@undefined",
                     "isType": true,
@@ -953,7 +953,7 @@ Map {
                       },
                       "exports": Map {
                         "Category" => Object {
-                          "code": "{id: number,name: string}",
+                          "code": "{id?: number,name?: string}",
                           "done": true,
                           "id": "SchemaTypeCoder@undefined",
                           "isType": true,
@@ -981,7 +981,7 @@ Map {
                       },
                       "exports": Map {
                         "Tag" => Object {
-                          "code": "{id: number,name: string}",
+                          "code": "{id?: number,name?: string}",
                           "done": true,
                           "id": "SchemaTypeCoder@undefined",
                           "isType": true,
@@ -1140,7 +1140,7 @@ Map {
           },
           "exports": Map {
             "Pet" => Object {
-              "code": "{id: number,name: string,category: Category,photoUrls: Array<string>,tags: Array<Tag>,status: string}",
+              "code": "{id?: number,name: string,category?: Category,photoUrls: Array<string>,tags?: Array<Tag>,status?: string}",
               "done": true,
               "id": "SchemaTypeCoder@undefined",
               "isType": true,
@@ -1160,7 +1160,7 @@ Map {
                 },
                 "exports": Map {
                   "Category" => Object {
-                    "code": "{id: number,name: string}",
+                    "code": "{id?: number,name?: string}",
                     "done": true,
                     "id": "SchemaTypeCoder@undefined",
                     "isType": true,
@@ -1188,7 +1188,7 @@ Map {
                 },
                 "exports": Map {
                   "Tag" => Object {
-                    "code": "{id: number,name: string}",
+                    "code": "{id?: number,name?: string}",
                     "done": true,
                     "id": "SchemaTypeCoder@undefined",
                     "isType": true,
@@ -1361,7 +1361,7 @@ Map {
                 },
                 "exports": Map {
                   "Pet" => Object {
-                    "code": "{id: number,name: string,category: Category,photoUrls: Array<string>,tags: Array<Tag>,status: string}",
+                    "code": "{id?: number,name: string,category?: Category,photoUrls: Array<string>,tags?: Array<Tag>,status?: string}",
                     "done": true,
                     "id": "SchemaTypeCoder@undefined",
                     "isType": true,
@@ -1381,7 +1381,7 @@ Map {
                       },
                       "exports": Map {
                         "Category" => Object {
-                          "code": "{id: number,name: string}",
+                          "code": "{id?: number,name?: string}",
                           "done": true,
                           "id": "SchemaTypeCoder@undefined",
                           "isType": true,
@@ -1409,7 +1409,7 @@ Map {
                       },
                       "exports": Map {
                         "Tag" => Object {
-                          "code": "{id: number,name: string}",
+                          "code": "{id?: number,name?: string}",
                           "done": true,
                           "id": "SchemaTypeCoder@undefined",
                           "isType": true,
@@ -1568,7 +1568,7 @@ Map {
           },
           "exports": Map {
             "Pet" => Object {
-              "code": "{id: number,name: string,category: Category,photoUrls: Array<string>,tags: Array<Tag>,status: string}",
+              "code": "{id?: number,name: string,category?: Category,photoUrls: Array<string>,tags?: Array<Tag>,status?: string}",
               "done": true,
               "id": "SchemaTypeCoder@undefined",
               "isType": true,
@@ -1588,7 +1588,7 @@ Map {
                 },
                 "exports": Map {
                   "Category" => Object {
-                    "code": "{id: number,name: string}",
+                    "code": "{id?: number,name?: string}",
                     "done": true,
                     "id": "SchemaTypeCoder@undefined",
                     "isType": true,
@@ -1616,7 +1616,7 @@ Map {
                 },
                 "exports": Map {
                   "Tag" => Object {
-                    "code": "{id: number,name: string}",
+                    "code": "{id?: number,name?: string}",
                     "done": true,
                     "id": "SchemaTypeCoder@undefined",
                     "isType": true,
@@ -1867,7 +1867,7 @@ Map {
                 },
                 "exports": Map {
                   "Pet" => Object {
-                    "code": "{id: number,name: string,category: Category,photoUrls: Array<string>,tags: Array<Tag>,status: string}",
+                    "code": "{id?: number,name: string,category?: Category,photoUrls: Array<string>,tags?: Array<Tag>,status?: string}",
                     "done": true,
                     "id": "SchemaTypeCoder@undefined",
                     "isType": true,
@@ -1887,7 +1887,7 @@ Map {
                       },
                       "exports": Map {
                         "Category" => Object {
-                          "code": "{id: number,name: string}",
+                          "code": "{id?: number,name?: string}",
                           "done": true,
                           "id": "SchemaTypeCoder@undefined",
                           "isType": true,
@@ -1915,7 +1915,7 @@ Map {
                       },
                       "exports": Map {
                         "Tag" => Object {
-                          "code": "{id: number,name: string}",
+                          "code": "{id?: number,name?: string}",
                           "done": true,
                           "id": "SchemaTypeCoder@undefined",
                           "isType": true,
@@ -2125,7 +2125,7 @@ Map {
                 },
                 "exports": Map {
                   "Pet" => Object {
-                    "code": "{id: number,name: string,category: Category,photoUrls: Array<string>,tags: Array<Tag>,status: string}",
+                    "code": "{id?: number,name: string,category?: Category,photoUrls: Array<string>,tags?: Array<Tag>,status?: string}",
                     "done": true,
                     "id": "SchemaTypeCoder@undefined",
                     "isType": true,
@@ -2145,7 +2145,7 @@ Map {
                       },
                       "exports": Map {
                         "Category" => Object {
-                          "code": "{id: number,name: string}",
+                          "code": "{id?: number,name?: string}",
                           "done": true,
                           "id": "SchemaTypeCoder@undefined",
                           "isType": true,
@@ -2173,7 +2173,7 @@ Map {
                       },
                       "exports": Map {
                         "Tag" => Object {
-                          "code": "{id: number,name: string}",
+                          "code": "{id?: number,name?: string}",
                           "done": true,
                           "id": "SchemaTypeCoder@undefined",
                           "isType": true,
@@ -2383,7 +2383,7 @@ Map {
                 },
                 "exports": Map {
                   "Pet" => Object {
-                    "code": "{id: number,name: string,category: Category,photoUrls: Array<string>,tags: Array<Tag>,status: string}",
+                    "code": "{id?: number,name: string,category?: Category,photoUrls: Array<string>,tags?: Array<Tag>,status?: string}",
                     "done": true,
                     "id": "SchemaTypeCoder@undefined",
                     "isType": true,
@@ -2403,7 +2403,7 @@ Map {
                       },
                       "exports": Map {
                         "Category" => Object {
-                          "code": "{id: number,name: string}",
+                          "code": "{id?: number,name?: string}",
                           "done": true,
                           "id": "SchemaTypeCoder@undefined",
                           "isType": true,
@@ -2431,7 +2431,7 @@ Map {
                       },
                       "exports": Map {
                         "Tag" => Object {
-                          "code": "{id: number,name: string}",
+                          "code": "{id?: number,name?: string}",
                           "done": true,
                           "id": "SchemaTypeCoder@undefined",
                           "isType": true,
@@ -2646,7 +2646,7 @@ Map {
           },
           "exports": Map {
             "Pet" => Object {
-              "code": "{id: number,name: string,category: Category,photoUrls: Array<string>,tags: Array<Tag>,status: string}",
+              "code": "{id?: number,name: string,category?: Category,photoUrls: Array<string>,tags?: Array<Tag>,status?: string}",
               "done": true,
               "id": "SchemaTypeCoder@undefined",
               "isType": true,
@@ -2666,7 +2666,7 @@ Map {
                 },
                 "exports": Map {
                   "Category" => Object {
-                    "code": "{id: number,name: string}",
+                    "code": "{id?: number,name?: string}",
                     "done": true,
                     "id": "SchemaTypeCoder@undefined",
                     "isType": true,
@@ -2694,7 +2694,7 @@ Map {
                 },
                 "exports": Map {
                   "Tag" => Object {
-                    "code": "{id: number,name: string}",
+                    "code": "{id?: number,name?: string}",
                     "done": true,
                     "id": "SchemaTypeCoder@undefined",
                     "isType": true,
@@ -2847,7 +2847,7 @@ Map {
                 },
                 "exports": Map {
                   "ApiResponse" => Object {
-                    "code": "{code: number,type: string,message: string}",
+                    "code": "{code?: number,type?: string,message?: string}",
                     "done": true,
                     "id": "SchemaTypeCoder@undefined",
                     "isType": true,
@@ -2977,7 +2977,7 @@ Map {
           },
           "exports": Map {
             "ApiResponse" => Object {
-              "code": "{code: number,type: string,message: string}",
+              "code": "{code?: number,type?: string,message?: string}",
               "done": true,
               "id": "SchemaTypeCoder@undefined",
               "isType": true,
@@ -3347,7 +3347,7 @@ Map {
                 },
                 "exports": Map {
                   "Order" => Object {
-                    "code": "{id: number,petId: number,quantity: number,shipDate: string,status: string,complete: boolean}",
+                    "code": "{id?: number,petId?: number,quantity?: number,shipDate?: string,status?: string,complete?: boolean}",
                     "done": true,
                     "id": "SchemaTypeCoder@undefined",
                     "isType": true,
@@ -3487,7 +3487,7 @@ Map {
           },
           "exports": Map {
             "Order" => Object {
-              "code": "{id: number,petId: number,quantity: number,shipDate: string,status: string,complete: boolean}",
+              "code": "{id?: number,petId?: number,quantity?: number,shipDate?: string,status?: string,complete?: boolean}",
               "done": true,
               "id": "SchemaTypeCoder@undefined",
               "isType": true,
@@ -3703,7 +3703,7 @@ Map {
                 },
                 "exports": Map {
                   "Order" => Object {
-                    "code": "{id: number,petId: number,quantity: number,shipDate: string,status: string,complete: boolean}",
+                    "code": "{id?: number,petId?: number,quantity?: number,shipDate?: string,status?: string,complete?: boolean}",
                     "done": true,
                     "id": "SchemaTypeCoder@undefined",
                     "isType": true,
@@ -3889,7 +3889,7 @@ Map {
                 },
                 "exports": Map {
                   "Order" => Object {
-                    "code": "{id: number,petId: number,quantity: number,shipDate: string,status: string,complete: boolean}",
+                    "code": "{id?: number,petId?: number,quantity?: number,shipDate?: string,status?: string,complete?: boolean}",
                     "done": true,
                     "id": "SchemaTypeCoder@undefined",
                     "isType": true,
@@ -4080,7 +4080,7 @@ Map {
           },
           "exports": Map {
             "Order" => Object {
-              "code": "{id: number,petId: number,quantity: number,shipDate: string,status: string,complete: boolean}",
+              "code": "{id?: number,petId?: number,quantity?: number,shipDate?: string,status?: string,complete?: boolean}",
               "done": true,
               "id": "SchemaTypeCoder@undefined",
               "isType": true,
@@ -4232,7 +4232,7 @@ Map {
                 },
                 "exports": Map {
                   "User" => Object {
-                    "code": "{id: number,username: string,firstName: string,lastName: string,email: string,password: string,phone: string,userStatus: number}",
+                    "code": "{id?: number,username?: string,firstName?: string,lastName?: string,email?: string,password?: string,phone?: string,userStatus?: number}",
                     "done": true,
                     "id": "SchemaTypeCoder@undefined",
                     "isType": true,
@@ -4370,7 +4370,7 @@ Map {
           },
           "exports": Map {
             "User" => Object {
-              "code": "{id: number,username: string,firstName: string,lastName: string,email: string,password: string,phone: string,userStatus: number}",
+              "code": "{id?: number,username?: string,firstName?: string,lastName?: string,email?: string,password?: string,phone?: string,userStatus?: number}",
               "done": true,
               "id": "SchemaTypeCoder@undefined",
               "isType": true,
@@ -4532,7 +4532,7 @@ Map {
                 },
                 "exports": Map {
                   "User" => Object {
-                    "code": "{id: number,username: string,firstName: string,lastName: string,email: string,password: string,phone: string,userStatus: number}",
+                    "code": "{id?: number,username?: string,firstName?: string,lastName?: string,email?: string,password?: string,phone?: string,userStatus?: number}",
                     "done": true,
                     "id": "SchemaTypeCoder@undefined",
                     "isType": true,
@@ -4680,7 +4680,7 @@ Map {
           },
           "exports": Map {
             "User" => Object {
-              "code": "{id: number,username: string,firstName: string,lastName: string,email: string,password: string,phone: string,userStatus: number}",
+              "code": "{id?: number,username?: string,firstName?: string,lastName?: string,email?: string,password?: string,phone?: string,userStatus?: number}",
               "done": true,
               "id": "SchemaTypeCoder@undefined",
               "isType": true,
@@ -5392,7 +5392,7 @@ Map {
                 },
                 "exports": Map {
                   "User" => Object {
-                    "code": "{id: number,username: string,firstName: string,lastName: string,email: string,password: string,phone: string,userStatus: number}",
+                    "code": "{id?: number,username?: string,firstName?: string,lastName?: string,email?: string,password?: string,phone?: string,userStatus?: number}",
                     "done": true,
                     "id": "SchemaTypeCoder@undefined",
                     "isType": true,
@@ -5601,7 +5601,7 @@ Map {
                 },
                 "exports": Map {
                   "User" => Object {
-                    "code": "{id: number,username: string,firstName: string,lastName: string,email: string,password: string,phone: string,userStatus: number}",
+                    "code": "{id?: number,username?: string,firstName?: string,lastName?: string,email?: string,password?: string,phone?: string,userStatus?: number}",
                     "done": true,
                     "id": "SchemaTypeCoder@undefined",
                     "isType": true,
@@ -5810,7 +5810,7 @@ Map {
                 },
                 "exports": Map {
                   "User" => Object {
-                    "code": "{id: number,username: string,firstName: string,lastName: string,email: string,password: string,phone: string,userStatus: number}",
+                    "code": "{id?: number,username?: string,firstName?: string,lastName?: string,email?: string,password?: string,phone?: string,userStatus?: number}",
                     "done": true,
                     "id": "SchemaTypeCoder@undefined",
                     "isType": true,
@@ -6024,7 +6024,7 @@ Map {
           },
           "exports": Map {
             "User" => Object {
-              "code": "{id: number,username: string,firstName: string,lastName: string,email: string,password: string,phone: string,userStatus: number}",
+              "code": "{id?: number,username?: string,firstName?: string,lastName?: string,email?: string,password?: string,phone?: string,userStatus?: number}",
               "done": true,
               "id": "SchemaTypeCoder@undefined",
               "isType": true,
@@ -6097,7 +6097,7 @@ Map {
     },
     "exports": Map {
       "Pet" => Object {
-        "code": "{id: number,name: string,category: Category,photoUrls: Array<string>,tags: Array<Tag>,status: string}",
+        "code": "{id?: number,name: string,category?: Category,photoUrls: Array<string>,tags?: Array<Tag>,status?: string}",
         "done": true,
         "id": "SchemaTypeCoder@undefined",
         "isType": true,
@@ -6117,7 +6117,7 @@ Map {
           },
           "exports": Map {
             "Category" => Object {
-              "code": "{id: number,name: string}",
+              "code": "{id?: number,name?: string}",
               "done": true,
               "id": "SchemaTypeCoder@undefined",
               "isType": true,
@@ -6145,7 +6145,7 @@ Map {
           },
           "exports": Map {
             "Tag" => Object {
-              "code": "{id: number,name: string}",
+              "code": "{id?: number,name?: string}",
               "done": true,
               "id": "SchemaTypeCoder@undefined",
               "isType": true,
@@ -6212,7 +6212,7 @@ Map {
     },
     "exports": Map {
       "ApiResponse" => Object {
-        "code": "{code: number,type: string,message: string}",
+        "code": "{code?: number,type?: string,message?: string}",
         "done": true,
         "id": "SchemaTypeCoder@undefined",
         "isType": true,
@@ -6236,7 +6236,7 @@ Map {
     },
     "exports": Map {
       "Order" => Object {
-        "code": "{id: number,petId: number,quantity: number,shipDate: string,status: string,complete: boolean}",
+        "code": "{id?: number,petId?: number,quantity?: number,shipDate?: string,status?: string,complete?: boolean}",
         "done": true,
         "id": "SchemaTypeCoder@undefined",
         "isType": true,
@@ -6260,7 +6260,7 @@ Map {
     },
     "exports": Map {
       "User" => Object {
-        "code": "{id: number,username: string,firstName: string,lastName: string,email: string,password: string,phone: string,userStatus: number}",
+        "code": "{id?: number,username?: string,firstName?: string,lastName?: string,email?: string,password?: string,phone?: string,userStatus?: number}",
         "done": true,
         "id": "SchemaTypeCoder@undefined",
         "isType": true,
@@ -6284,7 +6284,7 @@ Map {
     },
     "exports": Map {
       "Category" => Object {
-        "code": "{id: number,name: string}",
+        "code": "{id?: number,name?: string}",
         "done": true,
         "id": "SchemaTypeCoder@undefined",
         "isType": true,
@@ -6308,7 +6308,7 @@ Map {
     },
     "exports": Map {
       "Tag" => Object {
-        "code": "{id: number,name: string}",
+        "code": "{id?: number,name?: string}",
         "done": true,
         "id": "SchemaTypeCoder@undefined",
         "isType": true,
diff --git a/test/typescript-generator/schema-type-coder.test.js b/test/typescript-generator/schema-type-coder.test.js
index a3e05ea..4ef42e1 100644
--- a/test/typescript-generator/schema-type-coder.test.js
+++ b/test/typescript-generator/schema-type-coder.test.js
@@ -69,9 +69,9 @@ describe("a SchemaTypeCoder", () => {
       })
     );
 
-    const expected = format("const x = { name: string, age: number };");
+    const expected = format("type x = { name?: string, age?: number };");
 
-    expect(format(`const x = ${coder.write()}`)).toStrictEqual(expected);
+    expect(format(`type x = ${coder.write()}`)).toStrictEqual(expected);
   });
 
   it("generates a type declaration for an object with additionalProperties", () => {
@@ -91,7 +91,29 @@ describe("a SchemaTypeCoder", () => {
     );
 
     const expected = format(
-      "type x = { name: string, age: number, [key: string]: unknown };"
+      "type x = { name?: string, age?: number, [key: string]: unknown };"
+    );
+
+    expect(format(`type x = ${coder.write()}`)).toStrictEqual(expected);
+  });
+
+  it("generates a type declaration for an object with required properties", () => {
+    const coder = new SchemaTypeCoder(
+      new Requirement({
+        type: "object",
+
+        properties: {
+          optionalString: { type: "string" },
+          requiredString: { type: "string", required: true },
+          anotherRequiredString: { type: "string" },
+        },
+
+        required: ["anotherRequiredString"],
+      })
+    );
+
+    const expected = format(
+      "type x = { optionalString?: string, requiredString: string, anotherRequiredString: string };"
     );
 
     expect(format(`type x = ${coder.write()}`)).toStrictEqual(expected);
@@ -112,7 +134,7 @@ describe("a SchemaTypeCoder", () => {
     );
 
     const expected = format(
-      "type x = { name: string, age: number, [key: string]: unknown };"
+      "type x = { name?: string, age?: number, [key: string]: unknown };"
     );
 
     expect(format(`type x = ${coder.write()}`)).toStrictEqual(expected);
@@ -132,7 +154,7 @@ describe("a SchemaTypeCoder", () => {
       })
     );
 
-    const expected = format("type x = { name: string, age: number };");
+    const expected = format("type x = { name?: string, age?: number };");
 
     expect(format(`type x = ${coder.write()}`)).toStrictEqual(expected);
   });
@@ -142,18 +164,11 @@ describe("a SchemaTypeCoder", () => {
       new Requirement({
         type: "object",
 
-        properties: {
-          name: { type: "string" },
-          nickname: { type: "string" },
-        },
-
-        additionalProperties: { type: "string" },
+        additionalProperties: { type: "boolean" },
       })
     );
 
-    const expected = format(
-      "type x = { name: string, nickname: string, [key: string]: string };"
-    );
+    const expected = format("type x = {  [key: string]: boolean };");
 
     expect(format(`type x = ${coder.write()}`)).toStrictEqual(expected);
   });
@@ -162,11 +177,19 @@ describe("a SchemaTypeCoder", () => {
     const coder = new SchemaTypeCoder(
       new Requirement({
         type: "object",
-        additionalProperties: { type: "string" },
+
+        properties: {
+          aNumber: { type: "number" },
+          anotherNumber: { type: "number" },
+        },
+
+        additionalProperties: { type: "number" },
       })
     );
 
-    const expected = format("type x = { [key: string]: string };");
+    const expected = format(
+      "type x = { aNumber?: number; anotherNumber?: number; [key: string]: number };"
+    );
 
     expect(format(`type x = ${coder.write()}`)).toStrictEqual(expected);
   });