From 8646f5e698a6be9c540e124dd7926cd8b1307a0c Mon Sep 17 00:00:00 2001 From: Juan Cruz Viotti Date: Mon, 12 Jan 2026 15:37:36 -0400 Subject: [PATCH] Fix `additionalProperties` handling Signed-off-by: Juan Cruz Viotti --- src/generator/typescript.cc | 40 ++---- src/ir/include/sourcemeta/codegen/ir.h | 2 +- src/ir/ir_default_compiler.h | 15 ++- .../additional_properties_false/expected.d.ts | 10 ++ .../additional_properties_false/options.json | 3 + .../additional_properties_false/schema.json | 14 ++ .../additional_properties_false/test.ts | 73 ++++++++++ .../additional_properties_true/expected.d.ts | 34 +++++ .../additional_properties_true/options.json | 3 + .../additional_properties_true/schema.json | 14 ++ .../additional_properties_true/test.ts | 69 ++++++++++ .../2020-12/all_type_values/expected.d.ts | 34 +---- .../2020-12/anchor_refs/expected.d.ts | 23 +--- .../complex_nested_object/expected.d.ts | 118 +++-------------- .../2020-12/const_keyword/expected.d.ts | 23 +--- .../2020-12/deeply_nested_refs/expected.d.ts | 125 ++++-------------- .../2020-12/defs_and_refs/expected.d.ts | 84 +++--------- .../2020-12/embedded_resources/expected.d.ts | 16 +-- .../2020-12/enum_complex_types/expected.d.ts | 11 +- .../expected.d.ts | 120 ++++------------- .../expected.d.ts | 14 +- .../object_with_additional_properties/test.ts | 27 +++- .../2020-12/tuples_and_arrays/expected.d.ts | 72 ++-------- .../2020-12/vocabulary_ignored/expected.d.ts | 10 +- test/generator/generator_typescript_test.cc | 74 +++++------ test/ir/ir_2020_12_test.cc | 16 +-- 26 files changed, 439 insertions(+), 605 deletions(-) create mode 100644 test/e2e/typescript/2020-12/additional_properties_false/expected.d.ts create mode 100644 test/e2e/typescript/2020-12/additional_properties_false/options.json create mode 100644 test/e2e/typescript/2020-12/additional_properties_false/schema.json create mode 100644 test/e2e/typescript/2020-12/additional_properties_false/test.ts create mode 100644 test/e2e/typescript/2020-12/additional_properties_true/expected.d.ts create mode 100644 test/e2e/typescript/2020-12/additional_properties_true/options.json create mode 100644 test/e2e/typescript/2020-12/additional_properties_true/schema.json create mode 100644 test/e2e/typescript/2020-12/additional_properties_true/test.ts diff --git a/src/generator/typescript.cc b/src/generator/typescript.cc index 22e24ff..8d4a492 100644 --- a/src/generator/typescript.cc +++ b/src/generator/typescript.cc @@ -91,11 +91,7 @@ auto TypeScript::operator()(const IRObject &entry) const -> void { return; } - if (has_additional) { - this->output << "export type " << type_name << " = {\n"; - } else { - this->output << "export interface " << type_name << " {\n"; - } + this->output << "export interface " << type_name << " {\n"; // We always quote property names for safety. JSON Schema allows any string // as a property name, but unquoted TypeScript/ECMAScript property names @@ -115,32 +111,24 @@ auto TypeScript::operator()(const IRObject &entry) const -> void { } if (has_additional) { - this->output << "} & {\n"; - - // While we could do this with the more idiomatic `Record, Y>`, we choose the more verbose manner in order to allow users to - // declare a type called `Record` - this->output << " [K in string as K extends\n"; - - std::size_t index{0}; + // TypeScript index signatures must be a supertype of all property value + // types. We use a union of all member types plus the additional properties + // type plus undefined (for optional properties). + this->output << " [key: string]:\n"; for (const auto &[member_name, member_value] : entry.members) { - const auto is_last{index == entry.members.size() - 1}; - this->output << " \"" << escape_string(member_name) << "\""; - if (!is_last) { - this->output << " |"; - } - this->output << "\n"; - ++index; + this->output << " " + << sourcemeta::core::mangle(member_value.pointer, + this->prefix) + << " |\n"; } - - this->output << " ? never : K]: " + this->output << " " << sourcemeta::core::mangle(entry.additional->pointer, this->prefix) - << ";\n"; - this->output << "};\n"; - } else { - this->output << "}\n"; + << " |\n"; + this->output << " undefined;\n"; } + + this->output << "}\n"; } auto TypeScript::operator()(const IRImpossible &entry) const -> void { diff --git a/src/ir/include/sourcemeta/codegen/ir.h b/src/ir/include/sourcemeta/codegen/ir.h index 8b5c614..4af466b 100644 --- a/src/ir/include/sourcemeta/codegen/ir.h +++ b/src/ir/include/sourcemeta/codegen/ir.h @@ -64,7 +64,7 @@ struct IRObjectValue : IRType { struct IRObject : IRType { // To preserve the user's ordering std::vector> members; - std::optional additional; + std::optional additional; }; /// @ingroup ir diff --git a/src/ir/ir_default_compiler.h b/src/ir/ir_default_compiler.h index f1c20fe..11f3c54 100644 --- a/src/ir/ir_default_compiler.h +++ b/src/ir/ir_default_compiler.h @@ -96,13 +96,16 @@ auto handle_object(const sourcemeta::core::JSON &schema, members.emplace_back(entry.first, std::move(member_value)); } - std::optional additional{std::nullopt}; + std::optional additional{std::nullopt}; if (subschema.defines("additionalProperties")) { - auto additional_pointer{sourcemeta::core::to_pointer(location.pointer)}; - additional_pointer.push_back("additionalProperties"); - - additional = - IRObjectValue{{.pointer = std::move(additional_pointer)}, false, false}; + const auto &additional_schema{subschema.at("additionalProperties")}; + const auto is_false{additional_schema.is_boolean() && + !additional_schema.to_boolean()}; + if (!is_false) { + auto additional_pointer{sourcemeta::core::to_pointer(location.pointer)}; + additional_pointer.push_back("additionalProperties"); + additional = IRType{.pointer = std::move(additional_pointer)}; + } } return IRObject{{.pointer = sourcemeta::core::to_pointer(location.pointer)}, diff --git a/test/e2e/typescript/2020-12/additional_properties_false/expected.d.ts b/test/e2e/typescript/2020-12/additional_properties_false/expected.d.ts new file mode 100644 index 0000000..ac96d30 --- /dev/null +++ b/test/e2e/typescript/2020-12/additional_properties_false/expected.d.ts @@ -0,0 +1,10 @@ +export type StrictPerson_Properties_Name = string; + +export type StrictPerson_Properties_Age = number; + +export type StrictPerson_AdditionalProperties = never; + +export interface StrictPerson { + "name": StrictPerson_Properties_Name; + "age"?: StrictPerson_Properties_Age; +} diff --git a/test/e2e/typescript/2020-12/additional_properties_false/options.json b/test/e2e/typescript/2020-12/additional_properties_false/options.json new file mode 100644 index 0000000..9fb0fdb --- /dev/null +++ b/test/e2e/typescript/2020-12/additional_properties_false/options.json @@ -0,0 +1,3 @@ +{ + "defaultPrefix": "StrictPerson" +} diff --git a/test/e2e/typescript/2020-12/additional_properties_false/schema.json b/test/e2e/typescript/2020-12/additional_properties_false/schema.json new file mode 100644 index 0000000..d1feac2 --- /dev/null +++ b/test/e2e/typescript/2020-12/additional_properties_false/schema.json @@ -0,0 +1,14 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "age": { + "type": "integer" + } + }, + "required": [ "name" ], + "additionalProperties": false +} diff --git a/test/e2e/typescript/2020-12/additional_properties_false/test.ts b/test/e2e/typescript/2020-12/additional_properties_false/test.ts new file mode 100644 index 0000000..94d036c --- /dev/null +++ b/test/e2e/typescript/2020-12/additional_properties_false/test.ts @@ -0,0 +1,73 @@ +import { StrictPerson } from "./expected"; + +// Valid: required name only +const person1: StrictPerson = { + name: "John Doe" +}; + +// Valid: name and optional age +const person2: StrictPerson = { + name: "Jane Doe", + age: 25 +}; + +// Invalid: name must be string +const person3: StrictPerson = { + // @ts-expect-error + name: 123 +}; + +// Invalid: age must be number +const person4: StrictPerson = { + name: "John", + // @ts-expect-error + age: "twenty" +}; + +// Invalid: missing required name +// @ts-expect-error +const person5: StrictPerson = { + age: 30 +}; + +// Invalid: extra string property should be rejected +const person6: StrictPerson = { + name: "John", + // @ts-expect-error + nickname: "Johnny" +}; + +// Invalid: extra number property should be rejected +const person7: StrictPerson = { + name: "John", + // @ts-expect-error + score: 100 +}; + +// Invalid: extra boolean property should be rejected +const person8: StrictPerson = { + name: "John", + // @ts-expect-error + active: true +}; + +// Invalid: extra null property should be rejected +const person9: StrictPerson = { + name: "John", + // @ts-expect-error + nothing: null +}; + +// Invalid: extra array property should be rejected +const person10: StrictPerson = { + name: "John", + // @ts-expect-error + tags: [ "a", "b" ] +}; + +// Invalid: extra object property should be rejected +const person11: StrictPerson = { + name: "John", + // @ts-expect-error + metadata: { foo: "bar" } +}; diff --git a/test/e2e/typescript/2020-12/additional_properties_true/expected.d.ts b/test/e2e/typescript/2020-12/additional_properties_true/expected.d.ts new file mode 100644 index 0000000..8f311fa --- /dev/null +++ b/test/e2e/typescript/2020-12/additional_properties_true/expected.d.ts @@ -0,0 +1,34 @@ +export type FlexibleRecord_Properties_Name = string; + +export type FlexibleRecord_Properties_Count = number; + +export type FlexibleRecord_AdditionalProperties_AnyOf_ZIndex5 = number; + +export type FlexibleRecord_AdditionalProperties_AnyOf_ZIndex4 = string; + +export type FlexibleRecord_AdditionalProperties_AnyOf_ZIndex3 = unknown[]; + +export interface FlexibleRecord_AdditionalProperties_AnyOf_ZIndex2 { +} + +export type FlexibleRecord_AdditionalProperties_AnyOf_ZIndex1 = boolean; + +export type FlexibleRecord_AdditionalProperties_AnyOf_ZIndex0 = null; + +export type FlexibleRecord_AdditionalProperties = + FlexibleRecord_AdditionalProperties_AnyOf_ZIndex0 | + FlexibleRecord_AdditionalProperties_AnyOf_ZIndex1 | + FlexibleRecord_AdditionalProperties_AnyOf_ZIndex2 | + FlexibleRecord_AdditionalProperties_AnyOf_ZIndex3 | + FlexibleRecord_AdditionalProperties_AnyOf_ZIndex4 | + FlexibleRecord_AdditionalProperties_AnyOf_ZIndex5; + +export interface FlexibleRecord { + "name": FlexibleRecord_Properties_Name; + "count"?: FlexibleRecord_Properties_Count; + [key: string]: + FlexibleRecord_Properties_Name | + FlexibleRecord_Properties_Count | + FlexibleRecord_AdditionalProperties | + undefined; +} diff --git a/test/e2e/typescript/2020-12/additional_properties_true/options.json b/test/e2e/typescript/2020-12/additional_properties_true/options.json new file mode 100644 index 0000000..f554b3a --- /dev/null +++ b/test/e2e/typescript/2020-12/additional_properties_true/options.json @@ -0,0 +1,3 @@ +{ + "defaultPrefix": "FlexibleRecord" +} diff --git a/test/e2e/typescript/2020-12/additional_properties_true/schema.json b/test/e2e/typescript/2020-12/additional_properties_true/schema.json new file mode 100644 index 0000000..a6fd625 --- /dev/null +++ b/test/e2e/typescript/2020-12/additional_properties_true/schema.json @@ -0,0 +1,14 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "count": { + "type": "integer" + } + }, + "required": [ "name" ], + "additionalProperties": true +} diff --git a/test/e2e/typescript/2020-12/additional_properties_true/test.ts b/test/e2e/typescript/2020-12/additional_properties_true/test.ts new file mode 100644 index 0000000..5fceec4 --- /dev/null +++ b/test/e2e/typescript/2020-12/additional_properties_true/test.ts @@ -0,0 +1,69 @@ +import { FlexibleRecord } from "./expected"; + +// Valid: required name only +const record1: FlexibleRecord = { + name: "test" +}; + +// Valid: name and optional count +const record2: FlexibleRecord = { + name: "test", + count: 42 +}; + +// Valid: with string additional property +const record3: FlexibleRecord = { + name: "test", + extra: "some string" +}; + +// Valid: with number additional property +const record4: FlexibleRecord = { + name: "test", + extra: 123 +}; + +// Valid: with boolean additional property +const record5: FlexibleRecord = { + name: "test", + flag: true +}; + +// Valid: with null additional property +const record6: FlexibleRecord = { + name: "test", + nothing: null +}; + +// Valid: with array additional property +const record7: FlexibleRecord = { + name: "test", + items: [ 1, 2, 3 ] +}; + +// Valid: with object additional property +const record8: FlexibleRecord = { + name: "test", + nested: { foo: "bar" } +}; + +// Valid: multiple additional properties of different types +const record9: FlexibleRecord = { + name: "test", + count: 10, + label: "my label", + active: false, + data: [ "a", "b" ] +}; + +// Invalid: name must be string +const record10: FlexibleRecord = { + // @ts-expect-error + name: 123 +}; + +// Invalid: missing required name +// @ts-expect-error +const record11: FlexibleRecord = { + count: 5 +}; diff --git a/test/e2e/typescript/2020-12/all_type_values/expected.d.ts b/test/e2e/typescript/2020-12/all_type_values/expected.d.ts index 9d813e0..ab8a809 100644 --- a/test/e2e/typescript/2020-12/all_type_values/expected.d.ts +++ b/test/e2e/typescript/2020-12/all_type_values/expected.d.ts @@ -4,13 +4,9 @@ export type AllTypes_Properties_ObjectField_Properties_Nested = string; export type AllTypes_Properties_ObjectField_AdditionalProperties = never; -export type AllTypes_Properties_ObjectField = { +export interface AllTypes_Properties_ObjectField { "nested"?: AllTypes_Properties_ObjectField_Properties_Nested; -} & { - [K in string as K extends - "nested" - ? never : K]: AllTypes_Properties_ObjectField_AdditionalProperties; -}; +} export type AllTypes_Properties_NumberField = number; @@ -24,17 +20,11 @@ export type AllTypes_Properties_NestedTypes_Properties_DeepBoolean = boolean; export type AllTypes_Properties_NestedTypes_AdditionalProperties = never; -export type AllTypes_Properties_NestedTypes = { +export interface AllTypes_Properties_NestedTypes { "deepBoolean"?: AllTypes_Properties_NestedTypes_Properties_DeepBoolean; "deepNull"?: AllTypes_Properties_NestedTypes_Properties_DeepNull; "deepInteger"?: AllTypes_Properties_NestedTypes_Properties_DeepInteger; -} & { - [K in string as K extends - "deepBoolean" | - "deepNull" | - "deepInteger" - ? never : K]: AllTypes_Properties_NestedTypes_AdditionalProperties; -}; +} export type AllTypes_Properties_MultiType_AnyOf_ZIndex2 = null; @@ -57,7 +47,7 @@ export type AllTypes_Properties_ArrayField = AllTypes_Properties_ArrayField_Item export type AllTypes_AdditionalProperties = never; -export type AllTypes = { +export interface AllTypes { "stringField": AllTypes_Properties_StringField; "numberField": AllTypes_Properties_NumberField; "integerField": AllTypes_Properties_IntegerField; @@ -67,16 +57,4 @@ export type AllTypes = { "objectField": AllTypes_Properties_ObjectField; "multiType"?: AllTypes_Properties_MultiType; "nestedTypes"?: AllTypes_Properties_NestedTypes; -} & { - [K in string as K extends - "stringField" | - "numberField" | - "integerField" | - "booleanField" | - "nullField" | - "arrayField" | - "objectField" | - "multiType" | - "nestedTypes" - ? never : K]: AllTypes_AdditionalProperties; -}; +} diff --git a/test/e2e/typescript/2020-12/anchor_refs/expected.d.ts b/test/e2e/typescript/2020-12/anchor_refs/expected.d.ts index 4e13b77..bdf041e 100644 --- a/test/e2e/typescript/2020-12/anchor_refs/expected.d.ts +++ b/test/e2e/typescript/2020-12/anchor_refs/expected.d.ts @@ -16,28 +16,15 @@ export type ColorScheme_X24Defs_UColor_Properties_Alpha = number; export type ColorScheme_X24Defs_UColor_AdditionalProperties = never; -export type ColorScheme_X24Defs_UColor = { +export interface ColorScheme_X24Defs_UColor { "r": ColorScheme_X24Defs_UColor_Properties_R; "g": ColorScheme_X24Defs_UColor_Properties_G; "b": ColorScheme_X24Defs_UColor_Properties_B; "alpha"?: ColorScheme_X24Defs_UColor_Properties_Alpha; -} & { - [K in string as K extends - "r" | - "g" | - "b" | - "alpha" - ? never : K]: ColorScheme_X24Defs_UColor_AdditionalProperties; -}; - -export type ColorScheme = { +} + +export interface ColorScheme { "primary": ColorScheme_Properties_Primary; "secondary": ColorScheme_Properties_Secondary; "background"?: ColorScheme_Properties_Background; -} & { - [K in string as K extends - "primary" | - "secondary" | - "background" - ? never : K]: ColorScheme_AdditionalProperties; -}; +} diff --git a/test/e2e/typescript/2020-12/complex_nested_object/expected.d.ts b/test/e2e/typescript/2020-12/complex_nested_object/expected.d.ts index 67e1f5f..b99aedc 100644 --- a/test/e2e/typescript/2020-12/complex_nested_object/expected.d.ts +++ b/test/e2e/typescript/2020-12/complex_nested_object/expected.d.ts @@ -14,15 +14,10 @@ export type Record_Properties_Meta_Properties_Origin = string; export type Record_Properties_Meta_AdditionalProperties = never; -export type Record_Properties_Meta = { +export interface Record_Properties_Meta { "origin"?: Record_Properties_Meta_Properties_Origin; "originId"?: Record_Properties_Meta_Properties_OriginId; -} & { - [K in string as K extends - "origin" | - "originId" - ? never : K]: Record_Properties_Meta_AdditionalProperties; -}; +} export type Record_Properties_LocationInfo_Properties_StateCode = string; @@ -30,15 +25,10 @@ export type Record_Properties_LocationInfo_Properties_AreaCode = string; export type Record_Properties_LocationInfo_AdditionalProperties = never; -export type Record_Properties_LocationInfo = { +export interface Record_Properties_LocationInfo { "stateCode"?: Record_Properties_LocationInfo_Properties_StateCode; "areaCode"?: Record_Properties_LocationInfo_Properties_AreaCode; -} & { - [K in string as K extends - "stateCode" | - "areaCode" - ? never : K]: Record_Properties_LocationInfo_AdditionalProperties; -}; +} export type Record_Properties_Items_Items_Properties_SubCategory = string; @@ -80,15 +70,10 @@ export type Record_Properties_Items_Items_Properties_Meta_Properties_Origin = st export type Record_Properties_Items_Items_Properties_Meta_AdditionalProperties = never; -export type Record_Properties_Items_Items_Properties_Meta = { +export interface Record_Properties_Items_Items_Properties_Meta { "origin"?: Record_Properties_Items_Items_Properties_Meta_Properties_Origin; "originId"?: Record_Properties_Items_Items_Properties_Meta_Properties_OriginId; -} & { - [K in string as K extends - "origin" | - "originId" - ? never : K]: Record_Properties_Items_Items_Properties_Meta_AdditionalProperties; -}; +} export type Record_Properties_Items_Items_Properties_ItemId = string; @@ -106,7 +91,7 @@ export type Record_Properties_Items_Items_Properties_Category = string; export type Record_Properties_Items_Items_AdditionalProperties = never; -export type Record_Properties_Items_Items = { +export interface Record_Properties_Items_Items { "itemId": Record_Properties_Items_Items_Properties_ItemId; "sequenceNumber": Record_Properties_Items_Items_Properties_SequenceNumber; "description": Record_Properties_Items_Items_Properties_Description; @@ -120,23 +105,7 @@ export type Record_Properties_Items_Items = { "category"?: Record_Properties_Items_Items_Properties_Category; "subCategory"?: Record_Properties_Items_Items_Properties_SubCategory; "meta"?: Record_Properties_Items_Items_Properties_Meta; -} & { - [K in string as K extends - "itemId" | - "sequenceNumber" | - "description" | - "code" | - "occurredAt" | - "severity" | - "resolution" | - "resolvedAt" | - "outcome" | - "remarks" | - "category" | - "subCategory" | - "meta" - ? never : K]: Record_Properties_Items_Items_AdditionalProperties; -}; +} export type Record_Properties_Items = Record_Properties_Items_Items[]; @@ -154,21 +123,13 @@ export type Record_Properties_Entity_Properties_BirthDate = Record_X24Defs_UTime export type Record_Properties_Entity_AdditionalProperties = never; -export type Record_Properties_Entity = { +export interface Record_Properties_Entity { "fullName": Record_Properties_Entity_Properties_FullName; "birthDate": Record_Properties_Entity_Properties_BirthDate; "category"?: Record_Properties_Entity_Properties_Category; "classification"?: Record_Properties_Entity_Properties_Classification; "locations": Record_Properties_Entity_Properties_Locations; -} & { - [K in string as K extends - "fullName" | - "birthDate" | - "category" | - "classification" | - "locations" - ? never : K]: Record_Properties_Entity_AdditionalProperties; -}; +} export type Record_Properties_CreatedAt = Record_X24Defs_UTimestamp; @@ -186,21 +147,13 @@ export type Record_X24Defs_UTimestamp_Properties_Day = number; export type Record_X24Defs_UTimestamp_AdditionalProperties = never; -export type Record_X24Defs_UTimestamp = { +export interface Record_X24Defs_UTimestamp { "rawValue": Record_X24Defs_UTimestamp_Properties_RawValue; "year": Record_X24Defs_UTimestamp_Properties_Year; "month": Record_X24Defs_UTimestamp_Properties_Month; "day": Record_X24Defs_UTimestamp_Properties_Day; "isoFormat"?: Record_X24Defs_UTimestamp_Properties_IsoFormat; -} & { - [K in string as K extends - "rawValue" | - "year" | - "month" | - "day" | - "isoFormat" - ? never : K]: Record_X24Defs_UTimestamp_AdditionalProperties; -}; +} export type Record_X24Defs_ULocation_Properties_Region = string; @@ -226,7 +179,7 @@ export type Record_X24Defs_ULocation_Properties_City = string; export type Record_X24Defs_ULocation_AdditionalProperties = never; -export type Record_X24Defs_ULocation = { +export interface Record_X24Defs_ULocation { "rawValue": Record_X24Defs_ULocation_Properties_RawValue; "line1": Record_X24Defs_ULocation_Properties_Line1; "line2"?: Record_X24Defs_ULocation_Properties_Line2; @@ -235,18 +188,7 @@ export type Record_X24Defs_ULocation = { "region": Record_X24Defs_ULocation_Properties_Region; "postalCode": Record_X24Defs_ULocation_Properties_PostalCode; "country": Record_X24Defs_ULocation_Properties_Country; -} & { - [K in string as K extends - "rawValue" | - "line1" | - "line2" | - "city" | - "district" | - "region" | - "postalCode" | - "country" - ? never : K]: Record_X24Defs_ULocation_AdditionalProperties; -}; +} export type Record_X24Defs_UFullName_Properties_Suffix_AnyOf_ZIndex1 = null; @@ -280,25 +222,16 @@ export type Record_X24Defs_UFullName_Properties_FamilyName = string; export type Record_X24Defs_UFullName_AdditionalProperties = never; -export type Record_X24Defs_UFullName = { +export interface Record_X24Defs_UFullName { "rawValue"?: Record_X24Defs_UFullName_Properties_RawValue; "givenName": Record_X24Defs_UFullName_Properties_GivenName; "middleName"?: Record_X24Defs_UFullName_Properties_MiddleName; "familyName": Record_X24Defs_UFullName_Properties_FamilyName; "suffix"?: Record_X24Defs_UFullName_Properties_Suffix; "prefix"?: Record_X24Defs_UFullName_Properties_Prefix; -} & { - [K in string as K extends - "rawValue" | - "givenName" | - "middleName" | - "familyName" | - "suffix" | - "prefix" - ? never : K]: Record_X24Defs_UFullName_AdditionalProperties; -}; - -export type Record = { +} + +export interface Record { "recordId": Record_Properties_RecordId; "referenceCode"?: Record_Properties_ReferenceCode; "organizationName": Record_Properties_OrganizationName; @@ -309,17 +242,4 @@ export type Record = { "notes"?: Record_Properties_Notes; "items": Record_Properties_Items; "meta"?: Record_Properties_Meta; -} & { - [K in string as K extends - "recordId" | - "referenceCode" | - "organizationName" | - "createdAt" | - "region" | - "locationInfo" | - "entity" | - "notes" | - "items" | - "meta" - ? never : K]: Record_AdditionalProperties; -}; +} diff --git a/test/e2e/typescript/2020-12/const_keyword/expected.d.ts b/test/e2e/typescript/2020-12/const_keyword/expected.d.ts index 6f609b3..64ec0db 100644 --- a/test/e2e/typescript/2020-12/const_keyword/expected.d.ts +++ b/test/e2e/typescript/2020-12/const_keyword/expected.d.ts @@ -10,15 +10,10 @@ export type ConstTest_Properties_Nested_Properties_FixedNumber = 100; export type ConstTest_Properties_Nested_AdditionalProperties = never; -export type ConstTest_Properties_Nested = { +export interface ConstTest_Properties_Nested { "fixedValue"?: ConstTest_Properties_Nested_Properties_FixedValue; "fixedNumber"?: ConstTest_Properties_Nested_Properties_FixedNumber; -} & { - [K in string as K extends - "fixedValue" | - "fixedNumber" - ? never : K]: ConstTest_Properties_Nested_AdditionalProperties; -}; +} export type ConstTest_Properties_Mode = "production"; @@ -28,7 +23,7 @@ export type ConstTest_Properties_Count = 42; export type ConstTest_AdditionalProperties = never; -export type ConstTest = { +export interface ConstTest { "version": ConstTest_Properties_Version; "enabled": ConstTest_Properties_Enabled; "mode": ConstTest_Properties_Mode; @@ -36,14 +31,4 @@ export type ConstTest = { "nothing": ConstTest_Properties_Nothing; "optionalFlag"?: ConstTest_Properties_OptionalFlag; "nested"?: ConstTest_Properties_Nested; -} & { - [K in string as K extends - "version" | - "enabled" | - "mode" | - "count" | - "nothing" | - "optionalFlag" | - "nested" - ? never : K]: ConstTest_AdditionalProperties; -}; +} diff --git a/test/e2e/typescript/2020-12/deeply_nested_refs/expected.d.ts b/test/e2e/typescript/2020-12/deeply_nested_refs/expected.d.ts index 7b471ef..bff636f 100644 --- a/test/e2e/typescript/2020-12/deeply_nested_refs/expected.d.ts +++ b/test/e2e/typescript/2020-12/deeply_nested_refs/expected.d.ts @@ -34,35 +34,22 @@ export type ApiResponse_X24Defs_UResponseMeta_Properties_DeprecationWarnings_Ite export type ApiResponse_X24Defs_UResponseMeta_Properties_DeprecationWarnings_Items_AdditionalProperties = never; -export type ApiResponse_X24Defs_UResponseMeta_Properties_DeprecationWarnings_Items = { +export interface ApiResponse_X24Defs_UResponseMeta_Properties_DeprecationWarnings_Items { "message": ApiResponse_X24Defs_UResponseMeta_Properties_DeprecationWarnings_Items_Properties_Message; "field": ApiResponse_X24Defs_UResponseMeta_Properties_DeprecationWarnings_Items_Properties_Field; "suggestedAlternative"?: ApiResponse_X24Defs_UResponseMeta_Properties_DeprecationWarnings_Items_Properties_SuggestedAlternative; -} & { - [K in string as K extends - "message" | - "field" | - "suggestedAlternative" - ? never : K]: ApiResponse_X24Defs_UResponseMeta_Properties_DeprecationWarnings_Items_AdditionalProperties; -}; +} export type ApiResponse_X24Defs_UResponseMeta_Properties_DeprecationWarnings = ApiResponse_X24Defs_UResponseMeta_Properties_DeprecationWarnings_Items[]; export type ApiResponse_X24Defs_UResponseMeta_AdditionalProperties = never; -export type ApiResponse_X24Defs_UResponseMeta = { +export interface ApiResponse_X24Defs_UResponseMeta { "requestId": ApiResponse_X24Defs_UResponseMeta_Properties_RequestId; "timestamp": ApiResponse_X24Defs_UResponseMeta_Properties_Timestamp; "version"?: ApiResponse_X24Defs_UResponseMeta_Properties_Version; "deprecationWarnings"?: ApiResponse_X24Defs_UResponseMeta_Properties_DeprecationWarnings; -} & { - [K in string as K extends - "requestId" | - "timestamp" | - "version" | - "deprecationWarnings" - ? never : K]: ApiResponse_X24Defs_UResponseMeta_AdditionalProperties; -}; +} export type ApiResponse_X24Defs_UPaginationInfo_Properties_TotalPages = number; @@ -78,23 +65,14 @@ export type ApiResponse_X24Defs_UPaginationInfo_Properties_HasNextPage = boolean export type ApiResponse_X24Defs_UPaginationInfo_AdditionalProperties = never; -export type ApiResponse_X24Defs_UPaginationInfo = { +export interface ApiResponse_X24Defs_UPaginationInfo { "page": ApiResponse_X24Defs_UPaginationInfo_Properties_Page; "pageSize": ApiResponse_X24Defs_UPaginationInfo_Properties_PageSize; "totalItems": ApiResponse_X24Defs_UPaginationInfo_Properties_TotalItems; "totalPages": ApiResponse_X24Defs_UPaginationInfo_Properties_TotalPages; "hasNextPage"?: ApiResponse_X24Defs_UPaginationInfo_Properties_HasNextPage; "hasPreviousPage"?: ApiResponse_X24Defs_UPaginationInfo_Properties_HasPreviousPage; -} & { - [K in string as K extends - "page" | - "pageSize" | - "totalItems" | - "totalPages" | - "hasNextPage" | - "hasPreviousPage" - ? never : K]: ApiResponse_X24Defs_UPaginationInfo_AdditionalProperties; -}; +} export type ApiResponse_X24Defs_UPaginatedResult_Properties_Pagination = ApiResponse_X24Defs_UPaginationInfo; @@ -106,17 +84,11 @@ export type ApiResponse_X24Defs_UPaginatedResult_Properties_Filters = ApiRespons export type ApiResponse_X24Defs_UPaginatedResult_AdditionalProperties = never; -export type ApiResponse_X24Defs_UPaginatedResult = { +export interface ApiResponse_X24Defs_UPaginatedResult { "items": ApiResponse_X24Defs_UPaginatedResult_Properties_Items; "pagination": ApiResponse_X24Defs_UPaginatedResult_Properties_Pagination; "filters"?: ApiResponse_X24Defs_UPaginatedResult_Properties_Filters; -} & { - [K in string as K extends - "items" | - "pagination" | - "filters" - ? never : K]: ApiResponse_X24Defs_UPaginatedResult_AdditionalProperties; -}; +} export type ApiResponse_X24Defs_UEntityReference_Properties_Type = string; @@ -124,15 +96,10 @@ export type ApiResponse_X24Defs_UEntityReference_Properties_Id = string; export type ApiResponse_X24Defs_UEntityReference_AdditionalProperties = never; -export type ApiResponse_X24Defs_UEntityReference = { +export interface ApiResponse_X24Defs_UEntityReference { "id": ApiResponse_X24Defs_UEntityReference_Properties_Id; "type": ApiResponse_X24Defs_UEntityReference_Properties_Type; -} & { - [K in string as K extends - "id" | - "type" - ? never : K]: ApiResponse_X24Defs_UEntityReference_AdditionalProperties; -}; +} export type ApiResponse_X24Defs_UEntityAttributes_Properties_X75pdatedAt_AnyOf_ZIndex1 = null; @@ -173,23 +140,14 @@ export type ApiResponse_X24Defs_UEntityAttributes_Properties_CreatedAt = string; export type ApiResponse_X24Defs_UEntityAttributes_AdditionalProperties = never; -export type ApiResponse_X24Defs_UEntityAttributes = { +export interface ApiResponse_X24Defs_UEntityAttributes { "name": ApiResponse_X24Defs_UEntityAttributes_Properties_Name; "description"?: ApiResponse_X24Defs_UEntityAttributes_Properties_Description; "createdAt": ApiResponse_X24Defs_UEntityAttributes_Properties_CreatedAt; "updatedAt"?: ApiResponse_X24Defs_UEntityAttributes_Properties_X75pdatedAt; "tags"?: ApiResponse_X24Defs_UEntityAttributes_Properties_Tags; "metadata"?: ApiResponse_X24Defs_UEntityAttributes_Properties_Metadata; -} & { - [K in string as K extends - "name" | - "description" | - "createdAt" | - "updatedAt" | - "tags" | - "metadata" - ? never : K]: ApiResponse_X24Defs_UEntityAttributes_AdditionalProperties; -}; +} export type ApiResponse_X24Defs_UEntity_Properties_Type = "user" | "organization" | "resource"; @@ -201,15 +159,15 @@ export type ApiResponse_X24Defs_UEntity_Properties_Relationships_Properties_Chil export type ApiResponse_X24Defs_UEntity_Properties_Relationships_AdditionalProperties = ApiResponse_X24Defs_UEntityReference; -export type ApiResponse_X24Defs_UEntity_Properties_Relationships = { +export interface ApiResponse_X24Defs_UEntity_Properties_Relationships { "parent"?: ApiResponse_X24Defs_UEntity_Properties_Relationships_Properties_Parent; "children"?: ApiResponse_X24Defs_UEntity_Properties_Relationships_Properties_Children; -} & { - [K in string as K extends - "parent" | - "children" - ? never : K]: ApiResponse_X24Defs_UEntity_Properties_Relationships_AdditionalProperties; -}; + [key: string]: + ApiResponse_X24Defs_UEntity_Properties_Relationships_Properties_Parent | + ApiResponse_X24Defs_UEntity_Properties_Relationships_Properties_Children | + ApiResponse_X24Defs_UEntity_Properties_Relationships_AdditionalProperties | + undefined; +} export type ApiResponse_X24Defs_UEntity_Properties_Id = string; @@ -217,19 +175,12 @@ export type ApiResponse_X24Defs_UEntity_Properties_Attributes = ApiResponse_X24D export type ApiResponse_X24Defs_UEntity_AdditionalProperties = never; -export type ApiResponse_X24Defs_UEntity = { +export interface ApiResponse_X24Defs_UEntity { "id": ApiResponse_X24Defs_UEntity_Properties_Id; "type": ApiResponse_X24Defs_UEntity_Properties_Type; "attributes": ApiResponse_X24Defs_UEntity_Properties_Attributes; "relationships"?: ApiResponse_X24Defs_UEntity_Properties_Relationships; -} & { - [K in string as K extends - "id" | - "type" | - "attributes" | - "relationships" - ? never : K]: ApiResponse_X24Defs_UEntity_AdditionalProperties; -}; +} export type ApiResponse_X24Defs_UAppliedFilters_Properties_Types_Items = "user" | "organization" | "resource"; @@ -253,44 +204,24 @@ export type ApiResponse_X24Defs_UAppliedFilters_Properties_DateRange_Properties_ export type ApiResponse_X24Defs_UAppliedFilters_Properties_DateRange_AdditionalProperties = never; -export type ApiResponse_X24Defs_UAppliedFilters_Properties_DateRange = { +export interface ApiResponse_X24Defs_UAppliedFilters_Properties_DateRange { "start": ApiResponse_X24Defs_UAppliedFilters_Properties_DateRange_Properties_Start; "end": ApiResponse_X24Defs_UAppliedFilters_Properties_DateRange_Properties_End; -} & { - [K in string as K extends - "start" | - "end" - ? never : K]: ApiResponse_X24Defs_UAppliedFilters_Properties_DateRange_AdditionalProperties; -}; +} export type ApiResponse_X24Defs_UAppliedFilters_AdditionalProperties = never; -export type ApiResponse_X24Defs_UAppliedFilters = { +export interface ApiResponse_X24Defs_UAppliedFilters { "search"?: ApiResponse_X24Defs_UAppliedFilters_Properties_Search; "dateRange"?: ApiResponse_X24Defs_UAppliedFilters_Properties_DateRange; "types"?: ApiResponse_X24Defs_UAppliedFilters_Properties_Types; "sortBy"?: ApiResponse_X24Defs_UAppliedFilters_Properties_SortBy; "sortOrder"?: ApiResponse_X24Defs_UAppliedFilters_Properties_SortOrder; -} & { - [K in string as K extends - "search" | - "dateRange" | - "types" | - "sortBy" | - "sortOrder" - ? never : K]: ApiResponse_X24Defs_UAppliedFilters_AdditionalProperties; -}; - -export type ApiResponse = { +} + +export interface ApiResponse { "status": ApiResponse_Properties_Status; "errorCode"?: ApiResponse_Properties_ErrorCode; "data": ApiResponse_Properties_Data; "meta": ApiResponse_Properties_Meta; -} & { - [K in string as K extends - "status" | - "errorCode" | - "data" | - "meta" - ? never : K]: ApiResponse_AdditionalProperties; -}; +} diff --git a/test/e2e/typescript/2020-12/defs_and_refs/expected.d.ts b/test/e2e/typescript/2020-12/defs_and_refs/expected.d.ts index f045aed..cd3b687 100644 --- a/test/e2e/typescript/2020-12/defs_and_refs/expected.d.ts +++ b/test/e2e/typescript/2020-12/defs_and_refs/expected.d.ts @@ -30,19 +30,12 @@ export type SocialPlatform_X24Defs_X55ser_Properties_Email = SocialPlatform_X24D export type SocialPlatform_X24Defs_X55ser_AdditionalProperties = never; -export type SocialPlatform_X24Defs_X55ser = { +export interface SocialPlatform_X24Defs_X55ser { "id": SocialPlatform_X24Defs_X55ser_Properties_Id; "username": SocialPlatform_X24Defs_X55ser_Properties_X75sername; "email": SocialPlatform_X24Defs_X55ser_Properties_Email; "profile"?: SocialPlatform_X24Defs_X55ser_Properties_Profile; -} & { - [K in string as K extends - "id" | - "username" | - "email" | - "profile" - ? never : K]: SocialPlatform_X24Defs_X55ser_AdditionalProperties; -}; +} export type SocialPlatform_X24Defs_X55X55ID = string; @@ -56,15 +49,10 @@ export type SocialPlatform_X24Defs_UTag_Properties_Name = string; export type SocialPlatform_X24Defs_UTag_AdditionalProperties = never; -export type SocialPlatform_X24Defs_UTag = { +export interface SocialPlatform_X24Defs_UTag { "name": SocialPlatform_X24Defs_UTag_Properties_Name; "slug"?: SocialPlatform_X24Defs_UTag_Properties_Slug; -} & { - [K in string as K extends - "name" | - "slug" - ? never : K]: SocialPlatform_X24Defs_UTag_AdditionalProperties; -}; +} export type SocialPlatform_X24Defs_USettings_Properties_Theme = SocialPlatform_X24Defs_UTheme; @@ -74,17 +62,11 @@ export type SocialPlatform_X24Defs_USettings_Properties_Notifications = SocialPl export type SocialPlatform_X24Defs_USettings_AdditionalProperties = never; -export type SocialPlatform_X24Defs_USettings = { +export interface SocialPlatform_X24Defs_USettings { "theme"?: SocialPlatform_X24Defs_USettings_Properties_Theme; "notifications"?: SocialPlatform_X24Defs_USettings_Properties_Notifications; "privacy"?: SocialPlatform_X24Defs_USettings_Properties_Privacy; -} & { - [K in string as K extends - "theme" | - "notifications" | - "privacy" - ? never : K]: SocialPlatform_X24Defs_USettings_AdditionalProperties; -}; +} export type SocialPlatform_X24Defs_UProfile_Properties_Location_AnyOf_ZIndex1 = null; @@ -106,17 +88,11 @@ export type SocialPlatform_X24Defs_UProfile_Properties_Avatar = SocialPlatform_X export type SocialPlatform_X24Defs_UProfile_AdditionalProperties = never; -export type SocialPlatform_X24Defs_UProfile = { +export interface SocialPlatform_X24Defs_UProfile { "bio"?: SocialPlatform_X24Defs_UProfile_Properties_Bio; "avatar"?: SocialPlatform_X24Defs_UProfile_Properties_Avatar; "location"?: SocialPlatform_X24Defs_UProfile_Properties_Location; -} & { - [K in string as K extends - "bio" | - "avatar" | - "location" - ? never : K]: SocialPlatform_X24Defs_UProfile_AdditionalProperties; -}; +} export type SocialPlatform_X24Defs_UPrivacySettings_Properties_ShowEmail = boolean; @@ -124,15 +100,10 @@ export type SocialPlatform_X24Defs_UPrivacySettings_Properties_ProfileVisible = export type SocialPlatform_X24Defs_UPrivacySettings_AdditionalProperties = never; -export type SocialPlatform_X24Defs_UPrivacySettings = { +export interface SocialPlatform_X24Defs_UPrivacySettings { "profileVisible"?: SocialPlatform_X24Defs_UPrivacySettings_Properties_ProfileVisible; "showEmail"?: SocialPlatform_X24Defs_UPrivacySettings_Properties_ShowEmail; -} & { - [K in string as K extends - "profileVisible" | - "showEmail" - ? never : K]: SocialPlatform_X24Defs_UPrivacySettings_AdditionalProperties; -}; +} export type SocialPlatform_X24Defs_UPostStatus = "draft" | "published" | "archived"; @@ -152,23 +123,14 @@ export type SocialPlatform_X24Defs_UPost_Properties_Author = SocialPlatform_X24D export type SocialPlatform_X24Defs_UPost_AdditionalProperties = never; -export type SocialPlatform_X24Defs_UPost = { +export interface SocialPlatform_X24Defs_UPost { "id": SocialPlatform_X24Defs_UPost_Properties_Id; "title": SocialPlatform_X24Defs_UPost_Properties_Title; "content"?: SocialPlatform_X24Defs_UPost_Properties_Content; "author": SocialPlatform_X24Defs_UPost_Properties_Author; "tags"?: SocialPlatform_X24Defs_UPost_Properties_Tags; "status"?: SocialPlatform_X24Defs_UPost_Properties_Status; -} & { - [K in string as K extends - "id" | - "title" | - "content" | - "author" | - "tags" | - "status" - ? never : K]: SocialPlatform_X24Defs_UPost_AdditionalProperties; -}; +} export type SocialPlatform_X24Defs_UNotificationSettings_Properties_Sms = boolean; @@ -178,32 +140,18 @@ export type SocialPlatform_X24Defs_UNotificationSettings_Properties_Email = bool export type SocialPlatform_X24Defs_UNotificationSettings_AdditionalProperties = never; -export type SocialPlatform_X24Defs_UNotificationSettings = { +export interface SocialPlatform_X24Defs_UNotificationSettings { "email"?: SocialPlatform_X24Defs_UNotificationSettings_Properties_Email; "push"?: SocialPlatform_X24Defs_UNotificationSettings_Properties_Push; "sms"?: SocialPlatform_X24Defs_UNotificationSettings_Properties_Sms; -} & { - [K in string as K extends - "email" | - "push" | - "sms" - ? never : K]: SocialPlatform_X24Defs_UNotificationSettings_AdditionalProperties; -}; +} export type SocialPlatform_X24Defs_UEmail = string; -export type SocialPlatform = { +export interface SocialPlatform { "user": SocialPlatform_Properties_X75ser; "posts": SocialPlatform_Properties_Posts; "settings": SocialPlatform_Properties_Settings; "followers"?: SocialPlatform_Properties_Followers; "pinnedPost"?: SocialPlatform_Properties_PinnedPost; -} & { - [K in string as K extends - "user" | - "posts" | - "settings" | - "followers" | - "pinnedPost" - ? never : K]: SocialPlatform_AdditionalProperties; -}; +} diff --git a/test/e2e/typescript/2020-12/embedded_resources/expected.d.ts b/test/e2e/typescript/2020-12/embedded_resources/expected.d.ts index 06cffc9..7f184ca 100644 --- a/test/e2e/typescript/2020-12/embedded_resources/expected.d.ts +++ b/test/e2e/typescript/2020-12/embedded_resources/expected.d.ts @@ -6,18 +6,10 @@ export type DocumentSystem_X24Defs_UItem_Properties_Name = string; export type DocumentSystem_X24Defs_UItem_AdditionalProperties = never; -export type DocumentSystem_X24Defs_UItem = { +export interface DocumentSystem_X24Defs_UItem { "name": DocumentSystem_X24Defs_UItem_Properties_Name; -} & { - [K in string as K extends - "name" - ? never : K]: DocumentSystem_X24Defs_UItem_AdditionalProperties; -}; +} -export type DocumentSystem = { +export interface DocumentSystem { "item": DocumentSystem_Properties_Item; -} & { - [K in string as K extends - "item" - ? never : K]: DocumentSystem_AdditionalProperties; -}; +} diff --git a/test/e2e/typescript/2020-12/enum_complex_types/expected.d.ts b/test/e2e/typescript/2020-12/enum_complex_types/expected.d.ts index dca6e38..6048b0e 100644 --- a/test/e2e/typescript/2020-12/enum_complex_types/expected.d.ts +++ b/test/e2e/typescript/2020-12/enum_complex_types/expected.d.ts @@ -20,16 +20,9 @@ export type ComplexEnum_Properties_Coordinates = [ 0, 0 ] | [ 1, 1 ] | [ -1, -1 export type ComplexEnum_AdditionalProperties = never; -export type ComplexEnum = { +export interface ComplexEnum { "status"?: ComplexEnum_Properties_Status; "coordinates"?: ComplexEnum_Properties_Coordinates; "fixedConfig"?: ComplexEnum_Properties_FixedConfig; "fixedList"?: ComplexEnum_Properties_FixedList; -} & { - [K in string as K extends - "status" | - "coordinates" | - "fixedConfig" | - "fixedList" - ? never : K]: ComplexEnum_AdditionalProperties; -}; +} diff --git a/test/e2e/typescript/2020-12/implicit_types_and_reused_refs/expected.d.ts b/test/e2e/typescript/2020-12/implicit_types_and_reused_refs/expected.d.ts index 82d86ae..1e5fbdd 100644 --- a/test/e2e/typescript/2020-12/implicit_types_and_reused_refs/expected.d.ts +++ b/test/e2e/typescript/2020-12/implicit_types_and_reused_refs/expected.d.ts @@ -12,17 +12,11 @@ export type DocSystem_Properties_RelatedDocuments_Items_Properties_Id = DocSyste export type DocSystem_Properties_RelatedDocuments_Items_AdditionalProperties = never; -export type DocSystem_Properties_RelatedDocuments_Items = { +export interface DocSystem_Properties_RelatedDocuments_Items { "id": DocSystem_Properties_RelatedDocuments_Items_Properties_Id; "relationship": DocSystem_Properties_RelatedDocuments_Items_Properties_Relationship; "title"?: DocSystem_Properties_RelatedDocuments_Items_Properties_Title; -} & { - [K in string as K extends - "id" | - "relationship" | - "title" - ? never : K]: DocSystem_Properties_RelatedDocuments_Items_AdditionalProperties; -}; +} export type DocSystem_Properties_RelatedDocuments = DocSystem_Properties_RelatedDocuments_Items[]; @@ -48,21 +42,13 @@ export type DocSystem_Properties_Permissions_Properties_Editors = DocSystem_Prop export type DocSystem_Properties_Permissions_AdditionalProperties = never; -export type DocSystem_Properties_Permissions = { +export interface DocSystem_Properties_Permissions { "owner": DocSystem_Properties_Permissions_Properties_Owner; "readers": DocSystem_Properties_Permissions_Properties_Readers; "editors": DocSystem_Properties_Permissions_Properties_Editors; "isPublic"?: DocSystem_Properties_Permissions_Properties_IsPublic; "expiresAt"?: DocSystem_Properties_Permissions_Properties_ExpiresAt; -} & { - [K in string as K extends - "owner" | - "readers" | - "editors" | - "isPublic" | - "expiresAt" - ? never : K]: DocSystem_Properties_Permissions_AdditionalProperties; -}; +} export type DocSystem_Properties_History_Items_Properties_Timestamp = DocSystem_X24Defs_UTimestamp; @@ -94,17 +80,11 @@ export type DocSystem_Properties_History_Items_Properties_Details_AnyOf_ZIndex0_ export type DocSystem_Properties_History_Items_Properties_Details_AnyOf_ZIndex0_AdditionalProperties = never; -export type DocSystem_Properties_History_Items_Properties_Details_AnyOf_ZIndex0 = { +export interface DocSystem_Properties_History_Items_Properties_Details_AnyOf_ZIndex0 { "field"?: DocSystem_Properties_History_Items_Properties_Details_AnyOf_ZIndex0_Properties_Field; "oldValue"?: DocSystem_Properties_History_Items_Properties_Details_AnyOf_ZIndex0_Properties_OldValue; "newValue"?: DocSystem_Properties_History_Items_Properties_Details_AnyOf_ZIndex0_Properties_NewValue; -} & { - [K in string as K extends - "field" | - "oldValue" | - "newValue" - ? never : K]: DocSystem_Properties_History_Items_Properties_Details_AnyOf_ZIndex0_AdditionalProperties; -}; +} export type DocSystem_Properties_History_Items_Properties_Details = DocSystem_Properties_History_Items_Properties_Details_AnyOf_ZIndex0 | @@ -116,19 +96,12 @@ export type DocSystem_Properties_History_Items_Properties_Action = "created" | " export type DocSystem_Properties_History_Items_AdditionalProperties = never; -export type DocSystem_Properties_History_Items = { +export interface DocSystem_Properties_History_Items { "action": DocSystem_Properties_History_Items_Properties_Action; "actor": DocSystem_Properties_History_Items_Properties_Actor; "timestamp": DocSystem_Properties_History_Items_Properties_Timestamp; "details"?: DocSystem_Properties_History_Items_Properties_Details; -} & { - [K in string as K extends - "action" | - "actor" | - "timestamp" | - "details" - ? never : K]: DocSystem_Properties_History_Items_AdditionalProperties; -}; +} export type DocSystem_Properties_History = DocSystem_Properties_History_Items[]; @@ -146,15 +119,10 @@ export type DocSystem_Properties_Document_Properties_Tags_Items_Properties_Color export type DocSystem_Properties_Document_Properties_Tags_Items_AdditionalProperties = never; -export type DocSystem_Properties_Document_Properties_Tags_Items = { +export interface DocSystem_Properties_Document_Properties_Tags_Items { "name": DocSystem_Properties_Document_Properties_Tags_Items_Properties_Name; "color"?: DocSystem_Properties_Document_Properties_Tags_Items_Properties_Color; -} & { - [K in string as K extends - "name" | - "color" - ? never : K]: DocSystem_Properties_Document_Properties_Tags_Items_AdditionalProperties; -}; +} export type DocSystem_Properties_Document_Properties_Tags = DocSystem_Properties_Document_Properties_Tags_Items[]; @@ -170,17 +138,11 @@ export type DocSystem_Properties_Document_Properties_Metadata_Properties_Created export type DocSystem_Properties_Document_Properties_Metadata_AdditionalProperties = never; -export type DocSystem_Properties_Document_Properties_Metadata = { +export interface DocSystem_Properties_Document_Properties_Metadata { "createdAt"?: DocSystem_Properties_Document_Properties_Metadata_Properties_CreatedAt; "updatedAt"?: DocSystem_Properties_Document_Properties_Metadata_Properties_X75pdatedAt; "version"?: DocSystem_Properties_Document_Properties_Metadata_Properties_Version; -} & { - [K in string as K extends - "createdAt" | - "updatedAt" | - "version" - ? never : K]: DocSystem_Properties_Document_Properties_Metadata_AdditionalProperties; -}; +} export type DocSystem_Properties_Document_Properties_Id = DocSystem_X24Defs_X55X55ID; @@ -198,23 +160,17 @@ export type DocSystem_Properties_Document_Properties_Content_Properties_Body = s export type DocSystem_Properties_Document_Properties_Content_AdditionalProperties = never; -export type DocSystem_Properties_Document_Properties_Content = { +export interface DocSystem_Properties_Document_Properties_Content { "format": DocSystem_Properties_Document_Properties_Content_Properties_Format; "body": DocSystem_Properties_Document_Properties_Content_Properties_Body; "summary"?: DocSystem_Properties_Document_Properties_Content_Properties_Summary; -} & { - [K in string as K extends - "format" | - "body" | - "summary" - ? never : K]: DocSystem_Properties_Document_Properties_Content_AdditionalProperties; -}; +} export type DocSystem_Properties_Document_Properties_Author = DocSystem_X24Defs_X55ser; export type DocSystem_Properties_Document_AdditionalProperties = never; -export type DocSystem_Properties_Document = { +export interface DocSystem_Properties_Document { "id": DocSystem_Properties_Document_Properties_Id; "title": DocSystem_Properties_Document_Properties_Title; "content": DocSystem_Properties_Document_Properties_Content; @@ -222,17 +178,7 @@ export type DocSystem_Properties_Document = { "reviewers"?: DocSystem_Properties_Document_Properties_Reviewers; "tags"?: DocSystem_Properties_Document_Properties_Tags; "metadata"?: DocSystem_Properties_Document_Properties_Metadata; -} & { - [K in string as K extends - "id" | - "title" | - "content" | - "author" | - "reviewers" | - "tags" | - "metadata" - ? never : K]: DocSystem_Properties_Document_AdditionalProperties; -}; +} export type DocSystem_AdditionalProperties = never; @@ -252,19 +198,12 @@ export type DocSystem_X24Defs_X55ser_Properties_DisplayName = export type DocSystem_X24Defs_X55ser_AdditionalProperties = never; -export type DocSystem_X24Defs_X55ser = { +export interface DocSystem_X24Defs_X55ser { "id": DocSystem_X24Defs_X55ser_Properties_Id; "email": DocSystem_X24Defs_X55ser_Properties_Email; "displayName"?: DocSystem_X24Defs_X55ser_Properties_DisplayName; "role"?: DocSystem_X24Defs_X55ser_Properties_Role; -} & { - [K in string as K extends - "id" | - "email" | - "displayName" | - "role" - ? never : K]: DocSystem_X24Defs_X55ser_AdditionalProperties; -}; +} export type DocSystem_X24Defs_X55X55ID = string; @@ -282,28 +221,15 @@ export type DocSystem_X24Defs_UTimestamp_Properties_Iso = string; export type DocSystem_X24Defs_UTimestamp_AdditionalProperties = never; -export type DocSystem_X24Defs_UTimestamp = { +export interface DocSystem_X24Defs_UTimestamp { "unix": DocSystem_X24Defs_UTimestamp_Properties_X75nix; "iso": DocSystem_X24Defs_UTimestamp_Properties_Iso; "timezone"?: DocSystem_X24Defs_UTimestamp_Properties_Timezone; -} & { - [K in string as K extends - "unix" | - "iso" | - "timezone" - ? never : K]: DocSystem_X24Defs_UTimestamp_AdditionalProperties; -}; - -export type DocSystem = { +} + +export interface DocSystem { "document": DocSystem_Properties_Document; "permissions": DocSystem_Properties_Permissions; "history": DocSystem_Properties_History; "relatedDocuments"?: DocSystem_Properties_RelatedDocuments; -} & { - [K in string as K extends - "document" | - "permissions" | - "history" | - "relatedDocuments" - ? never : K]: DocSystem_AdditionalProperties; -}; +} diff --git a/test/e2e/typescript/2020-12/object_with_additional_properties/expected.d.ts b/test/e2e/typescript/2020-12/object_with_additional_properties/expected.d.ts index dbbe48c..b931cdb 100644 --- a/test/e2e/typescript/2020-12/object_with_additional_properties/expected.d.ts +++ b/test/e2e/typescript/2020-12/object_with_additional_properties/expected.d.ts @@ -4,12 +4,12 @@ export type Person_Properties_Age = number; export type Person_AdditionalProperties = string; -export type Person = { +export interface Person { "name": Person_Properties_Name; "age"?: Person_Properties_Age; -} & { - [K in string as K extends - "name" | - "age" - ? never : K]: Person_AdditionalProperties; -}; + [key: string]: + Person_Properties_Name | + Person_Properties_Age | + Person_AdditionalProperties | + undefined; +} diff --git a/test/e2e/typescript/2020-12/object_with_additional_properties/test.ts b/test/e2e/typescript/2020-12/object_with_additional_properties/test.ts index 009d7ef..a931f17 100644 --- a/test/e2e/typescript/2020-12/object_with_additional_properties/test.ts +++ b/test/e2e/typescript/2020-12/object_with_additional_properties/test.ts @@ -1,10 +1,33 @@ import { Person } from "./expected"; -const person: Person = { +const test1: Person = { name: "John Doe" }; -const invalidPerson: Person = { +const test2: Person = { // @ts-expect-error name: 123 }; + +const test3: Person = { + name: "John Doe", + age: 30 +}; + +const test4: Person = { + name: "John Doe", + age: 30, + extra: "foo" +}; + +// @ts-expect-error name is required +const test5: Person = { + extra: "foo" +}; + +const test6: Person = { + name: "John Doe", + age: 30, + // @ts-expect-error + extra: true +}; diff --git a/test/e2e/typescript/2020-12/tuples_and_arrays/expected.d.ts b/test/e2e/typescript/2020-12/tuples_and_arrays/expected.d.ts index 48dd646..c61f6ba 100644 --- a/test/e2e/typescript/2020-12/tuples_and_arrays/expected.d.ts +++ b/test/e2e/typescript/2020-12/tuples_and_arrays/expected.d.ts @@ -76,15 +76,10 @@ export type DataPipeline_Properties_Stages_Items_Properties_InputTypes_AnyOf_ZIn export type DataPipeline_Properties_Stages_Items_Properties_InputTypes_AnyOf_ZIndex3_Items_AdditionalProperties = never; -export type DataPipeline_Properties_Stages_Items_Properties_InputTypes_AnyOf_ZIndex3_Items = { +export interface DataPipeline_Properties_Stages_Items_Properties_InputTypes_AnyOf_ZIndex3_Items { "typeName"?: DataPipeline_Properties_Stages_Items_Properties_InputTypes_AnyOf_ZIndex3_Items_Properties_TypeName; "nullable"?: DataPipeline_Properties_Stages_Items_Properties_InputTypes_AnyOf_ZIndex3_Items_Properties_Nullable; -} & { - [K in string as K extends - "typeName" | - "nullable" - ? never : K]: DataPipeline_Properties_Stages_Items_Properties_InputTypes_AnyOf_ZIndex3_Items_AdditionalProperties; -}; +} export type DataPipeline_Properties_Stages_Items_Properties_InputTypes_AnyOf_ZIndex3 = [DataPipeline_Properties_Stages_Items_Properties_InputTypes_AnyOf_ZIndex3_PrefixItems_ZIndex0, DataPipeline_Properties_Stages_Items_Properties_InputTypes_AnyOf_ZIndex3_PrefixItems_ZIndex1, ...DataPipeline_Properties_Stages_Items_Properties_InputTypes_AnyOf_ZIndex3_Items[]]; @@ -111,15 +106,10 @@ export type DataPipeline_Properties_Stages_Items_Properties_Config_AnyOf_ZIndex0 export type DataPipeline_Properties_Stages_Items_Properties_Config_AnyOf_ZIndex0_AdditionalProperties = never; -export type DataPipeline_Properties_Stages_Items_Properties_Config_AnyOf_ZIndex0 = { +export interface DataPipeline_Properties_Stages_Items_Properties_Config_AnyOf_ZIndex0 { "timeout"?: DataPipeline_Properties_Stages_Items_Properties_Config_AnyOf_ZIndex0_Properties_Timeout; "retries"?: DataPipeline_Properties_Stages_Items_Properties_Config_AnyOf_ZIndex0_Properties_Retries; -} & { - [K in string as K extends - "timeout" | - "retries" - ? never : K]: DataPipeline_Properties_Stages_Items_Properties_Config_AnyOf_ZIndex0_AdditionalProperties; -}; +} export type DataPipeline_Properties_Stages_Items_Properties_Config = DataPipeline_Properties_Stages_Items_Properties_Config_AnyOf_ZIndex0 | @@ -127,21 +117,13 @@ export type DataPipeline_Properties_Stages_Items_Properties_Config = export type DataPipeline_Properties_Stages_Items_AdditionalProperties = never; -export type DataPipeline_Properties_Stages_Items = { +export interface DataPipeline_Properties_Stages_Items { "name": DataPipeline_Properties_Stages_Items_Properties_Name; "inputTypes": DataPipeline_Properties_Stages_Items_Properties_InputTypes; "outputType": DataPipeline_Properties_Stages_Items_Properties_OutputType; "config"?: DataPipeline_Properties_Stages_Items_Properties_Config; "metrics"?: DataPipeline_Properties_Stages_Items_Properties_Metrics; -} & { - [K in string as K extends - "name" | - "inputTypes" | - "outputType" | - "config" | - "metrics" - ? never : K]: DataPipeline_Properties_Stages_Items_AdditionalProperties; -}; +} export type DataPipeline_Properties_Stages = DataPipeline_Properties_Stages_Items[]; @@ -211,19 +193,12 @@ export type DataPipeline_Properties_Pipeline_Properties_Coordinates = export type DataPipeline_Properties_Pipeline_AdditionalProperties = never; -export type DataPipeline_Properties_Pipeline = { +export interface DataPipeline_Properties_Pipeline { "id": DataPipeline_Properties_Pipeline_Properties_Id; "version": DataPipeline_Properties_Pipeline_Properties_Version; "coordinates": DataPipeline_Properties_Pipeline_Properties_Coordinates; "tags"?: DataPipeline_Properties_Pipeline_Properties_Tags; -} & { - [K in string as K extends - "id" | - "version" | - "coordinates" | - "tags" - ? never : K]: DataPipeline_Properties_Pipeline_AdditionalProperties; -}; +} export type DataPipeline_Properties_Metadata_Properties_ModifiedAt_AnyOf_ZIndex1 = null; @@ -295,19 +270,12 @@ export type DataPipeline_Properties_Metadata_Properties_Authors = DataPipeline_P export type DataPipeline_Properties_Metadata_AdditionalProperties = never; -export type DataPipeline_Properties_Metadata = { +export interface DataPipeline_Properties_Metadata { "createdAt"?: DataPipeline_Properties_Metadata_Properties_CreatedAt; "modifiedAt"?: DataPipeline_Properties_Metadata_Properties_ModifiedAt; "authors"?: DataPipeline_Properties_Metadata_Properties_Authors; "flags"?: DataPipeline_Properties_Metadata_Properties_Flags; -} & { - [K in string as K extends - "createdAt" | - "modifiedAt" | - "authors" | - "flags" - ? never : K]: DataPipeline_Properties_Metadata_AdditionalProperties; -}; +} export type DataPipeline_Properties_Connections_Items_AnyOf_ZIndex5 = number; @@ -319,15 +287,10 @@ export type DataPipeline_Properties_Connections_Items_AnyOf_ZIndex3_PrefixItems_ export type DataPipeline_Properties_Connections_Items_AnyOf_ZIndex3_PrefixItems_ZIndex2_AdditionalProperties = never; -export type DataPipeline_Properties_Connections_Items_AnyOf_ZIndex3_PrefixItems_ZIndex2 = { +export interface DataPipeline_Properties_Connections_Items_AnyOf_ZIndex3_PrefixItems_ZIndex2 { "weight": DataPipeline_Properties_Connections_Items_AnyOf_ZIndex3_PrefixItems_ZIndex2_Properties_Weight; "bidirectional"?: DataPipeline_Properties_Connections_Items_AnyOf_ZIndex3_PrefixItems_ZIndex2_Properties_Bidirectional; -} & { - [K in string as K extends - "weight" | - "bidirectional" - ? never : K]: DataPipeline_Properties_Connections_Items_AnyOf_ZIndex3_PrefixItems_ZIndex2_AdditionalProperties; -}; +} export type DataPipeline_Properties_Connections_Items_AnyOf_ZIndex3_PrefixItems_ZIndex1 = string; @@ -356,16 +319,9 @@ export type DataPipeline_Properties_Connections = DataPipeline_Properties_Connec export type DataPipeline_AdditionalProperties = never; -export type DataPipeline = { +export interface DataPipeline { "pipeline": DataPipeline_Properties_Pipeline; "stages": DataPipeline_Properties_Stages; "connections": DataPipeline_Properties_Connections; "metadata"?: DataPipeline_Properties_Metadata; -} & { - [K in string as K extends - "pipeline" | - "stages" | - "connections" | - "metadata" - ? never : K]: DataPipeline_AdditionalProperties; -}; +} diff --git a/test/e2e/typescript/2020-12/vocabulary_ignored/expected.d.ts b/test/e2e/typescript/2020-12/vocabulary_ignored/expected.d.ts index 96b0738..5e1b5a6 100644 --- a/test/e2e/typescript/2020-12/vocabulary_ignored/expected.d.ts +++ b/test/e2e/typescript/2020-12/vocabulary_ignored/expected.d.ts @@ -6,14 +6,8 @@ export type VocabTest_Properties_Name = string; export type VocabTest_AdditionalProperties = never; -export type VocabTest = { +export interface VocabTest { "name": VocabTest_Properties_Name; "value": VocabTest_Properties_Value; "optional"?: VocabTest_Properties_Optional; -} & { - [K in string as K extends - "name" | - "value" | - "optional" - ? never : K]: VocabTest_AdditionalProperties; -}; +} diff --git a/test/generator/generator_typescript_test.cc b/test/generator/generator_typescript_test.cc index ddd6d7e..6409da5 100644 --- a/test/generator/generator_typescript_test.cc +++ b/test/generator/generator_typescript_test.cc @@ -783,8 +783,8 @@ TEST(Generator_typescript, object_with_additional_properties_typed) { "age", IRObjectValue{{sourcemeta::core::Pointer{"properties", "age"}}, false, false}); - object.additional = IRObjectValue{ - {sourcemeta::core::Pointer{"additionalProperties"}}, false, false}; + object.additional = + IRType{{sourcemeta::core::Pointer{"additionalProperties"}}}; result.emplace_back(std::move(object)); std::ostringstream output; @@ -796,15 +796,15 @@ export type Person_Properties_Age = number; export type Person_AdditionalProperties = string; -export type Person = { +export interface Person { "name": Person_Properties_Name; "age"?: Person_Properties_Age; -} & { - [K in string as K extends - "name" | - "age" - ? never : K]: Person_AdditionalProperties; -}; + [key: string]: + Person_Properties_Name | + Person_Properties_Age | + Person_AdditionalProperties | + undefined; +} )TS"}; EXPECT_EQ(output.str(), expected); @@ -828,8 +828,8 @@ TEST(Generator_typescript, object.members.emplace_back( "id", IRObjectValue{ {sourcemeta::core::Pointer{"properties", "id"}}, true, false}); - object.additional = IRObjectValue{ - {sourcemeta::core::Pointer{"additionalProperties"}}, false, false}; + object.additional = + IRType{{sourcemeta::core::Pointer{"additionalProperties"}}}; result.emplace_back(std::move(object)); std::ostringstream output; @@ -839,13 +839,13 @@ TEST(Generator_typescript, export type Item_AdditionalProperties = string; -export type Item = { +export interface Item { "id": Item_Properties_Id; -} & { - [K in string as K extends - "id" - ? never : K]: Item_AdditionalProperties; -}; + [key: string]: + Item_Properties_Id | + Item_AdditionalProperties | + undefined; +} )TS"}; EXPECT_EQ(output.str(), expected); @@ -887,8 +887,8 @@ TEST(Generator_typescript, object_with_additional_properties_false) { "foo", IRObjectValue{{sourcemeta::core::Pointer{"properties", "foo"}}, false, false}); - object.additional = IRObjectValue{ - {sourcemeta::core::Pointer{"additionalProperties"}}, false, false}; + object.additional = + IRType{{sourcemeta::core::Pointer{"additionalProperties"}}}; result.emplace_back(std::move(object)); std::ostringstream output; @@ -898,13 +898,13 @@ TEST(Generator_typescript, object_with_additional_properties_false) { export type MyObject_AdditionalProperties = never; -export type MyObject = { +export interface MyObject { "foo"?: MyObject_Properties_Foo; -} & { - [K in string as K extends - "foo" - ? never : K]: MyObject_AdditionalProperties; -}; + [key: string]: + MyObject_Properties_Foo | + MyObject_AdditionalProperties | + undefined; +} )TS"}; EXPECT_EQ(output.str(), expected); @@ -960,8 +960,8 @@ TEST(Generator_typescript, object_with_additional_properties_any) { "name", IRObjectValue{{sourcemeta::core::Pointer{"properties", "name"}}, false, false}); - object.additional = IRObjectValue{ - {sourcemeta::core::Pointer{"additionalProperties"}}, false, false}; + object.additional = + IRType{{sourcemeta::core::Pointer{"additionalProperties"}}}; result.emplace_back(std::move(object)); std::ostringstream output; @@ -986,13 +986,13 @@ export type Test_AdditionalProperties = Test_AdditionalProperties_AnyOf_3 | Test_AdditionalProperties_AnyOf_4; -export type Test = { +export interface Test { "name"?: Test_Properties_Name; -} & { - [K in string as K extends - "name" - ? never : K]: Test_AdditionalProperties; -}; + [key: string]: + Test_Properties_Name | + Test_AdditionalProperties | + undefined; +} )TS"}; EXPECT_EQ(output.str(), expected); @@ -1009,8 +1009,8 @@ TEST(Generator_typescript, object_only_additional_properties) { IRObject object; object.pointer = {}; - object.additional = IRObjectValue{ - {sourcemeta::core::Pointer{"additionalProperties"}}, false, false}; + object.additional = + IRType{{sourcemeta::core::Pointer{"additionalProperties"}}}; result.emplace_back(std::move(object)); std::ostringstream output; @@ -1086,8 +1086,8 @@ TEST(Generator_typescript, object_only_additional_properties_true) { IRObject object; object.pointer = {}; - object.additional = IRObjectValue{ - {sourcemeta::core::Pointer{"additionalProperties"}}, false, false}; + object.additional = + IRType{{sourcemeta::core::Pointer{"additionalProperties"}}}; result.emplace_back(std::move(object)); std::ostringstream output; diff --git a/test/ir/ir_2020_12_test.cc b/test/ir/ir_2020_12_test.cc index d6b9ee4..2cc0fe7 100644 --- a/test/ir/ir_2020_12_test.cc +++ b/test/ir/ir_2020_12_test.cc @@ -373,8 +373,6 @@ TEST(IR_2020_12, object_with_additional_properties) { "/properties/foo"); EXPECT_TRUE(std::get(result.at(2)).additional.has_value()); - EXPECT_FALSE(std::get(result.at(2)).additional->required); - EXPECT_FALSE(std::get(result.at(2)).additional->immutable); EXPECT_AS_STRING(std::get(result.at(2)).additional->pointer, "/additionalProperties"); } @@ -444,11 +442,7 @@ TEST(IR_2020_12, object_with_impossible_additional_properties) { std::get(result.at(2)).members.at(0).second.pointer, "/properties/foo"); - EXPECT_TRUE(std::get(result.at(2)).additional.has_value()); - EXPECT_FALSE(std::get(result.at(2)).additional->required); - EXPECT_FALSE(std::get(result.at(2)).additional->immutable); - EXPECT_AS_STRING(std::get(result.at(2)).additional->pointer, - "/additionalProperties"); + EXPECT_FALSE(std::get(result.at(2)).additional.has_value()); } TEST(IR_2020_12, array_with_items) { @@ -874,9 +868,7 @@ TEST(IR_2020_12, embedded_resource_with_nested_id_no_duplicates) { EXPECT_AS_STRING( std::get(result.at(4)).members.at(0).second.pointer, "/$defs/Item/properties/name"); - EXPECT_TRUE(std::get(result.at(4)).additional.has_value()); - EXPECT_AS_STRING(std::get(result.at(4)).additional->pointer, - "/$defs/Item/additionalProperties"); + EXPECT_FALSE(std::get(result.at(4)).additional.has_value()); EXPECT_TRUE(std::holds_alternative(result.at(5))); EXPECT_AS_STRING(std::get(result.at(5)).pointer, ""); @@ -886,7 +878,5 @@ TEST(IR_2020_12, embedded_resource_with_nested_id_no_duplicates) { EXPECT_AS_STRING( std::get(result.at(5)).members.at(0).second.pointer, "/properties/item"); - EXPECT_TRUE(std::get(result.at(5)).additional.has_value()); - EXPECT_AS_STRING(std::get(result.at(5)).additional->pointer, - "/additionalProperties"); + EXPECT_FALSE(std::get(result.at(5)).additional.has_value()); }