### Question:
UnionGenerator implements Runnable { @Override public void run() { writer.writeShapeDocs(shape); writer.openBlock("export type $L = ", "", symbol.getName(), () -> { for (String variant : variantMap.values()) { writer.write("| $L.$L", symbol.getName(), variant); } writer.write("| $L.$$UnknownMember", symbol.getName()); }); writer.openBlock("export namespace $L {", "}", symbol.getName(), () -> { writeUnionMemberInterfaces(); writeVisitorType(); writeVisitorFunction(); writeFilterSensitiveLog(); }); } UnionGenerator(Model model, SymbolProvider symbolProvider, TypeScriptWriter writer, UnionShape shape); @Override void run();  }### Answer:
@Test public void generatesTaggedUnions() { MemberShape memberA = MemberShape.builder() .id("com.foo#Example$A") .target("smithy.api#String") .build(); MemberShape memberB = MemberShape.builder() .id("com.foo#Example$B") .target("smithy.api#Integer") .build(); MemberShape memberC = MemberShape.builder() .id("com.foo#Example$C") .target("smithy.api#Boolean") .build(); UnionShape unionShape = UnionShape.builder() .id("com.foo#Example") .addMember(memberA) .addMember(memberB) .addMember(memberC) .build(); Model model = Model.assembler().addShapes(unionShape, memberA, memberB, memberC).assemble().unwrap(); SymbolProvider symbolProvider = TypeScriptCodegenPlugin.createSymbolProvider(model); TypeScriptWriter writer = new TypeScriptWriter("./Example"); new UnionGenerator(model, symbolProvider, writer, unionShape).run(); String output = writer.toString(); assertThat(output, containsString("export type Example =\n" + " | Example.AMember\n" + " | Example.BMember\n" + " | Example.CMember\n" + " | Example.$UnknownMember")); assertThat(output, containsString("export namespace Example {")); assertThat(output, containsString("export interface $UnknownMember {\n" + " A?: never;\n" + " B?: never;\n" + " C?: never;\n" + " $unknown: [string, any];\n" + " }")); assertThat(output, containsString("export interface AMember {\n" + " A: string;\n" + " B?: never;\n" + " C?: never;\n" + " $unknown?: never;\n" + " }")); assertThat(output, containsString("export interface BMember {\n" + " A?: never;\n" + " B: number;\n" + " C?: never;\n" + " $unknown?: never;\n" + " }")); assertThat(output, containsString("export interface CMember {\n" + " A?: never;\n" + " B?: never;\n" + " C: boolean;\n" + " $unknown?: never;\n" + " }")); assertThat(output, containsString("export interface Visitor<T> {\n" + " A: (value: string) => T;\n" + " B: (value: number) => T;\n" + " C: (value: boolean) => T;\n" + " _: (name: string, value: any) => T;\n" + " }")); assertThat(output, containsString("export const visit = <T>(\n" + " value: Example,\n" + " visitor: Visitor<T>\n" + " ): T => {\n" + " if (value.A !== undefined) return visitor.A(value.A);\n" + " if (value.B !== undefined) return visitor.B(value.B);\n" + " if (value.C !== undefined) return visitor.C(value.C);\n" + " return visitor._(value.$unknown[0], value.$unknown[1]);\n" + " }")); }