Skip to content

Commit 49958f2

Browse files
authored
feat: allow undefined when property optional for exactOptionalPropertyTypes (#1448)
* feat: allow undefined when property optional for exactOptionalPropertyTypes * update protocol tests
1 parent 0d9cee8 commit 49958f2

File tree

4 files changed

+106
-103
lines changed

4 files changed

+106
-103
lines changed

private/smithy-rpcv2-cbor/src/models/models_0.ts

Lines changed: 100 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export class ValidationException extends __BaseException {
3434
* A member can appear in this list more than once if it failed to satisfy multiple constraints.
3535
* @public
3636
*/
37-
fieldList?: ValidationExceptionField[];
37+
fieldList?: ValidationExceptionField[] | undefined;
3838

3939
/**
4040
* @internal
@@ -54,14 +54,14 @@ export class ValidationException extends __BaseException {
5454
* @public
5555
*/
5656
export interface ClientOptionalDefaults {
57-
member?: number;
57+
member?: number | undefined;
5858
}
5959

6060
/**
6161
* @public
6262
*/
6363
export interface ComplexNestedErrorData {
64-
Foo?: string;
64+
Foo?: string | undefined;
6565
}
6666

6767
/**
@@ -71,8 +71,8 @@ export interface ComplexNestedErrorData {
7171
export class ComplexError extends __BaseException {
7272
readonly name: "ComplexError" = "ComplexError";
7373
readonly $fault: "client" = "client";
74-
TopLevel?: string;
75-
Nested?: ComplexNestedErrorData;
74+
TopLevel?: string | undefined;
75+
Nested?: ComplexNestedErrorData | undefined;
7676
/**
7777
* @internal
7878
*/
@@ -111,36 +111,36 @@ export enum TestIntEnum {
111111
* @public
112112
*/
113113
export interface Defaults {
114-
defaultString?: string;
115-
defaultBoolean?: boolean;
116-
defaultList?: string[];
117-
defaultTimestamp?: Date;
118-
defaultBlob?: Uint8Array;
119-
defaultByte?: number;
120-
defaultShort?: number;
121-
defaultInteger?: number;
122-
defaultLong?: number;
123-
defaultFloat?: number;
124-
defaultDouble?: number;
125-
defaultMap?: Record<string, string>;
126-
defaultEnum?: TestEnum;
127-
defaultIntEnum?: TestIntEnum;
128-
emptyString?: string;
129-
falseBoolean?: boolean;
130-
emptyBlob?: Uint8Array;
131-
zeroByte?: number;
132-
zeroShort?: number;
133-
zeroInteger?: number;
134-
zeroLong?: number;
135-
zeroFloat?: number;
136-
zeroDouble?: number;
114+
defaultString?: string | undefined;
115+
defaultBoolean?: boolean | undefined;
116+
defaultList?: string[] | undefined;
117+
defaultTimestamp?: Date | undefined;
118+
defaultBlob?: Uint8Array | undefined;
119+
defaultByte?: number | undefined;
120+
defaultShort?: number | undefined;
121+
defaultInteger?: number | undefined;
122+
defaultLong?: number | undefined;
123+
defaultFloat?: number | undefined;
124+
defaultDouble?: number | undefined;
125+
defaultMap?: Record<string, string> | undefined;
126+
defaultEnum?: TestEnum | undefined;
127+
defaultIntEnum?: TestIntEnum | undefined;
128+
emptyString?: string | undefined;
129+
falseBoolean?: boolean | undefined;
130+
emptyBlob?: Uint8Array | undefined;
131+
zeroByte?: number | undefined;
132+
zeroShort?: number | undefined;
133+
zeroInteger?: number | undefined;
134+
zeroLong?: number | undefined;
135+
zeroFloat?: number | undefined;
136+
zeroDouble?: number | undefined;
137137
}
138138

139139
/**
140140
* @public
141141
*/
142142
export interface GreetingStruct {
143-
hi?: string;
143+
hi?: string | undefined;
144144
}
145145

146146
/**
@@ -152,21 +152,21 @@ export interface EmptyStructure {}
152152
* @public
153153
*/
154154
export interface Float16Output {
155-
value?: number;
155+
value?: number | undefined;
156156
}
157157

158158
/**
159159
* @public
160160
*/
161161
export interface FractionalSecondsOutput {
162-
datetime?: Date;
162+
datetime?: Date | undefined;
163163
}
164164

165165
/**
166166
* @public
167167
*/
168168
export interface GreetingWithErrorsOutput {
169-
greeting?: string;
169+
greeting?: string | undefined;
170170
}
171171

172172
/**
@@ -176,7 +176,7 @@ export interface GreetingWithErrorsOutput {
176176
export class InvalidGreeting extends __BaseException {
177177
readonly name: "InvalidGreeting" = "InvalidGreeting";
178178
readonly $fault: "client" = "client";
179-
Message?: string;
179+
Message?: string | undefined;
180180
/**
181181
* @internal
182182
*/
@@ -195,57 +195,57 @@ export class InvalidGreeting extends __BaseException {
195195
* @public
196196
*/
197197
export interface OperationWithDefaultsInput {
198-
defaults?: Defaults;
199-
clientOptionalDefaults?: ClientOptionalDefaults;
200-
topLevelDefault?: string;
201-
otherTopLevelDefault?: number;
198+
defaults?: Defaults | undefined;
199+
clientOptionalDefaults?: ClientOptionalDefaults | undefined;
200+
topLevelDefault?: string | undefined;
201+
otherTopLevelDefault?: number | undefined;
202202
}
203203

204204
/**
205205
* @public
206206
*/
207207
export interface OperationWithDefaultsOutput {
208-
defaultString?: string;
209-
defaultBoolean?: boolean;
210-
defaultList?: string[];
211-
defaultTimestamp?: Date;
212-
defaultBlob?: Uint8Array;
213-
defaultByte?: number;
214-
defaultShort?: number;
215-
defaultInteger?: number;
216-
defaultLong?: number;
217-
defaultFloat?: number;
218-
defaultDouble?: number;
219-
defaultMap?: Record<string, string>;
220-
defaultEnum?: TestEnum;
221-
defaultIntEnum?: TestIntEnum;
222-
emptyString?: string;
223-
falseBoolean?: boolean;
224-
emptyBlob?: Uint8Array;
225-
zeroByte?: number;
226-
zeroShort?: number;
227-
zeroInteger?: number;
228-
zeroLong?: number;
229-
zeroFloat?: number;
230-
zeroDouble?: number;
208+
defaultString?: string | undefined;
209+
defaultBoolean?: boolean | undefined;
210+
defaultList?: string[] | undefined;
211+
defaultTimestamp?: Date | undefined;
212+
defaultBlob?: Uint8Array | undefined;
213+
defaultByte?: number | undefined;
214+
defaultShort?: number | undefined;
215+
defaultInteger?: number | undefined;
216+
defaultLong?: number | undefined;
217+
defaultFloat?: number | undefined;
218+
defaultDouble?: number | undefined;
219+
defaultMap?: Record<string, string> | undefined;
220+
defaultEnum?: TestEnum | undefined;
221+
defaultIntEnum?: TestIntEnum | undefined;
222+
emptyString?: string | undefined;
223+
falseBoolean?: boolean | undefined;
224+
emptyBlob?: Uint8Array | undefined;
225+
zeroByte?: number | undefined;
226+
zeroShort?: number | undefined;
227+
zeroInteger?: number | undefined;
228+
zeroLong?: number | undefined;
229+
zeroFloat?: number | undefined;
230+
zeroDouble?: number | undefined;
231231
}
232232

233233
/**
234234
* @public
235235
*/
236236
export interface SimpleStructure {
237-
value?: string;
237+
value?: string | undefined;
238238
}
239239

240240
/**
241241
* @public
242242
*/
243243
export interface RpcV2CborDenseMapsInputOutput {
244-
denseStructMap?: Record<string, GreetingStruct>;
245-
denseNumberMap?: Record<string, number>;
246-
denseBooleanMap?: Record<string, boolean>;
247-
denseStringMap?: Record<string, string>;
248-
denseSetMap?: Record<string, string[]>;
244+
denseStructMap?: Record<string, GreetingStruct> | undefined;
245+
denseNumberMap?: Record<string, number> | undefined;
246+
denseBooleanMap?: Record<string, boolean> | undefined;
247+
denseStringMap?: Record<string, string> | undefined;
248+
denseSetMap?: Record<string, string[]> | undefined;
249249
}
250250

251251
/**
@@ -274,85 +274,85 @@ export enum IntegerEnum {
274274
* @public
275275
*/
276276
export interface StructureListMember {
277-
a?: string;
278-
b?: string;
277+
a?: string | undefined;
278+
b?: string | undefined;
279279
}
280280

281281
/**
282282
* @public
283283
*/
284284
export interface RpcV2CborListInputOutput {
285-
stringList?: string[];
286-
stringSet?: string[];
287-
integerList?: number[];
288-
booleanList?: boolean[];
289-
timestampList?: Date[];
290-
enumList?: FooEnum[];
291-
intEnumList?: IntegerEnum[];
285+
stringList?: string[] | undefined;
286+
stringSet?: string[] | undefined;
287+
integerList?: number[] | undefined;
288+
booleanList?: boolean[] | undefined;
289+
timestampList?: Date[] | undefined;
290+
enumList?: FooEnum[] | undefined;
291+
intEnumList?: IntegerEnum[] | undefined;
292292
/**
293293
* A list of lists of strings.
294294
* @public
295295
*/
296-
nestedStringList?: string[][];
296+
nestedStringList?: string[][] | undefined;
297297

298-
structureList?: StructureListMember[];
299-
blobList?: Uint8Array[];
298+
structureList?: StructureListMember[] | undefined;
299+
blobList?: Uint8Array[] | undefined;
300300
}
301301

302302
/**
303303
* @public
304304
*/
305305
export interface RpcV2CborSparseMapsInputOutput {
306-
sparseStructMap?: Record<string, GreetingStruct>;
307-
sparseNumberMap?: Record<string, number>;
308-
sparseBooleanMap?: Record<string, boolean>;
309-
sparseStringMap?: Record<string, string>;
310-
sparseSetMap?: Record<string, string[]>;
306+
sparseStructMap?: Record<string, GreetingStruct> | undefined;
307+
sparseNumberMap?: Record<string, number> | undefined;
308+
sparseBooleanMap?: Record<string, boolean> | undefined;
309+
sparseStringMap?: Record<string, string> | undefined;
310+
sparseSetMap?: Record<string, string[]> | undefined;
311311
}
312312

313313
/**
314314
* @public
315315
*/
316316
export interface SimpleScalarStructure {
317-
trueBooleanValue?: boolean;
318-
falseBooleanValue?: boolean;
319-
byteValue?: number;
320-
doubleValue?: number;
321-
floatValue?: number;
322-
integerValue?: number;
323-
longValue?: number;
324-
shortValue?: number;
325-
stringValue?: string;
326-
blobValue?: Uint8Array;
317+
trueBooleanValue?: boolean | undefined;
318+
falseBooleanValue?: boolean | undefined;
319+
byteValue?: number | undefined;
320+
doubleValue?: number | undefined;
321+
floatValue?: number | undefined;
322+
integerValue?: number | undefined;
323+
longValue?: number | undefined;
324+
shortValue?: number | undefined;
325+
stringValue?: string | undefined;
326+
blobValue?: Uint8Array | undefined;
327327
}
328328

329329
/**
330330
* @public
331331
*/
332332
export interface SparseNullsOperationInputOutput {
333-
sparseStringList?: string[];
334-
sparseStringMap?: Record<string, string>;
333+
sparseStringList?: string[] | undefined;
334+
sparseStringMap?: Record<string, string> | undefined;
335335
}
336336

337337
/**
338338
* @public
339339
*/
340340
export interface RecursiveShapesInputOutputNested1 {
341-
foo?: string;
342-
nested?: RecursiveShapesInputOutputNested2;
341+
foo?: string | undefined;
342+
nested?: RecursiveShapesInputOutputNested2 | undefined;
343343
}
344344

345345
/**
346346
* @public
347347
*/
348348
export interface RecursiveShapesInputOutputNested2 {
349-
bar?: string;
350-
recursiveMember?: RecursiveShapesInputOutputNested1;
349+
bar?: string | undefined;
350+
recursiveMember?: RecursiveShapesInputOutputNested1 | undefined;
351351
}
352352

353353
/**
354354
* @public
355355
*/
356356
export interface RecursiveShapesInputOutput {
357-
nested?: RecursiveShapesInputOutputNested1;
357+
nested?: RecursiveShapesInputOutputNested1 | undefined;
358358
}

smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/StructuredMemberWriter.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,9 @@ void writeMembers(TypeScriptWriter writer, Shape shape) {
106106
String optionalSuffix = shape.isUnionShape() || !isRequiredMember(member) ? "?" : "";
107107
String typeSuffix = requiredMemberMode == RequiredMemberMode.NULLABLE
108108
&& isRequiredMember(member) ? " | undefined" : "";
109+
if (optionalSuffix.equals("?")) {
110+
typeSuffix = " | undefined"; // support exactOptionalPropertyTypes.
111+
}
109112
writer.write("${L}${L}${L}: ${T}${L};", memberPrefix, memberName, optionalSuffix,
110113
symbolProvider.toSymbol(member), typeSuffix);
111114

smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/TypeScriptSettings.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -558,7 +558,7 @@ public enum RequiredMemberMode {
558558
NULLABLE("nullable"),
559559

560560
/**
561-
* This will dissallow members marked as {@link RequiredTrait} to be {@code undefined}.
561+
* This will disallow members marked as {@link RequiredTrait} to be {@code undefined}.
562562
* Use this mode with CAUTION because it comes with certain risks. When a server drops
563563
* {@link RequiredTrait} from an output shape (and it is replaced with {@link DefaultTrait}
564564
* as defined by the spec), if the server does not always serialize a value,

smithy-typescript-codegen/src/test/java/software/amazon/smithy/typescript/codegen/StructureGeneratorTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ public void properlyGeneratesOptionalNonMessageMemberOfException() {
8181
"export class Err extends __BaseException {\n"
8282
+ " readonly name: \"Err\" = \"Err\";\n"
8383
+ " readonly $fault: \"client\" = \"client\";\n"
84-
+ " foo?: string;\n"
84+
+ " foo?: string | undefined;\n"
8585
+ " /**\n"
8686
+ " * @internal\n"
8787
+ " */\n"
@@ -525,7 +525,7 @@ public void generatesNonErrorStructures() {
525525
String output = writer.toString();
526526

527527
assertThat(output, containsString("export interface Bar {"));
528-
assertThat(output, containsString("foo?: string;"));
528+
assertThat(output, containsString("foo?: string | undefined;"));
529529
}
530530

531531
private StructureShape createNonErrorStructure() {

0 commit comments

Comments
 (0)