You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@beam.apache.org by gi...@apache.org on 2022/07/09 22:20:31 UTC

[beam] branch asf-site updated: Publishing website 2022/07/09 22:20:23 at commit f641c24

This is an automated email from the ASF dual-hosted git repository.

git-site-role pushed a commit to branch asf-site
in repository https://gitbox.apache.org/repos/asf/beam.git


The following commit(s) were added to refs/heads/asf-site by this push:
     new c071f5dd777 Publishing website 2022/07/09 22:20:23 at commit f641c24
c071f5dd777 is described below

commit c071f5dd777d2f34eaa3458e7e136d3011304581
Author: jenkins <bu...@apache.org>
AuthorDate: Sat Jul 9 22:20:23 2022 +0000

    Publishing website 2022/07/09 22:20:23 at commit f641c24
---
 website/generated-content/documentation/index.xml  | 644 ++++++++++++++++++++-
 .../documentation/programming-guide/index.html     | 478 ++++++++++++---
 website/generated-content/sitemap.xml              |   2 +-
 3 files changed, 1026 insertions(+), 98 deletions(-)

diff --git a/website/generated-content/documentation/index.xml b/website/generated-content/documentation/index.xml
index 16920ccfee8..9b91a7b9570 100644
--- a/website/generated-content/documentation/index.xml
+++ b/website/generated-content/documentation/index.xml
@@ -4216,10 +4216,12 @@ programming guide, take a look at the
 &lt;li data-type="language-java" class="active">Java SDK&lt;/li>
 &lt;li data-type="language-py">Python SDK&lt;/li>
 &lt;li data-type="language-go">Go SDK&lt;/li>
+&lt;li data-type="language-typescript">Typescript SDK&lt;/li>
 &lt;/ul>
 &lt;/nav>
 &lt;p class="language-py">The Python SDK supports Python 3.7, 3.8, and 3.9.&lt;/p>
 &lt;p class="language-go">The Go SDK supports Go v1.18+. SDK release 2.32.0 is the last experimental version.&lt;/p>
+&lt;p class="language-typescript">The Typescript SDK supports Node v16+ and is still experimental.&lt;/p>
 &lt;h2 id="overview">1. Overview&lt;/h2>
 &lt;p>To use Beam, you need to first create a driver program using the classes in one
 of the Beam SDKs. Your driver program &lt;em>defines&lt;/em> your pipeline, including all of
@@ -4307,6 +4309,10 @@ class &lt;code>Pipeline&lt;/code> (typically in the &lt;code>main()&lt;/code> fu
 your pipeline&amp;rsquo;s configuration options programmatically, but it&amp;rsquo;s often easier to
 set the options ahead of time (or read them from the command line) and pass them
 to the &lt;code>Pipeline&lt;/code> object when you create the object.&lt;/p>
+&lt;span class="language-typescript">
+A Pipeline in the Typescript API is simply a function that will be called
+with a single `root` object and is passed to a Runner's `run` method.
+&lt;/span>
 &lt;div class='language-java snippet'>
 &lt;div class="notebook-skip code-snippet">
 &lt;a class="copy" type="button" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Copy to clipboard">
@@ -4340,6 +4346,17 @@ to the &lt;code>Pipeline&lt;/code> object when you create the object.&lt;/p>
 &lt;/span>&lt;span class="c1">&lt;/span>&lt;span class="nx">pipeline&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">scope&lt;/span> &lt;span class="o">:=&lt;/span> &lt;span class="nx">beam&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">NewPipelineWithRoot&lt;/span>&lt;span class="p">()&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
 &lt;/div>
 &lt;/div>
+&lt;div class='language-typescript snippet'>
+&lt;div class="notebook-skip code-snippet">
+&lt;a class="copy" type="button" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Copy to clipboard">
+&lt;img src="/images/copy-icon.svg"/>
+&lt;/a>
+&lt;div class="highlight">&lt;pre class="chroma">&lt;code class="language-typescript" data-lang="typescript">&lt;span class="nx">await&lt;/span> &lt;span class="nx">beam&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">createRunner&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="nx">run&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kd">function&lt;/span> &lt;span class="nx">pipeline&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">root&lt;/span>&lt;s [...]
+&lt;span class="c1">// Use root to build a pipeline.
+&lt;/span>&lt;span class="c1">&lt;/span>&lt;span class="p">});&lt;/span>
+&lt;/code>&lt;/pre>&lt;/div>
+&lt;/div>
+&lt;/div>
 &lt;h3 id="configuring-pipeline-options">2.1. Configuring pipeline options&lt;/h3>
 &lt;p>Use the pipeline options to configure different aspects of your pipeline, such
 as the pipeline runner that will execute your pipeline and any runner-specific
@@ -4357,6 +4374,9 @@ you can use to set fields in &lt;code>PipelineOptions&lt;/code> using command-li
 as demonstrated in the following example code:&lt;/p>
 &lt;p class="language-go">Use Go flags to parse command line arguments to configure your pipeline. Flags must be parsed
 before &lt;code>beam.Init()&lt;/code> is called.&lt;/p>
+&lt;p class="language-typescript">Any Javascript object can be used as pipeline options.
+One can either construct one manually, but it is also common to pass an object
+created from command line options such as &lt;code>yargs.argv&lt;/code>.&lt;/p>
 &lt;div class='language-java snippet'>
 &lt;div class="notebook-skip code-snippet">
 &lt;a class="copy" type="button" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Copy to clipboard">
@@ -4385,6 +4405,20 @@ before &lt;code>beam.Init()&lt;/code> is called.&lt;/p>
 &lt;/span>&lt;span class="c1">&lt;/span>&lt;span class="nx">flag&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">Parse&lt;/span>&lt;span class="p">()&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
 &lt;/div>
 &lt;/div>
+&lt;div class='language-typescript snippet'>
+&lt;div class="notebook-skip code-snippet">
+&lt;a class="copy" type="button" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Copy to clipboard">
+&lt;img src="/images/copy-icon.svg"/>
+&lt;/a>
+&lt;div class="highlight">&lt;pre class="chroma">&lt;code class="language-typescript" data-lang="typescript">&lt;span class="kr">const&lt;/span> &lt;span class="nx">pipeline_options&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>
+&lt;span class="nx">runner&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;default&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
+&lt;span class="nx">project&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;my_project&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
+&lt;span class="p">};&lt;/span>
+&lt;span class="kr">const&lt;/span> &lt;span class="nx">runner&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">beam&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">createRunner&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">pipeline_options&lt;/span>&lt;span class="p">);&lt;/span>
+&lt;span class="kr">const&lt;/span> &lt;span class="nx">runnerFromCommandLineOptions&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">beam&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">createRunner&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">yargs&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">argv&lt;/span>&lt;span class="p">);&lt;/span>
+&lt;/code>&lt;/pre>&lt;/div>
+&lt;/div>
+&lt;/div>
 &lt;p>This interprets command-line arguments that follow the format:&lt;/p>
 &lt;pre>&lt;code>--&amp;lt;option&amp;gt;=&amp;lt;value&amp;gt;
 &lt;/code>&lt;/pre>&lt;span class="language-java">
@@ -4403,9 +4437,10 @@ options.&lt;/p>
 &lt;/blockquote>
 &lt;h4 id="creating-custom-options">2.1.2. Creating custom options&lt;/h4>
 &lt;p>You can add your own custom options in addition to the standard
-&lt;code>PipelineOptions&lt;/code>. To add your own options, define an interface with getter and
-setter methods for each option, as in the following example for
-adding &lt;code>input&lt;/code> and &lt;code>output&lt;/code> custom options:&lt;/p>
+&lt;code>PipelineOptions&lt;/code>.
+&lt;p class="language-java">To add your own options, define an interface with getter and
+setter methods for each option.&lt;/p>
+The following example shows how to add &lt;code>input&lt;/code> and &lt;code>output&lt;/code> custom options:&lt;/p>
 &lt;div class='language-java snippet'>
 &lt;div class="notebook-skip code-snippet">
 &lt;a class="copy" type="button" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Copy to clipboard">
@@ -4428,8 +4463,8 @@ adding &lt;code>input&lt;/code> and &lt;code>output&lt;/code> custom options:&lt
 &lt;span class="k">class&lt;/span> &lt;span class="nc">MyOptions&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">PipelineOptions&lt;/span>&lt;span class="p">):&lt;/span>
 &lt;span class="nd">@classmethod&lt;/span>
 &lt;span class="k">def&lt;/span> &lt;span class="nf">_add_argparse_args&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">cls&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">parser&lt;/span>&lt;span class="p">):&lt;/span>
-&lt;span class="n">parser&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">add_argument&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;--input-file&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
-&lt;span class="n">parser&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">add_argument&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;--output-path&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
+&lt;span class="n">parser&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">add_argument&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;--input&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
+&lt;span class="n">parser&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">add_argument&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;--output&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
 &lt;/div>
 &lt;/div>
 &lt;div class='language-go snippet'>
@@ -4444,9 +4479,20 @@ adding &lt;code>input&lt;/code> and &lt;code>output&lt;/code> custom options:&lt
 &lt;span class="p">)&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
 &lt;/div>
 &lt;/div>
+&lt;div class='language-typescript snippet'>
+&lt;div class="notebook-skip code-snippet">
+&lt;a class="copy" type="button" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Copy to clipboard">
+&lt;img src="/images/copy-icon.svg"/>
+&lt;/a>
+&lt;div class="highlight">&lt;pre class="chroma">&lt;code class="language-typescript" data-lang="typescript">&lt;span class="kr">const&lt;/span> &lt;span class="nx">options&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">yargs&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">argv&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// Or an alternative command-line parsing library.
+&lt;/span>&lt;span class="c1">&lt;/span>
+&lt;span class="c1">// Use options.input and options.output during pipeline construction.
+&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
+&lt;/div>
+&lt;/div>
 &lt;p>You can also specify a description, which appears when a user passes &lt;code>--help&lt;/code> as
 a command-line argument, and a default value.&lt;/p>
-&lt;p>You set the description and default value using annotations, as follows:&lt;/p>
+&lt;p class="language-java language-py langauge-go">You set the description and default value using annotations, as follows:&lt;/p>
 &lt;div class='language-java snippet'>
 &lt;div class="notebook-skip code-snippet">
 &lt;a class="copy" type="button" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Copy to clipboard">
@@ -4474,13 +4520,11 @@ a command-line argument, and a default value.&lt;/p>
 &lt;span class="nd">@classmethod&lt;/span>
 &lt;span class="k">def&lt;/span> &lt;span class="nf">_add_argparse_args&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">cls&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">parser&lt;/span>&lt;span class="p">):&lt;/span>
 &lt;span class="n">parser&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">add_argument&lt;/span>&lt;span class="p">(&lt;/span>
-&lt;span class="s1">&amp;#39;--input-file&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
+&lt;span class="s1">&amp;#39;--input&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
 &lt;span class="n">default&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;gs://dataflow-samples/shakespeare/kinglear.txt&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
 &lt;span class="n">help&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;The file path for the input text to process.&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
 &lt;span class="n">parser&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">add_argument&lt;/span>&lt;span class="p">(&lt;/span>
-&lt;span class="s1">&amp;#39;--output-path&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
-&lt;span class="n">required&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="bp">True&lt;/span>&lt;span class="p">,&lt;/span>
-&lt;span class="n">help&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;The path prefix for output files.&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
+&lt;span class="s1">&amp;#39;--output&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">required&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="bp">True&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">help&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;The path prefix for output files.&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
 &lt;/div>
 &lt;/div>
 &lt;div class='language-go snippet'>
@@ -4494,6 +4538,8 @@ a command-line argument, and a default value.&lt;/p>
 &lt;span class="p">)&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
 &lt;/div>
 &lt;/div>
+&lt;p class="language-py">For Python, you can also simply parse your custom options with argparse; there
+is no need to create a separate PipelineOptions subclass.&lt;/p>
 &lt;p class="language-java">It&amp;rsquo;s recommended that you register your interface with &lt;code>PipelineOptionsFactory&lt;/code>
 and then pass the interface when creating the &lt;code>PipelineOptions&lt;/code> object. When you
 register your interface with &lt;code>PipelineOptionsFactory&lt;/code>, the &lt;code>--help&lt;/code> can find
@@ -4543,12 +4589,16 @@ represent the data records in that source.&lt;/p>
 transform to the &lt;code>Pipeline&lt;/code> object itself.
 &lt;span class="language-java">&lt;code>TextIO.Read&lt;/code>&lt;/span>
 &lt;span class="language-py">&lt;code>io.TextFileSource&lt;/code>&lt;/span>
-&lt;span class="language-go">&lt;code>textio.Read&lt;/code>&lt;/span>, for example, reads from an
+&lt;span class="language-go">&lt;code>textio.Read&lt;/code>&lt;/span>
+&lt;span class="language-typescript">&lt;code>textio.ReadFromText&lt;/code>&lt;/span>,
+for example, reads from an
 external text file and returns a &lt;code>PCollection&lt;/code> whose elements are of type
 &lt;code>String&lt;/code>, each &lt;code>String&lt;/code> represents one line from the text file. Here&amp;rsquo;s how you
 would apply &lt;span class="language-java">&lt;code>TextIO.Read&lt;/code>&lt;/span>
 &lt;span class="language-py">&lt;code>io.TextFileSource&lt;/code>&lt;/span>
-&lt;span class="language-go">&lt;code>textio.Read&lt;/code>&lt;/span> to your &lt;code>Pipeline&lt;/code> to create
+&lt;span class="language-go">&lt;code>textio.Read&lt;/code>&lt;/span>
+&lt;span class="language-typescript">&lt;code>textio.ReadFromText&lt;/code>&lt;/span>
+to your &lt;code>Pipeline&lt;/code> &lt;span class="language-typescript">root&lt;/span> to create
 a &lt;code>PCollection&lt;/code>:&lt;/p>
 &lt;div class='language-java snippet'>
 &lt;div class="notebook-skip code-snippet">
@@ -4587,6 +4637,19 @@ a &lt;code>PCollection&lt;/code>:&lt;/p>
 &lt;/span>&lt;span class="c1">&lt;/span>&lt;span class="nx">lines&lt;/span> &lt;span class="o">:=&lt;/span> &lt;span class="nx">textio&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">Read&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">scope&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;gs://some/inputData.txt&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
 &lt;/div>
 &lt;/div>
+&lt;div class='language-go snippet'>
+&lt;div class="notebook-skip code-snippet">
+&lt;a class="copy" type="button" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Copy to clipboard">
+&lt;img src="/images/copy-icon.svg"/>
+&lt;/a>
+&lt;div class="highlight">&lt;pre class="chroma">&lt;code class="language-go" data-lang="go">&lt;span class="nx">async&lt;/span> &lt;span class="nx">function&lt;/span> &lt;span class="nf">pipeline&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">root&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nx">beam&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">Root&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
+&lt;span class="c1">// Note that textio.ReadFromText is an AsyncPTransform.
+&lt;/span>&lt;span class="c1">&lt;/span> &lt;span class="kd">const&lt;/span> &lt;span class="nx">pcoll&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nx">PCollection&lt;/span>&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="kt">string&lt;/span>&lt;span class="p">&amp;gt;&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nx">await&lt;/span> &lt;span class="nx">root&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">asyncApply&lt;/span>&lt;span class="p">(&lt;/span>
+&lt;span class="nx">textio&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">ReadFromText&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;path/to/text_pattern&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
+&lt;span class="p">);&lt;/span>
+&lt;span class="p">}&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
+&lt;/div>
+&lt;/div>
 &lt;p>See the &lt;a href="#pipeline-io">section on I/O&lt;/a> to learn more about how to read from the
 various data sources supported by the Beam SDK.&lt;/p>
 &lt;h4 id="creating-pcollection-in-memory">3.1.2. Creating a PCollection from in-memory data&lt;/h4>
@@ -4601,8 +4664,13 @@ Beam-provided &lt;code>Create&lt;/code> transform. Much like a data adapter&amp;
 itself.&lt;/p>
 &lt;p class="language-go">To create a &lt;code>PCollection&lt;/code> from an in-memory &lt;code>slice&lt;/code>, you use the Beam-provided
 &lt;code>beam.CreateList&lt;/code> transform. Pass the pipeline &lt;code>scope&lt;/code>, and the &lt;code>slice&lt;/code> to this transform.&lt;/p>
+&lt;p class="language-typescript">To create a &lt;code>PCollection&lt;/code> from an in-memory &lt;code>array&lt;/code>, you use the Beam-provided
+&lt;code>Create&lt;/code> transform. Apply this transform directly to your &lt;code>Root&lt;/code> object.&lt;/p>
 &lt;p>The following example code shows how to create a &lt;code>PCollection&lt;/code> from an in-memory
-&lt;span class="language-java">&lt;code>List&lt;/code>&lt;/span>&lt;span class="language-py">&lt;code>list&lt;/code>&lt;/span>&lt;span class="language-go">&lt;code>slice&lt;/code>&lt;/span>:&lt;/p>
+&lt;span class="language-java">&lt;code>List&lt;/code>&lt;/span>
+&lt;span class="language-py">&lt;code>list&lt;/code>&lt;/span>
+&lt;span class="language-go">&lt;code>slice&lt;/code>&lt;/span>
+&lt;span class="language-typescript">&lt;code>array&lt;/code>&lt;/span>:&lt;/p>
 &lt;div class='language-java snippet'>
 &lt;div class="notebook-skip code-snippet">
 &lt;a class="copy" type="button" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Copy to clipboard">
@@ -4662,6 +4730,24 @@ itself.&lt;/p>
 &lt;/span>&lt;span class="c1">&lt;/span>&lt;span class="nx">linesPCol&lt;/span> &lt;span class="o">:=&lt;/span> &lt;span class="nx">beam&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">CreateList&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">s&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">lines&lt;/span>&lt;span class="p">)&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
 &lt;/div>
 &lt;/div>
+&lt;div class='language-typescript snippet'>
+&lt;div class="notebook-skip code-snippet">
+&lt;a class="copy" type="button" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Copy to clipboard">
+&lt;img src="/images/copy-icon.svg"/>
+&lt;/a>
+&lt;div class="highlight">&lt;pre class="chroma">&lt;code class="language-typescript" data-lang="typescript">&lt;span class="kd">function&lt;/span> &lt;span class="nx">pipeline&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">root&lt;/span>: &lt;span class="kt">beam.Root&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
+&lt;span class="kr">const&lt;/span> &lt;span class="nx">pcoll&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">root&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">apply&lt;/span>&lt;span class="p">(&lt;/span>
+&lt;span class="nx">beam&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">create&lt;/span>&lt;span class="p">([&lt;/span>
+&lt;span class="s2">&amp;#34;To be, or not to be: that is the question: &amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
+&lt;span class="s2">&amp;#34;Whether &amp;#39;tis nobler in the mind to suffer &amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
+&lt;span class="s2">&amp;#34;The slings and arrows of outrageous fortune, &amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
+&lt;span class="s2">&amp;#34;Or to take arms against a sea of troubles, &amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
+&lt;span class="p">])&lt;/span>
+&lt;span class="p">);&lt;/span>
+&lt;span class="p">}&lt;/span>
+&lt;/code>&lt;/pre>&lt;/div>
+&lt;/div>
+&lt;/div>
 &lt;h3 id="pcollection-characteristics">3.2. PCollection characteristics&lt;/h3>
 &lt;p>A &lt;code>PCollection&lt;/code> is owned by the specific &lt;code>Pipeline&lt;/code> object for which it is
 created; multiple pipelines cannot share a &lt;code>PCollection&lt;/code>.
@@ -4793,7 +4879,17 @@ the transform itself as an argument, and the operation returns the output
 &lt;div class="highlight">&lt;pre class="chroma">&lt;code class="language-go" data-lang="go">&lt;span class="p">[&lt;/span>&lt;span class="nx">Output&lt;/span> &lt;span class="nx">PCollection&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">:=&lt;/span> &lt;span class="nx">beam&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">ParDo&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">scope&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">[&lt;/span>&lt [...]
 &lt;/div>
 &lt;/div>
-&lt;p class="language-java language-py">Because Beam uses a generic &lt;code>apply&lt;/code> method for &lt;code>PCollection&lt;/code>, you can both chain
+&lt;div class='language-typescript snippet'>
+&lt;div class="notebook-skip code-snippet">
+&lt;a class="copy" type="button" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Copy to clipboard">
+&lt;img src="/images/copy-icon.svg"/>
+&lt;/a>
+&lt;div class="highlight">&lt;pre class="chroma">&lt;code class="language-typescript" data-lang="typescript">&lt;span class="p">[&lt;/span>&lt;span class="nx">Output&lt;/span> &lt;span class="nx">PCollection&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="nx">Input&lt;/span> &lt;span class="nx">PCollection&lt;/span>&lt;span class="p">].&lt;/span>&lt;span class="nx">apply&lt;/span>&lt;span class="p">([&lt;/span>&lt;span  [...]
+&lt;span class="p">[&lt;/span>&lt;span class="nx">Output&lt;/span> &lt;span class="nx">PCollection&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">await&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="nx">Input&lt;/span> &lt;span class="nx">PCollection&lt;/span>&lt;span class="p">].&lt;/span>&lt;span class="nx">asyncApply&lt;/span>&lt;span class="p">([&lt;/span>&lt;span class="nx">AsyncTransform&lt;/span>&lt;span class="p">])&lt;/span>
+&lt;/code>&lt;/pre>&lt;/div>
+&lt;/div>
+&lt;/div>
+&lt;p class="language-java language-py language-typescript">Because Beam uses a generic &lt;code>apply&lt;/code> method for &lt;code>PCollection&lt;/code>, you can both chain
 transforms sequentially and also apply transforms that contain other transforms
 nested within (called &lt;a href="#composite-transforms">composite transforms&lt;/a> in the Beam
 SDKs).&lt;/p>
@@ -4841,6 +4937,17 @@ For example, you can successively call transforms on PCollections to modify the
 &lt;span class="p">[&lt;/span>&lt;span class="nx">Final&lt;/span> &lt;span class="nx">Output&lt;/span> &lt;span class="nx">PCollection&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">:=&lt;/span> &lt;span class="nx">beam&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">ParDo&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">scope&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="nx">Third&lt;/span> &lt;span class="nx">Tran [...]
 &lt;/div>
 &lt;/div>
+&lt;div class='language-typescript snippet'>
+&lt;div class="notebook-skip code-snippet">
+&lt;a class="copy" type="button" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Copy to clipboard">
+&lt;img src="/images/copy-icon.svg"/>
+&lt;/a>
+&lt;div class="highlight">&lt;pre class="chroma">&lt;code class="language-typescript" data-lang="typescript">&lt;span class="p">[&lt;/span>&lt;span class="nx">Final&lt;/span> &lt;span class="nx">Output&lt;/span> &lt;span class="nx">PCollection&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="nx">Initial&lt;/span> &lt;span class="nx">Input&lt;/span> &lt;span class="nx">PCollection&lt;/span>&lt;span class="p">].&lt;/span>& [...]
+&lt;span class="p">.&lt;/span>&lt;span class="nx">apply&lt;/span>&lt;span class="p">([&lt;/span>&lt;span class="nx">Second&lt;/span> &lt;span class="nx">Transform&lt;/span>&lt;span class="p">])&lt;/span>
+&lt;span class="p">.&lt;/span>&lt;span class="nx">apply&lt;/span>&lt;span class="p">([&lt;/span>&lt;span class="nx">Third&lt;/span> &lt;span class="nx">Transform&lt;/span>&lt;span class="p">])&lt;/span>
+&lt;/code>&lt;/pre>&lt;/div>
+&lt;/div>
+&lt;/div>
 &lt;p>The graph of this pipeline looks like the following:&lt;/p>
 &lt;p>&lt;img src="/images/design-your-pipeline-linear.svg" alt="This linear pipeline starts with one input collection, sequentially appliesthree transforms, and ends with one output collection.">&lt;/p>
 &lt;p>&lt;em>Figure 1: A linear pipeline with three sequential transforms.&lt;/em>&lt;/p>
@@ -4878,6 +4985,17 @@ a branching pipeline, like so:&lt;/p>
 &lt;span class="p">[&lt;/span>&lt;span class="nx">PCollection&lt;/span> &lt;span class="nx">of&lt;/span> &lt;span class="sc">&amp;#39;B&amp;#39;&lt;/span> &lt;span class="nx">names&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nx">beam&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">ParDo&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">scope&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class= [...]
 &lt;/div>
 &lt;/div>
+&lt;div class='language-typescript snippet'>
+&lt;div class="notebook-skip code-snippet">
+&lt;a class="copy" type="button" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Copy to clipboard">
+&lt;img src="/images/copy-icon.svg"/>
+&lt;/a>
+&lt;div class="highlight">&lt;pre class="chroma">&lt;code class="language-typescript" data-lang="typescript">&lt;span class="p">[&lt;/span>&lt;span class="nx">PCollection&lt;/span> &lt;span class="nx">of&lt;/span> &lt;span class="nx">database&lt;/span> &lt;span class="nx">table&lt;/span> &lt;span class="nx">rows&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="nx">Database&lt;/span> &lt;span class="nx">Table&lt;/span> &l [...]
+&lt;span class="p">[&lt;/span>&lt;span class="nx">PCollection&lt;/span> &lt;span class="nx">of&lt;/span> &lt;span class="s1">&amp;#39;A&amp;#39;&lt;/span> &lt;span class="nx">names&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="nx">PCollection&lt;/span> &lt;span class="nx">of&lt;/span> &lt;span class="nx">database&lt;/span> &lt;span class="nx">table&lt;/span> &lt;span class="nx">rows&lt;/span>&lt;span class="p">].&lt;/ [...]
+&lt;span class="p">[&lt;/span>&lt;span class="nx">PCollection&lt;/span> &lt;span class="nx">of&lt;/span> &lt;span class="s1">&amp;#39;B&amp;#39;&lt;/span> &lt;span class="nx">names&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="nx">PCollection&lt;/span> &lt;span class="nx">of&lt;/span> &lt;span class="nx">database&lt;/span> &lt;span class="nx">table&lt;/span> &lt;span class="nx">rows&lt;/span>&lt;span class="p">].&lt;/ [...]
+&lt;/code>&lt;/pre>&lt;/div>
+&lt;/div>
+&lt;/div>
 &lt;p>The graph of this branching pipeline looks like the following:&lt;/p>
 &lt;p>&lt;img src="/images/design-your-pipeline-multiple-pcollections.svg" alt="This pipeline applies two transforms to a single input collection. Eachtransform produces an output collection.">&lt;/p>
 &lt;p>&lt;em>Figure 2: A branching pipeline. Two transforms are applied to a single
@@ -4886,6 +5004,18 @@ PCollection of database table rows.&lt;/em>&lt;/p>
 nest multiple transforms inside a single, larger transform. Composite transforms
 are particularly useful for building a reusable sequence of simple steps that
 get used in a lot of different places.&lt;/p>
+&lt;p class="language-python">The pipe syntax allows one to apply PTransforms to &lt;code>tuple&lt;/code>s and &lt;code>dict&lt;/code>s of
+PCollections as well for those transforms accepting multiple inputs (such as
+&lt;code>Flatten&lt;/code> and &lt;code>CoGroupByKey&lt;/code>).&lt;/p>
+&lt;p class="language-typescript">PTransforms can also be applied to any &lt;code>PValue&lt;/code>, which include the Root object,
+PCollections, arrays of &lt;code>PValue&lt;/code>s, and objects with &lt;code>PValue&lt;/code> values.
+One can apply transforms to these composite types by wrapping them with
+&lt;code>beam.P&lt;/code>, e.g.
+&lt;code>beam.P({left: pcollA, right: pcollB}).apply(transformExpectingTwoPCollections)&lt;/code>.&lt;/p>
+&lt;p class="language-typescript">PTransforms come in two flavors, synchronous and asynchronous, depending on
+whether their &lt;em>application&lt;/em>* involves asynchronous invocations.
+An &lt;code>AsyncTransform&lt;/code> must be applied with &lt;code>asyncApply&lt;/code> and returns a &lt;code>Promise&lt;/code>
+which must be awaited before further pipeline construction.&lt;/p>
 &lt;h3 id="core-beam-transforms">4.2. Core Beam transforms&lt;/h3>
 &lt;p>Beam provides the following core transforms, each of which represents a different
 processing paradigm:&lt;/p>
@@ -4897,6 +5027,8 @@ processing paradigm:&lt;/p>
 &lt;li>&lt;code>Flatten&lt;/code>&lt;/li>
 &lt;li>&lt;code>Partition&lt;/code>&lt;/li>
 &lt;/ul>
+&lt;p class="language-typescript">The Typescript SDK provides some of the most basic of these transforms
+as methods on &lt;code>PCollection&lt;/code> itself.&lt;/p>
 &lt;h4 id="pardo">4.2.1. ParDo&lt;/h4>
 &lt;p>&lt;code>ParDo&lt;/code> is a Beam transform for generic parallel processing. The &lt;code>ParDo&lt;/code>
 processing paradigm is similar to the &amp;ldquo;Map&amp;rdquo; phase of a
@@ -5021,6 +5153,25 @@ as shown in the following example code:&lt;/p>
 &lt;span class="nx">wordLengths&lt;/span> &lt;span class="o">:=&lt;/span> &lt;span class="nx">beam&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">ParDo&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">s&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">&amp;amp;&lt;/span>&lt;span class="nx">ComputeWordLengthFn&lt;/span>&lt;span class="p">{},&lt;/span> &lt;span class="nx">words&lt;/span>&lt;span class="p">)&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
 &lt;/div>
 &lt;/div>
+&lt;div class='language-typescript snippet'>
+&lt;div class="notebook-skip code-snippet">
+&lt;a class="copy" type="button" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Copy to clipboard">
+&lt;img src="/images/copy-icon.svg"/>
+&lt;/a>
+&lt;div class="highlight">&lt;pre class="chroma">&lt;code class="language-typescript" data-lang="typescript">&lt;span class="err">#&lt;/span> &lt;span class="nx">The&lt;/span> &lt;span class="nx">input&lt;/span> &lt;span class="nx">PCollection&lt;/span> &lt;span class="nx">of&lt;/span> &lt;span class="nx">Strings&lt;/span>&lt;span class="p">.&lt;/span>
+&lt;span class="kr">const&lt;/span> &lt;span class="nx">words&lt;/span> : &lt;span class="kt">PCollection&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">string&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">...&lt;/span>
+&lt;span class="err">#&lt;/span> &lt;span class="nx">The&lt;/span> &lt;span class="nx">DoFn&lt;/span> &lt;span class="nx">to&lt;/span> &lt;span class="nx">perform&lt;/span> &lt;span class="nx">on&lt;/span> &lt;span class="nx">each&lt;/span> &lt;span class="nx">element&lt;/span> &lt;span class="k">in&lt;/span> &lt;span class="nx">the&lt;/span> &lt;span class="nx">input&lt;/span> &lt;span class="nx">PCollection&lt;/span>&lt;span class="p">.&lt;/span>
+&lt;span class="kd">function&lt;/span> &lt;span class="nx">computeWordLengthFn&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="nx">beam&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">DoFn&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">string&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">number&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="p">{&lt;/span>
+&lt;span class="k">return&lt;/span> &lt;span class="p">{&lt;/span>
+&lt;span class="nx">process&lt;/span>: &lt;span class="kt">function&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nx">element&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
+&lt;span class="nx">yield&lt;/span> &lt;span class="nx">element&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">length&lt;/span>&lt;span class="p">;&lt;/span>
+&lt;span class="p">},&lt;/span>
+&lt;span class="p">};&lt;/span>
+&lt;span class="p">}&lt;/span>
+&lt;span class="kr">const&lt;/span> &lt;span class="nx">result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">words&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">apply&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">beam&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">parDo&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">computeWordLengthFn&lt;/span>&lt;span class="p">()));&lt;/span>
+&lt;/code>&lt;/pre>&lt;/div>
+&lt;/div>
+&lt;/div>
 &lt;p>In the example, our input &lt;code>PCollection&lt;/code> contains &lt;span class="language-java language-py">&lt;code>String&lt;/code>&lt;/span>
 &lt;span class="language-go">&lt;code>string&lt;/code>&lt;/span> values. We apply a
 &lt;code>ParDo&lt;/code> transform that specifies a function (&lt;code>ComputeWordLengthFn&lt;/code>) to compute
@@ -5089,7 +5240,7 @@ provides a method for emitting elements. The parameter types must match the inpu
 and output types of your &lt;code>DoFn&lt;/code> or the framework will raise an error. Note: &lt;code>@Element&lt;/code> and
 &lt;code>OutputReceiver&lt;/code> were introduced in Beam 2.5.0; if using an earlier release of Beam, a
 &lt;code>ProcessContext&lt;/code> parameter should be used instead.&lt;/p>
-&lt;p class="language-py">Inside your &lt;code>DoFn&lt;/code> subclass, you&amp;rsquo;ll write a method &lt;code>process&lt;/code> where you provide
+&lt;p class="language-py language-typescript">Inside your &lt;code>DoFn&lt;/code> subclass, you&amp;rsquo;ll write a method &lt;code>process&lt;/code> where you provide
 the actual processing logic. You don&amp;rsquo;t need to manually extract the elements
 from the input collection; the Beam SDKs handle that for you. Your &lt;code>process&lt;/code> method
 should accept an argument &lt;code>element&lt;/code>, which is the input element, and return an
@@ -5149,6 +5300,21 @@ or the framework will raise an error.&lt;/p>
 &lt;span class="p">}&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
 &lt;/div>
 &lt;/div>
+&lt;div class='language-typescript snippet'>
+&lt;div class="notebook-skip code-snippet">
+&lt;a class="copy" type="button" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Copy to clipboard">
+&lt;img src="/images/copy-icon.svg"/>
+&lt;/a>
+&lt;div class="highlight">&lt;pre class="chroma">&lt;code class="language-typescript" data-lang="typescript">&lt;span class="kd">function&lt;/span> &lt;span class="nx">computeWordLengthFn&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="nx">beam&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">DoFn&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">string&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">number&lt;/ [...]
+&lt;span class="k">return&lt;/span> &lt;span class="p">{&lt;/span>
+&lt;span class="nx">process&lt;/span>: &lt;span class="kt">function&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nx">element&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
+&lt;span class="nx">yield&lt;/span> &lt;span class="nx">element&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">length&lt;/span>&lt;span class="p">;&lt;/span>
+&lt;span class="p">},&lt;/span>
+&lt;span class="p">};&lt;/span>
+&lt;span class="p">}&lt;/span>
+&lt;/code>&lt;/pre>&lt;/div>
+&lt;/div>
+&lt;/div>
 &lt;p class="language-go">Simple DoFns can also be written as functions.&lt;/p>
 &lt;div class='language-go snippet'>
 &lt;div class="notebook-skip code-snippet">
@@ -5205,7 +5371,7 @@ elements from the input collection).&lt;/li>
 that value in any way.&lt;/li>
 &lt;/ul>
 &lt;/span>
-&lt;span class="language-py">
+&lt;span class="language-py language-typescript">
 &lt;ul>
 &lt;li>You should not in any way modify the &lt;code>element&lt;/code> argument provided to the
 &lt;code>process&lt;/code> method, or any side inputs.&lt;/li>
@@ -5226,12 +5392,14 @@ that value in any way.&lt;/li>
 &lt;code>ParDo&lt;/code> by providing a lightweight &lt;code>DoFn&lt;/code> in-line, as
 &lt;span class="language-java">an anonymous inner class instance&lt;/span>
 &lt;span class="language-py">a lambda function&lt;/span>
-&lt;span class="language-go">an anonymous function&lt;/span>.&lt;/p>
+&lt;span class="language-go">an anonymous function&lt;/span>
+&lt;span class="language-typescript">a function passed to &lt;code>PCollection.map&lt;/code> or &lt;code>PCollection.flatMap&lt;/code>&lt;/span>.&lt;/p>
 &lt;p>Here&amp;rsquo;s the previous example, &lt;code>ParDo&lt;/code> with &lt;code>ComputeLengthWordsFn&lt;/code>, with the
 &lt;code>DoFn&lt;/code> specified as
 &lt;span class="language-java">an anonymous inner class instance&lt;/span>
 &lt;span class="language-py">a lambda function&lt;/span>
-&lt;span class="language-go">an anonymous function&lt;/span>:&lt;/p>
+&lt;span class="language-go">an anonymous function&lt;/span>
+&lt;span class="language-typescript">a function&lt;/span>:&lt;/p>
 &lt;div class='language-java snippet'>
 &lt;div class="notebook-skip code-snippet">
 &lt;a class="copy" type="button" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Copy to clipboard">
@@ -5275,15 +5443,26 @@ that value in any way.&lt;/li>
 &lt;span class="p">},&lt;/span> &lt;span class="nx">words&lt;/span>&lt;span class="p">)&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
 &lt;/div>
 &lt;/div>
+&lt;div class='language-typescript snippet'>
+&lt;div class="notebook-skip code-snippet">
+&lt;a class="copy" type="button" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Copy to clipboard">
+&lt;img src="/images/copy-icon.svg"/>
+&lt;/a>
+&lt;div class="highlight">&lt;pre class="chroma">&lt;code class="language-typescript" data-lang="typescript">&lt;span class="c1">// The input PCollection of strings.
+&lt;/span>&lt;span class="c1">&lt;/span>&lt;span class="nx">words&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">...&lt;/span>
+&lt;span class="kr">const&lt;/span> &lt;span class="nx">result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">words&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">flatMap&lt;/span>&lt;span class="p">((&lt;/span>&lt;span class="nx">word&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">=&amp;gt;&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="nx">word&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">length&lt;/span>&lt;span class="p">]) [...]
+&lt;/code>&lt;/pre>&lt;/div>
+&lt;/div>
+&lt;/div>
 &lt;p>If your &lt;code>ParDo&lt;/code> performs a one-to-one mapping of input elements to output
 elements&amp;ndash;that is, for each input element, it applies a function that produces
 &lt;em>exactly one&lt;/em> output element, &lt;span class="language-go">you can return that
 element directly.&lt;/span>&lt;span class="language-java language-py">you can use the higher-level
-&lt;span class="language-java">&lt;code>MapElements&lt;/code>&lt;/span>&lt;span class="language-py">&lt;code>Map&lt;/code>&lt;/span>
+&lt;span class="language-java">&lt;code>MapElements&lt;/code>&lt;/span>&lt;span class="language-py language-py">&lt;code>Map&lt;/code>&lt;/span>
 transform.&lt;/span>&lt;span class="language-java">&lt;code>MapElements&lt;/code> can accept an anonymous
 Java 8 lambda function for additional brevity.&lt;/span>&lt;/p>
 &lt;p>Here&amp;rsquo;s the previous example using &lt;span class="language-java">&lt;code>MapElements&lt;/code>&lt;/span>
-&lt;span class="language-py">&lt;code>Map&lt;/code>&lt;/span>&lt;span class="language-go">a direct return&lt;/span>:&lt;/p>
+&lt;span class="language-py language-typescript">&lt;code>Map&lt;/code>&lt;/span>&lt;span class="language-go">a direct return&lt;/span>:&lt;/p>
 &lt;div class='language-java snippet'>
 &lt;div class="notebook-skip code-snippet">
 &lt;a class="copy" type="button" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Copy to clipboard">
@@ -5324,6 +5503,17 @@ Java 8 lambda function for additional brevity.&lt;/span>&lt;/p>
 &lt;span class="p">},&lt;/span> &lt;span class="nx">words&lt;/span>&lt;span class="p">)&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
 &lt;/div>
 &lt;/div>
+&lt;div class='language-typescript snippet'>
+&lt;div class="notebook-skip code-snippet">
+&lt;a class="copy" type="button" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Copy to clipboard">
+&lt;img src="/images/copy-icon.svg"/>
+&lt;/a>
+&lt;div class="highlight">&lt;pre class="chroma">&lt;code class="language-typescript" data-lang="typescript">&lt;span class="c1">// The input PCollection of string.
+&lt;/span>&lt;span class="c1">&lt;/span>&lt;span class="nx">words&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">...&lt;/span>
+&lt;span class="kr">const&lt;/span> &lt;span class="nx">result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">words&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">map&lt;/span>&lt;span class="p">((&lt;/span>&lt;span class="nx">word&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">=&amp;gt;&lt;/span> &lt;span class="nx">word&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">length&lt;/span>&lt;span class="p">);&lt;/span>
+&lt;/code>&lt;/pre>&lt;/div>
+&lt;/div>
+&lt;/div>
 &lt;p>&lt;span class="language-java" >&lt;/p>
 &lt;blockquote>
 &lt;p>&lt;strong>Note:&lt;/strong> You can use Java 8 lambda functions with several other Beam
@@ -5390,6 +5580,11 @@ tree, [2]
 &lt;/code>&lt;/pre>&lt;p>Thus, &lt;code>GroupByKey&lt;/code> represents a transform from a multimap (multiple keys to
 individual values) to a uni-map (unique keys to collections of values).&lt;/p>
 &lt;p>&lt;span class="language-java">Using &lt;code>GroupByKey&lt;/code> is straightforward:&lt;/span>&lt;/p>
+&lt;p class="language-py language-typescript">While all SDKs have a &lt;code>GroupByKey&lt;/code> transform, using &lt;code>GroupBy&lt;/code> is
+generally more natural.
+The &lt;code>GroupBy&lt;/code> transform can be parameterized by the name(s) of properties
+on which to group the elements of the PCollection, or a function taking
+the each element as input that maps to a key on which to do grouping.&lt;/p>
 &lt;div class='language-java snippet'>
 &lt;div class="notebook-skip code-snippet">
 &lt;a class="copy" type="button" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Copy to clipboard">
@@ -5403,6 +5598,16 @@ individual values) to a uni-map (unique keys to collections of values).&lt;/p>
 &lt;span class="n">mapped&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">apply&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">GroupByKey&lt;/span>&lt;span class="o">.&amp;lt;&lt;/span>&lt;span class="n">String&lt;/span>&lt;span class="o">,&lt;/span> &lt;span class="n">String&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="n">create&lt;/span>&lt;span class="o">());&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
 &lt;/div>
 &lt;/div>
+&lt;div class='language-py snippet'>
+&lt;div class="notebook-skip code-snippet">
+&lt;a class="copy" type="button" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Copy to clipboard">
+&lt;img src="/images/copy-icon.svg"/>
+&lt;/a>
+&lt;div class="highlight">&lt;pre class="chroma">&lt;code class="language-py" data-lang="py">&lt;span class="c1"># The input PCollection of (`string`, `int`) tuples.&lt;/span>
+&lt;span class="n">words_and_counts&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">...&lt;/span>
+&lt;span class="n">grouped_words&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">words_and_counts&lt;/span> &lt;span class="o">|&lt;/span> &lt;span class="n">beam&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">GroupByKey&lt;/span>&lt;span class="p">()&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
+&lt;/div>
+&lt;/div>
 &lt;div class='language-go snippet'>
 &lt;div class="notebook-skip code-snippet">
 &lt;a class="copy" type="button" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Copy to clipboard">
@@ -5414,6 +5619,27 @@ individual values) to a uni-map (unique keys to collections of values).&lt;/p>
 &lt;span class="nx">keyed&lt;/span> &lt;span class="o">:=&lt;/span> &lt;span class="nx">beam&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">GroupByKey&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">s&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">pairs&lt;/span>&lt;span class="p">)&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
 &lt;/div>
 &lt;/div>
+&lt;div class='language-typescript snippet'>
+&lt;div class="notebook-skip code-snippet">
+&lt;a class="copy" type="button" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Copy to clipboard">
+&lt;img src="/images/copy-icon.svg"/>
+&lt;/a>
+&lt;div class="highlight">&lt;pre class="chroma">&lt;code class="language-typescript" data-lang="typescript">&lt;span class="c1">// A PCollection of elements like
+&lt;/span>&lt;span class="c1">// {word: &amp;#34;cat&amp;#34;, score: 1}, {word: &amp;#34;dog&amp;#34;, score: 5}, {word: &amp;#34;cat&amp;#34;, score: 5}, ...
+&lt;/span>&lt;span class="c1">&lt;/span>&lt;span class="kr">const&lt;/span> &lt;span class="nx">scores&lt;/span> : &lt;span class="kt">PCollection&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="nx">word&lt;/span>: &lt;span class="kt">string&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">score&lt;/span>: &lt;span class="kt">number&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="o">=&lt;/ [...]
+&lt;span class="c1">// This will produce a PCollection with elements like
+&lt;/span>&lt;span class="c1">// {key: &amp;#34;cat&amp;#34;, value: [{ word: &amp;#34;cat&amp;#34;, score: 1 },
+&lt;/span>&lt;span class="c1">// { word: &amp;#34;cat&amp;#34;, score: 5 }, ...]}
+&lt;/span>&lt;span class="c1">// {key: &amp;#34;dog&amp;#34;, value: [{ word: &amp;#34;dog&amp;#34;, score: 5 }, ...]}
+&lt;/span>&lt;span class="c1">&lt;/span>&lt;span class="kr">const&lt;/span> &lt;span class="nx">grouped_by_word&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">scores&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">apply&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">beam&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">groupBy&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;word&amp;#34;&lt;/span>&lt;span class="p">));&lt;/span>
+&lt;span class="c1">// This will produce a PCollection with elements like
+&lt;/span>&lt;span class="c1">// {key: 3, value: [{ word: &amp;#34;cat&amp;#34;, score: 1 },
+&lt;/span>&lt;span class="c1">// { word: &amp;#34;dog&amp;#34;, score: 5 },
+&lt;/span>&lt;span class="c1">// { word: &amp;#34;cat&amp;#34;, score: 5 }, ...]}
+&lt;/span>&lt;span class="c1">&lt;/span>&lt;span class="kr">const&lt;/span> &lt;span class="nx">by_word_length&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">scores&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">apply&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">beam&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">groupBy&lt;/span>&lt;span class="p">((&lt;/span>&lt;span class="nx">x&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class= [...]
+&lt;/code>&lt;/pre>&lt;/div>
+&lt;/div>
+&lt;/div>
 &lt;h5 id="groupbykey-and-unbounded-pcollections">4.2.2.1 GroupByKey and unbounded PCollections&lt;/h5>
 &lt;p>If you are using unbounded &lt;code>PCollection&lt;/code>s, you must use either &lt;a href="#setting-your-pcollections-windowing-function">non-global
 windowing&lt;/a> or an
@@ -5557,6 +5783,28 @@ data contains names and phone numbers.&lt;/p>
 &lt;span class="nx">phones&lt;/span> &lt;span class="o">:=&lt;/span> &lt;span class="nf">CreateAndSplit&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">s&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">Scope&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;CreatePhones&amp;#34;&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="nx">phoneSlice&lt;/span>&lt;span class="p">)&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
 &lt;/div>
 &lt;/div>
+&lt;div class='language-typescript snippet'>
+&lt;div class="notebook-skip code-snippet">
+&lt;a class="copy" type="button" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Copy to clipboard">
+&lt;img src="/images/copy-icon.svg"/>
+&lt;/a>
+&lt;div class="highlight">&lt;pre class="chroma">&lt;code class="language-typescript" data-lang="typescript">&lt;span class="kr">const&lt;/span> &lt;span class="nx">emails_list&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>
+&lt;span class="p">{&lt;/span> &lt;span class="nx">name&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;amy&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">email&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;amy@example.com&amp;#34;&lt;/span> &lt;span class="p">},&lt;/span>
+&lt;span class="p">{&lt;/span> &lt;span class="nx">name&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;carl&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">email&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;carl@example.com&amp;#34;&lt;/span> &lt;span class="p">},&lt;/span>
+&lt;span class="p">{&lt;/span> &lt;span class="nx">name&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;julia&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">email&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;julia@example.com&amp;#34;&lt;/span> &lt;span class="p">},&lt;/span>
+&lt;span class="p">{&lt;/span> &lt;span class="nx">name&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;carl&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">email&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;carl@email.com&amp;#34;&lt;/span> &lt;span class="p">},&lt;/span>
+&lt;span class="p">];&lt;/span>
+&lt;span class="kr">const&lt;/span> &lt;span class="nx">phones_list&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>
+&lt;span class="p">{&lt;/span> &lt;span class="nx">name&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;amy&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">phone&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;111-222-3333&amp;#34;&lt;/span> &lt;span class="p">},&lt;/span>
+&lt;span class="p">{&lt;/span> &lt;span class="nx">name&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;james&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">phone&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;222-333-4444&amp;#34;&lt;/span> &lt;span class="p">},&lt;/span>
+&lt;span class="p">{&lt;/span> &lt;span class="nx">name&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;amy&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">phone&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;333-444-5555&amp;#34;&lt;/span> &lt;span class="p">},&lt;/span>
+&lt;span class="p">{&lt;/span> &lt;span class="nx">name&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;carl&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">phone&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;444-555-6666&amp;#34;&lt;/span> &lt;span class="p">},&lt;/span>
+&lt;span class="p">];&lt;/span>
+&lt;span class="kr">const&lt;/span> &lt;span class="nx">emails&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">root&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">apply&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">beam&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">create&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">emails_list&lt;/span>&lt;span class="p">));&lt;/span>
+&lt;span class="kr">const&lt;/span> &lt;span class="nx">phones&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">root&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">apply&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">beam&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">create&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">phones_list&lt;/span>&lt;span class="p">));&lt;/span>
+&lt;/code>&lt;/pre>&lt;/div>
+&lt;/div>
+&lt;/div>
 &lt;p>After &lt;code>CoGroupByKey&lt;/code>, the resulting data contains all data associated with each
 unique key from any of the input collections.&lt;/p>
 &lt;div class='language-java snippet'>
@@ -5645,7 +5893,51 @@ unique key from any of the input collections.&lt;/p>
 &lt;span class="p">}&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
 &lt;/div>
 &lt;/div>
-&lt;p class="language-java language-py">The following code example joins the two &lt;code>PCollection&lt;/code>s with &lt;code>CoGroupByKey&lt;/code>,
+&lt;div class='language-typescript snippet'>
+&lt;div class="notebook-skip code-snippet">
+&lt;a class="copy" type="button" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Copy to clipboard">
+&lt;img src="/images/copy-icon.svg"/>
+&lt;/a>
+&lt;div class="highlight">&lt;pre class="chroma">&lt;code class="language-typescript" data-lang="typescript">&lt;span class="kr">const&lt;/span> &lt;span class="nx">results&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>
+&lt;span class="p">{&lt;/span>
+&lt;span class="nx">name&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;amy&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
+&lt;span class="nx">values&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">{&lt;/span>
+&lt;span class="nx">emails&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">[{&lt;/span> &lt;span class="nx">name&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;amy&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">email&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;amy@example.com&amp;#34;&lt;/span> &lt;span class="p">}],&lt;/span>
+&lt;span class="nx">phones&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">[&lt;/span>
+&lt;span class="p">{&lt;/span> &lt;span class="nx">name&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;amy&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">phone&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;111-222-3333&amp;#34;&lt;/span> &lt;span class="p">},&lt;/span>
+&lt;span class="p">{&lt;/span> &lt;span class="nx">name&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;amy&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">phone&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;333-444-5555&amp;#34;&lt;/span> &lt;span class="p">},&lt;/span>
+&lt;span class="p">],&lt;/span>
+&lt;span class="p">},&lt;/span>
+&lt;span class="p">},&lt;/span>
+&lt;span class="p">{&lt;/span>
+&lt;span class="nx">name&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;carl&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
+&lt;span class="nx">values&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">{&lt;/span>
+&lt;span class="nx">emails&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">[&lt;/span>
+&lt;span class="p">{&lt;/span> &lt;span class="nx">name&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;carl&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">email&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;carl@example.com&amp;#34;&lt;/span> &lt;span class="p">},&lt;/span>
+&lt;span class="p">{&lt;/span> &lt;span class="nx">name&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;carl&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">email&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;carl@email.com&amp;#34;&lt;/span> &lt;span class="p">},&lt;/span>
+&lt;span class="p">],&lt;/span>
+&lt;span class="nx">phones&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">[{&lt;/span> &lt;span class="nx">name&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;carl&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">phone&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;444-555-6666&amp;#34;&lt;/span> &lt;span class="p">}],&lt;/span>
+&lt;span class="p">},&lt;/span>
+&lt;span class="p">},&lt;/span>
+&lt;span class="p">{&lt;/span>
+&lt;span class="nx">name&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;james&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
+&lt;span class="nx">values&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">{&lt;/span>
+&lt;span class="nx">emails&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">[],&lt;/span>
+&lt;span class="nx">phones&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">[{&lt;/span> &lt;span class="nx">name&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;james&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">phone&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;222-333-4444&amp;#34;&lt;/span> &lt;span class="p">}],&lt;/span>
+&lt;span class="p">},&lt;/span>
+&lt;span class="p">},&lt;/span>
+&lt;span class="p">{&lt;/span>
+&lt;span class="nx">name&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;julia&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
+&lt;span class="nx">values&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">{&lt;/span>
+&lt;span class="nx">emails&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">[{&lt;/span> &lt;span class="nx">name&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;julia&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">email&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;julia@example.com&amp;#34;&lt;/span> &lt;span class="p">}],&lt;/span>
+&lt;span class="nx">phones&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">[],&lt;/span>
+&lt;span class="p">},&lt;/span>
+&lt;span class="p">},&lt;/span>
+&lt;span class="p">];&lt;/span>
+&lt;/code>&lt;/pre>&lt;/div>
+&lt;/div>
+&lt;/div>
+&lt;p class="language-java language-py language-typescript">The following code example joins the two &lt;code>PCollection&lt;/code>s with &lt;code>CoGroupByKey&lt;/code>,
 followed by a &lt;code>ParDo&lt;/code> to consume the result. Then, the code uses tags to look up
 and format data from each collection.&lt;/p>
 &lt;p class="language-go">The following code example joins the two &lt;code>PCollection&lt;/code>s with &lt;code>CoGroupByKey&lt;/code>,
@@ -5744,6 +6036,22 @@ parameters maps to the ordering of the &lt;code>CoGroupByKey&lt;/code> inputs.&l
 &lt;span class="p">}&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
 &lt;/div>
 &lt;/div>
+&lt;div class='language-typescript snippet'>
+&lt;div class="notebook-skip code-snippet">
+&lt;a class="copy" type="button" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Copy to clipboard">
+&lt;img src="/images/copy-icon.svg"/>
+&lt;/a>
+&lt;div class="highlight">&lt;pre class="chroma">&lt;code class="language-typescript" data-lang="typescript">&lt;span class="kr">const&lt;/span> &lt;span class="nx">formatted_results_pcoll&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">beam&lt;/span>
+&lt;span class="p">.&lt;/span>&lt;span class="nx">P&lt;/span>&lt;span class="p">({&lt;/span> &lt;span class="nx">emails&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">phones&lt;/span> &lt;span class="p">})&lt;/span>
+&lt;span class="p">.&lt;/span>&lt;span class="nx">apply&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">beam&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">coGroupBy&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">))&lt;/span>
+&lt;span class="p">.&lt;/span>&lt;span class="nx">map&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kd">function&lt;/span> &lt;span class="nx">formatResults&lt;/span>&lt;span class="p">({&lt;/span> &lt;span class="nx">key&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">values&lt;/span> &lt;span class="p">})&lt;/span> &lt;span class="p">{&lt;/span>
+&lt;span class="kr">const&lt;/span> &lt;span class="nx">emails&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">values&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">emails&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">map&lt;/span>&lt;span class="p">((&lt;/span>&lt;span class="nx">x&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">=&amp;gt;&lt;/span> &lt;span class="nx">x&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">email&lt;/ [...]
+&lt;span class="kr">const&lt;/span> &lt;span class="nx">phones&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">values&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">phones&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">map&lt;/span>&lt;span class="p">((&lt;/span>&lt;span class="nx">x&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">=&amp;gt;&lt;/span> &lt;span class="nx">x&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">phone&lt;/ [...]
+&lt;span class="k">return&lt;/span> &lt;span class="sb">`&lt;/span>&lt;span class="si">${&lt;/span>&lt;span class="nx">key&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="sb">; [&lt;/span>&lt;span class="si">${&lt;/span>&lt;span class="nx">emails&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="sb">]; [&lt;/span>&lt;span class="si">${&lt;/span>&lt;span class="nx">phones&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="sb">]`&lt;/span>&lt;span class="p">;&lt;/span>
+&lt;span class="p">});&lt;/span>
+&lt;/code>&lt;/pre>&lt;/div>
+&lt;/div>
+&lt;/div>
 &lt;p>The formatted data looks like this:&lt;/p>
 &lt;div class='language-java snippet'>
 &lt;div class="notebook-skip code-snippet">
@@ -5784,10 +6092,25 @@ parameters maps to the ordering of the &lt;code>CoGroupByKey&lt;/code> inputs.&l
 &lt;span class="p">}&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
 &lt;/div>
 &lt;/div>
+&lt;div class='language-typescript snippet'>
+&lt;div class="notebook-skip code-snippet">
+&lt;a class="copy" type="button" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Copy to clipboard">
+&lt;img src="/images/copy-icon.svg"/>
+&lt;/a>
+&lt;div class="highlight">&lt;pre class="chroma">&lt;code class="language-typescript" data-lang="typescript">&lt;span class="kr">const&lt;/span> &lt;span class="nx">formatted_results&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>
+&lt;span class="s2">&amp;#34;amy; [amy@example.com]; [111-222-3333,333-444-5555]&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
+&lt;span class="s2">&amp;#34;carl; [carl@email.com,carl@example.com]; [444-555-6666]&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
+&lt;span class="s2">&amp;#34;james; []; [222-333-4444]&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
+&lt;span class="s2">&amp;#34;julia; [julia@example.com]; []&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
+&lt;span class="p">];&lt;/span>
+&lt;/code>&lt;/pre>&lt;/div>
+&lt;/div>
+&lt;/div>
 &lt;h4 id="combine">4.2.4. Combine&lt;/h4>
 &lt;p>&lt;span class="language-java">&lt;a href="https://beam.apache.org/releases/javadoc/2.40.0/index.html?org/apache/beam/sdk/transforms/Combine.html">&lt;code>Combine&lt;/code>&lt;/a>&lt;/span>
 &lt;span class="language-py">&lt;a href="https://github.com/apache/beam/blob/master/sdks/python/apache_beam/transforms/core.py">&lt;code>Combine&lt;/code>&lt;/a>&lt;/span>
 &lt;span class="language-go">&lt;a href="https://github.com/apache/beam/blob/master/sdks/go/pkg/beam/combine.go#L27">&lt;code>Combine&lt;/code>&lt;/a>&lt;/span>
+&lt;span class="language-typescript">&lt;a href="https://github.com/apache/beam/blob/master/sdks/typescript/src/apache_beam/transforms/group_and_combine.ts">&lt;code>Combine&lt;/code>&lt;/a>&lt;/span>
 is a Beam transform for combining collections of elements or values in your
 data. &lt;code>Combine&lt;/code> has variants that work on entire &lt;code>PCollection&lt;/code>s, and some that
 combine the values for each key in &lt;code>PCollection&lt;/code>s of key/value pairs.&lt;/p>
@@ -5818,7 +6141,14 @@ that your streaming computation might be idle. Incremental combining also
 reduces the storage of intermediate accumulators.&lt;/li>
 &lt;/ul>
 &lt;h5 id="simple-combines">4.2.4.1. Simple combinations using simple functions&lt;/h5>
-&lt;p>The following example code shows a simple combine function.&lt;/p>
+&lt;p>The following example code shows a simple combine function.
+&lt;span class="language-typescript">
+Combining is done by modifying a grouping transform with the &lt;code>combining&lt;/code> method.
+This method takes three parameters: the value to combine (either as a named
+property of the input elements, or a function of the entire input),
+the combining operation (either a binary function or a &lt;code>CombineFn&lt;/code>),
+and finally a name for the combined value in the output object.
+&lt;/span>&lt;/p>
 &lt;div class='language-java snippet'>
 &lt;div class="notebook-skip code-snippet">
 &lt;a class="copy" type="button" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Copy to clipboard">
@@ -5896,6 +6226,22 @@ the type of the output.&lt;/p>
 &lt;span class="p">}&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
 &lt;/div>
 &lt;/div>
+&lt;div class='language-typescript snippet'>
+&lt;div class="notebook-skip code-snippet">
+&lt;a class="copy" type="button" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Copy to clipboard">
+&lt;img src="/images/copy-icon.svg"/>
+&lt;/a>
+&lt;div class="highlight">&lt;pre class="chroma">&lt;code class="language-typescript" data-lang="typescript">&lt;span class="kr">const&lt;/span> &lt;span class="nx">pcoll&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">root&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">apply&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">beam&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">create&lt;/span>&lt;span class="p">([&lt;/span>&lt;span class="mi"> [...]
+&lt;span class="kr">const&lt;/span> &lt;span class="nx">result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">pcoll&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">apply&lt;/span>&lt;span class="p">(&lt;/span>
+&lt;span class="nx">beam&lt;/span>
+&lt;span class="p">.&lt;/span>&lt;span class="nx">groupGlobally&lt;/span>&lt;span class="p">()&lt;/span>
+&lt;span class="p">.&lt;/span>&lt;span class="nx">combining&lt;/span>&lt;span class="p">((&lt;/span>&lt;span class="nx">c&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">=&amp;gt;&lt;/span> &lt;span class="nx">c&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nx">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">y&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">=&amp;gt;&lt;/span> &lt;span class="nx">x&lt;/span> &lt; [...]
+&lt;span class="p">.&lt;/span>&lt;span class="nx">combining&lt;/span>&lt;span class="p">((&lt;/span>&lt;span class="nx">c&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">=&amp;gt;&lt;/span> &lt;span class="nx">c&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nx">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">y&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">=&amp;gt;&lt;/span> &lt;span class="nx">x&lt;/span> &lt; [...]
+&lt;span class="p">);&lt;/span>
+&lt;span class="kr">const&lt;/span> &lt;span class="nx">expected&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="nx">sum&lt;/span>: &lt;span class="kt">1111&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">product&lt;/span>: &lt;span class="kt">1000000&lt;/span> &lt;span class="p">}&lt;/span>
+&lt;/code>&lt;/pre>&lt;/div>
+&lt;/div>
+&lt;/div>
 &lt;h5 id="advanced-combines">4.2.4.2. Advanced combinations using CombineFn&lt;/h5>
 &lt;p>For more complex combine functions, you can define a
 &lt;span class="language-java language-py">subclass of&lt;/span>&lt;code>CombineFn&lt;/code>.
@@ -6017,6 +6363,27 @@ mean average:&lt;/p>
 &lt;span class="p">}&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
 &lt;/div>
 &lt;/div>
+&lt;div class='language-go snippet'>
+&lt;div class="notebook-skip code-snippet">
+&lt;a class="copy" type="button" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Copy to clipboard">
+&lt;img src="/images/copy-icon.svg"/>
+&lt;/a>
+&lt;div class="highlight">&lt;pre class="chroma">&lt;code class="language-go" data-lang="go">&lt;span class="kd">const&lt;/span> &lt;span class="nx">meanCombineFn&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nx">beam&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">CombineFn&lt;/span>&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nx">number&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="nx">number&lt;/span>&lt;span class=" [...]
+&lt;span class="p">{&lt;/span>
+&lt;span class="nx">createAccumulator&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">()&lt;/span> &lt;span class="p">=&amp;gt;&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">],&lt;/span>
+&lt;span class="nx">addInput&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">([&lt;/span>&lt;span class="nx">sum&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">count&lt;/span>&lt;span class="p">]:&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="nx">number&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">number&lt;/span>&lt;span class="p">],&lt;/span> &lt;span class="nx">i&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nx">number&lt;/spa [...]
+&lt;span class="nx">sum&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="nx">i&lt;/span>&lt;span class="p">,&lt;/span>
+&lt;span class="nx">count&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span>
+&lt;span class="p">],&lt;/span>
+&lt;span class="nx">mergeAccumulators&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nx">accumulators&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="nx">number&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">number&lt;/span>&lt;span class="p">][])&lt;/span> &lt;span class="p">=&amp;gt;&lt;/span>
+&lt;span class="nx">accumulators&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">reduce&lt;/span>&lt;span class="p">(([&lt;/span>&lt;span class="nx">sum0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">count0&lt;/span>&lt;span class="p">],&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="nx">sum1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">count1&lt;/span>&lt;span class="p">])&lt;/span> &lt;span class="p">=&amp;gt;&lt;/span> &lt;span class="p [...]
+&lt;span class="nx">sum0&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="nx">sum1&lt;/span>&lt;span class="p">,&lt;/span>
+&lt;span class="nx">count0&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="nx">count1&lt;/span>&lt;span class="p">,&lt;/span>
+&lt;span class="p">]),&lt;/span>
+&lt;span class="nx">extractOutput&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">([&lt;/span>&lt;span class="nx">sum&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">count&lt;/span>&lt;span class="p">]:&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="nx">number&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">number&lt;/span>&lt;span class="p">])&lt;/span> &lt;span class="p">=&amp;gt;&lt;/span> &lt;span class="nx">sum&lt;/span> &lt;span class="o" [...]
+&lt;span class="p">};&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
+&lt;/div>
+&lt;/div>
 &lt;span class="language-go">
 &lt;blockquote>
 &lt;p>&lt;strong>Note&lt;/strong>: Only &lt;code>MergeAccumulators&lt;/code> is a required method. The others will have a default interpretation
@@ -6061,6 +6428,17 @@ of integers.&lt;/p>
 &lt;div class="highlight">&lt;pre class="chroma">&lt;code class="language-go" data-lang="go">&lt;span class="nx">average&lt;/span> &lt;span class="o">:=&lt;/span> &lt;span class="nx">beam&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">Combine&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">s&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">&amp;amp;&lt;/span>&lt;span class="nx">averageFn&lt;/span>&lt;span class="p">{},&lt;/span> &lt;span class="nx">ints&l [...]
 &lt;/div>
 &lt;/div>
+&lt;div class='language-go snippet'>
+&lt;div class="notebook-skip code-snippet">
+&lt;a class="copy" type="button" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Copy to clipboard">
+&lt;img src="/images/copy-icon.svg"/>
+&lt;/a>
+&lt;div class="highlight">&lt;pre class="chroma">&lt;code class="language-go" data-lang="go">&lt;span class="kd">const&lt;/span> &lt;span class="nx">pcoll&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nx">root&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">apply&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">beam&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">create&lt;/span>&lt;span class="p">([&lt;/span>&lt;span class="mi">4&lt;/span>&lt;s [...]
+&lt;span class="kd">const&lt;/span> &lt;span class="nx">result&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nx">pcoll&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">apply&lt;/span>&lt;span class="p">(&lt;/span>
+&lt;span class="nx">beam&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">groupGlobally&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="nf">combining&lt;/span>&lt;span class="p">((&lt;/span>&lt;span class="nx">c&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">=&amp;gt;&lt;/span> &lt;span class="nx">c&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">meanCombineFn&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;mean&amp;#34;&lt;/ [...]
+&lt;span class="p">);&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
+&lt;/div>
+&lt;/div>
 &lt;h5 id="combine-global-windowing">4.2.4.4. Combine and global windowing&lt;/h5>
 &lt;p>If your input &lt;code>PCollection&lt;/code> uses the default global windowing, the default
 behavior is to return a &lt;code>PCollection&lt;/code> containing one item. That item&amp;rsquo;s value
@@ -6192,10 +6570,38 @@ PerKey must be an associative reduction function or a
 &lt;span class="o">//&lt;/span> &lt;span class="nx">avgAccuracyPerPlayer&lt;/span> &lt;span class="nx">is&lt;/span> &lt;span class="nx">a&lt;/span> &lt;span class="nx">PCollection&lt;/span>&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="kt">string&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="kt">float64&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
 &lt;/div>
 &lt;/div>
+&lt;div class='language-typescript snippet'>
+&lt;div class="notebook-skip code-snippet">
+&lt;a class="copy" type="button" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Copy to clipboard">
+&lt;img src="/images/copy-icon.svg"/>
+&lt;/a>
+&lt;div class="highlight">&lt;pre class="chroma">&lt;code class="language-typescript" data-lang="typescript">&lt;span class="kr">const&lt;/span> &lt;span class="nx">pcoll&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">root&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">apply&lt;/span>&lt;span class="p">(&lt;/span>
+&lt;span class="nx">beam&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">create&lt;/span>&lt;span class="p">([&lt;/span>
+&lt;span class="p">{&lt;/span> &lt;span class="nx">player&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;alice&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">accuracy&lt;/span>: &lt;span class="kt">1.0&lt;/span> &lt;span class="p">},&lt;/span>
+&lt;span class="p">{&lt;/span> &lt;span class="nx">player&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;bob&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">accuracy&lt;/span>: &lt;span class="kt">0.99&lt;/span> &lt;span class="p">},&lt;/span>
+&lt;span class="p">{&lt;/span> &lt;span class="nx">player&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;eve&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">accuracy&lt;/span>: &lt;span class="kt">0.5&lt;/span> &lt;span class="p">},&lt;/span>
+&lt;span class="p">{&lt;/span> &lt;span class="nx">player&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;eve&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">accuracy&lt;/span>: &lt;span class="kt">0.25&lt;/span> &lt;span class="p">},&lt;/span>
+&lt;span class="p">])&lt;/span>
+&lt;span class="p">);&lt;/span>
+&lt;span class="kr">const&lt;/span> &lt;span class="nx">result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">pcoll&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">apply&lt;/span>&lt;span class="p">(&lt;/span>
+&lt;span class="nx">beam&lt;/span>
+&lt;span class="p">.&lt;/span>&lt;span class="nx">groupBy&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;player&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
+&lt;span class="p">.&lt;/span>&lt;span class="nx">combining&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;accuracy&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">combiners&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">mean&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;mean&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
+&lt;span class="p">.&lt;/span>&lt;span class="nx">combining&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;accuracy&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">combiners&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">max&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;max&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
+&lt;span class="p">);&lt;/span>
+&lt;span class="kr">const&lt;/span> &lt;span class="nx">expected&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>
+&lt;span class="p">{&lt;/span> &lt;span class="nx">player&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;alice&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">mean&lt;/span>: &lt;span class="kt">1.0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">max&lt;/span>: &lt;span class="kt">1.0&lt;/span> &lt;span class="p">},&lt;/span>
+&lt;span class="p">{&lt;/span> &lt;span class="nx">player&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;bob&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">mean&lt;/span>: &lt;span class="kt">0.99&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">max&lt;/span>: &lt;span class="kt">0.99&lt;/span> &lt;span class="p">},&lt;/span>
+&lt;span class="p">{&lt;/span> &lt;span class="nx">player&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;eve&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">mean&lt;/span>: &lt;span class="kt">0.375&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">max&lt;/span>: &lt;span class="kt">0.5&lt;/span> &lt;span class="p">},&lt;/span>
+&lt;span class="p">];&lt;/span>
+&lt;/code>&lt;/pre>&lt;/div>
+&lt;/div>
+&lt;/div>
 &lt;h4 id="flatten">4.2.5. Flatten&lt;/h4>
 &lt;p>&lt;span class="language-java">&lt;a href="https://beam.apache.org/releases/javadoc/2.40.0/index.html?org/apache/beam/sdk/transforms/Flatten.html">&lt;code>Flatten&lt;/code>&lt;/a>&lt;/span>
 &lt;span class="language-py">&lt;a href="https://github.com/apache/beam/blob/master/sdks/python/apache_beam/transforms/core.py">&lt;code>Flatten&lt;/code>&lt;/a>&lt;/span>
 &lt;span class="language-go">&lt;a href="https://github.com/apache/beam/blob/master/sdks/go/pkg/beam/flatten.go">&lt;code>Flatten&lt;/code>&lt;/a>&lt;/span>
+&lt;span class="language-typescript">&lt;code>Flatten&lt;/code>&lt;/span>
 is a Beam transform for &lt;code>PCollection&lt;/code> objects that store the same data type.
 &lt;code>Flatten&lt;/code> merges multiple &lt;code>PCollection&lt;/code> objects into a single logical
 &lt;code>PCollection&lt;/code>.&lt;/p>
@@ -6239,6 +6645,20 @@ is a Beam transform for &lt;code>PCollection&lt;/code> objects that store the sa
 &lt;span class="nx">merged&lt;/span> &lt;span class="o">:=&lt;/span> &lt;span class="nx">beam&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">Flatten&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">s&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">pcol1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">pcol2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">pcol3&lt;/span>&lt;span class="p">)&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
 &lt;/div>
 &lt;/div>
+&lt;div class='language-typescript snippet'>
+&lt;div class="notebook-skip code-snippet">
+&lt;a class="copy" type="button" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Copy to clipboard">
+&lt;img src="/images/copy-icon.svg"/>
+&lt;/a>
+&lt;div class="highlight">&lt;pre class="chroma">&lt;code class="language-typescript" data-lang="typescript">&lt;span class="c1">// Flatten takem an array of PCollection objects, wrapped in beam.P(...)
+&lt;/span>&lt;span class="c1">// Returns a single PCollection that contains a union of all of the elements in all input PCollections.
+&lt;/span>&lt;span class="c1">&lt;/span>
+&lt;span class="kr">const&lt;/span> &lt;span class="nx">fib&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">root&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">apply&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">beam&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">create&lt;/span>&lt;span class="p">([&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;spa [...]
+&lt;span class="kr">const&lt;/span> &lt;span class="nx">pow&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">root&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">apply&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">beam&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">create&lt;/span>&lt;span class="p">([&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;spa [...]
+&lt;span class="kr">const&lt;/span> &lt;span class="nx">result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">beam&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">P&lt;/span>&lt;span class="p">([&lt;/span>&lt;span class="nx">fib&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">pow&lt;/span>&lt;span class="p">]).&lt;/span>&lt;span class="nx">apply&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">beam&lt;/span>&lt;span class="p">.&lt;/span>&lt; [...]
+&lt;/code>&lt;/pre>&lt;/div>
+&lt;/div>
+&lt;/div>
 &lt;h5 id="data-encoding-merged-collections">4.2.5.1. Data encoding in merged collections&lt;/h5>
 &lt;p>By default, the coder for the output &lt;code>PCollection&lt;/code> is the same as the coder for
 the first &lt;code>PCollection&lt;/code> in the input &lt;code>PCollectionList&lt;/code>. However, the input
@@ -6257,9 +6677,11 @@ pipeline is constructed.&lt;/p>
 &lt;p>&lt;span class="language-java">&lt;a href="https://beam.apache.org/releases/javadoc/2.40.0/index.html?org/apache/beam/sdk/transforms/Partition.html">&lt;code>Partition&lt;/code>&lt;/a>&lt;/span>
 &lt;span class="language-py">&lt;a href="https://github.com/apache/beam/blob/master/sdks/python/apache_beam/transforms/core.py">&lt;code>Partition&lt;/code>&lt;/a>&lt;/span>
 &lt;span class="language-go">&lt;a href="https://github.com/apache/beam/blob/master/sdks/go/pkg/beam/partition.go">&lt;code>Partition&lt;/code>&lt;/a>&lt;/span>
+&lt;span class="language-typescript">&lt;code>Partition&lt;/code>&lt;/span>
 is a Beam transform for &lt;code>PCollection&lt;/code> objects that store the same data
 type. &lt;code>Partition&lt;/code> splits a single &lt;code>PCollection&lt;/code> into a fixed number of smaller
 collections.&lt;/p>
+&lt;p class="language-typescript">Often in the Typescript SDK the &lt;code>Split&lt;/code> transform is more natural to use.&lt;/p>
 &lt;p>&lt;code>Partition&lt;/code> divides the elements of a &lt;code>PCollection&lt;/code> according to a partitioning
 function that you provide. The partitioning function contains the logic that
 determines how to split up the elements of the input &lt;code>PCollection&lt;/code> into each
@@ -6322,6 +6744,22 @@ for instance).&lt;/p>
 &lt;/span>&lt;span class="c1">&lt;/span>&lt;span class="nx">fortiethPercentile&lt;/span> &lt;span class="o">:=&lt;/span> &lt;span class="nx">studentsByPercentile&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">4&lt;/span>&lt;span class="p">]&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
 &lt;/div>
 &lt;/div>
+&lt;div class='language-typescript snippet'>
+&lt;div class="notebook-skip code-snippet">
+&lt;a class="copy" type="button" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Copy to clipboard">
+&lt;img src="/images/copy-icon.svg"/>
+&lt;/a>
+&lt;div class="highlight">&lt;pre class="chroma">&lt;code class="language-typescript" data-lang="typescript">&lt;span class="kr">const&lt;/span> &lt;span class="nx">deciles&lt;/span>: &lt;span class="kt">PCollection&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="nx">Student&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">[]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">students&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">apply [...]
+&lt;span class="nx">beam&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">partition&lt;/span>&lt;span class="p">(&lt;/span>
+&lt;span class="p">(&lt;/span>&lt;span class="nx">student&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">numPartitions&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">=&amp;gt;&lt;/span>
+&lt;span class="nb">Math&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">floor&lt;/span>&lt;span class="p">((&lt;/span>&lt;span class="nx">getPercentile&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">student&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="mi">100&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="nx">numPartitions&lt;/span>&lt;span class="p">),&lt;/span>
+&lt;span class="mi">10&lt;/span>
+&lt;span class="p">)&lt;/span>
+&lt;span class="p">);&lt;/span>
+&lt;span class="kr">const&lt;/span> &lt;span class="nx">topDecile&lt;/span>: &lt;span class="kt">PCollection&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="nx">Student&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">deciles&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">9&lt;/span>&lt;span class="p">];&lt;/span>
+&lt;/code>&lt;/pre>&lt;/div>
+&lt;/div>
+&lt;/div>
 &lt;h3 id="requirements-for-writing-user-code-for-beam-transforms">4.3. Requirements for writing user code for Beam transforms&lt;/h3>
 &lt;p>When you build user code for a Beam transform, you should keep in mind the
 distributed nature of execution. For example, there might be many copies of your
@@ -6367,7 +6805,21 @@ however, your subclass must not add any non-serializable members.&lt;/span>
 they are registered with &lt;code>register.FunctionXxY&lt;/code> (for simple functions) or
 &lt;code>register.DoFnXxY&lt;/code> (for sturctural DoFns), and are not closures. Structural
 &lt;code>DoFn&lt;/code>s will have all exported fields serialized. Unexported fields are unable to
-be serialized, and will be silently ignored.&lt;/span>&lt;/p>
+be serialized, and will be silently ignored.&lt;/span>
+&lt;span class="language-typescript">
+The Typescript SDK use &lt;a href="https://github.com/nokia/ts-serialize-closures">ts-serialize-closures&lt;/a>
+to serialize functions (and other objects).
+This works out of the box for functions that are not closures, and also works
+for closures as long as the function in question (and any closures it references)
+are compiled with the
+&lt;a href="https://github.com/apache/beam/blob/master/sdks/typescript/tsconfig.json">&lt;code>ts-closure-transform&lt;/code> hooks&lt;/a>
+(e.g. by using &lt;code>ttsc&lt;/code> in place of &lt;code>tsc&lt;/code>).
+One can alternatively call
+&lt;code>requireForSerialization(&amp;quot;importableModuleDefiningFunc&amp;quot;, {func})&lt;/code>
+to &lt;a href="https://github.com/apache/beam/blob/master/sdks/typescript/src/apache_beam/serialization.ts">register a function directly&lt;/a> by name which can be less error-prone.
+Note that if, as is often the case in Javascript, &lt;code>func&lt;/code> returns objects that
+contain closures, it is not sufficient to register &lt;code>func&lt;/code> alone&amp;ndash;its return
+value must be registered if used.&lt;/span>&lt;/p>
 &lt;p>Some other serializability factors you should keep in mind are:&lt;/p>
 &lt;ul>
 &lt;li>&lt;span class="language-java language-py">Transient&lt;/span>&lt;span class="langauage-go">Unexported&lt;/span>
@@ -6549,6 +7001,43 @@ function. This optimizes runtime execution of the iterable.&lt;/p>
 &lt;/span>&lt;span class="c1">&lt;/span>&lt;span class="o">//&lt;/span> &lt;span class="nx">on&lt;/span> &lt;span class="nx">how&lt;/span> &lt;span class="nx">to&lt;/span> &lt;span class="nx">contribute&lt;/span> &lt;span class="nx">them&lt;/span>&lt;span class="p">!&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
 &lt;/div>
 &lt;/div>
+&lt;div class='language-typescript snippet'>
+&lt;div class="notebook-skip code-snippet">
+&lt;a class="copy" type="button" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Copy to clipboard">
+&lt;img src="/images/copy-icon.svg"/>
+&lt;/a>
+&lt;div class="highlight">&lt;pre class="chroma">&lt;code class="language-typescript" data-lang="typescript">&lt;span class="c1">// Side inputs are provided by passing an extra context object to
+&lt;/span>&lt;span class="c1">// `map`, `flatMap`, or `parDo` transforms. This object will get passed as an
+&lt;/span>&lt;span class="c1">// extra argument to the provided function (or `process` method of the `DoFn`).
+&lt;/span>&lt;span class="c1">// `SideInputParam` properties (generally created with `pardo.xxxSideInput(...)`)
+&lt;/span>&lt;span class="c1">// have a `lookup` method that can be invoked from within the process method.
+&lt;/span>&lt;span class="c1">&lt;/span>
+&lt;span class="c1">// Let words be a PCollection of strings.
+&lt;/span>&lt;span class="c1">&lt;/span>&lt;span class="kr">const&lt;/span> &lt;span class="nx">words&lt;/span> : &lt;span class="kt">PCollection&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">string&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">...&lt;/span>
+&lt;span class="c1">// meanLengthPColl will contain a single number whose value is the
+&lt;/span>&lt;span class="c1">// average length of the words
+&lt;/span>&lt;span class="c1">&lt;/span>&lt;span class="kr">const&lt;/span> &lt;span class="nx">meanLengthPColl&lt;/span>: &lt;span class="kt">PCollection&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">number&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">words&lt;/span>
+&lt;span class="p">.&lt;/span>&lt;span class="nx">apply&lt;/span>&lt;span class="p">(&lt;/span>
+&lt;span class="nx">beam&lt;/span>
+&lt;span class="p">.&lt;/span>&lt;span class="nx">groupGlobally&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">string&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">()&lt;/span>
+&lt;span class="p">.&lt;/span>&lt;span class="nx">combining&lt;/span>&lt;span class="p">((&lt;/span>&lt;span class="nx">word&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">=&amp;gt;&lt;/span> &lt;span class="nx">word&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">length&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">combiners&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">mean&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&am [...]
+&lt;span class="p">)&lt;/span>
+&lt;span class="p">.&lt;/span>&lt;span class="nx">map&lt;/span>&lt;span class="p">(({&lt;/span> &lt;span class="nx">mean&lt;/span> &lt;span class="p">})&lt;/span> &lt;span class="o">=&amp;gt;&lt;/span> &lt;span class="nx">mean&lt;/span>&lt;span class="p">);&lt;/span>
+&lt;span class="c1">// Now we use this as a side input to yield only words that are
+&lt;/span>&lt;span class="c1">// smaller than average.
+&lt;/span>&lt;span class="c1">&lt;/span>&lt;span class="kr">const&lt;/span> &lt;span class="nx">smallWords&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">words&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">flatMap&lt;/span>&lt;span class="p">(&lt;/span>
+&lt;span class="c1">// This is the function, taking context as a second argument.
+&lt;/span>&lt;span class="c1">&lt;/span> &lt;span class="kd">function&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="nx">keepSmall&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">word&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">context&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
+&lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nx">word&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">length&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="nx">context&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">meanLength&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">lookup&lt;/span>&lt;span class="p">())&lt;/span> &lt;span class="p">{&lt;/span>
+&lt;span class="nx">yield&lt;/span> &lt;span class="nx">word&lt;/span>&lt;span class="p">;&lt;/span>
+&lt;span class="p">}&lt;/span>
+&lt;span class="p">},&lt;/span>
+&lt;span class="c1">// This is the context that will be passed as a second argument.
+&lt;/span>&lt;span class="c1">&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="nx">meanLength&lt;/span>: &lt;span class="kt">pardo.singletonSideInput&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">meanLengthPColl&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">}&lt;/span>
+&lt;span class="p">);&lt;/span>
+&lt;/code>&lt;/pre>&lt;/div>
+&lt;/div>
+&lt;/div>
 &lt;h4 id="side-inputs-windowing">4.4.2. Side inputs and windowing&lt;/h4>
 &lt;p>A windowed &lt;code>PCollection&lt;/code> may be infinite and thus cannot be compressed into a
 single value (or single collection class). When you create a &lt;code>PCollectionView&lt;/code>
@@ -6584,7 +7073,17 @@ If you choose to have multiple outputs, your &lt;code>DoFn&lt;/code> needs to be
 function that matches the number of outputs. &lt;code>beam.ParDo2&lt;/code> for two output &lt;code>PCollection&lt;/code>s,
 &lt;code>beam.ParDo3&lt;/code> for three and so on until &lt;code>beam.ParDo7&lt;/code>. If you need more, you can
 use &lt;code>beam.ParDoN&lt;/code> which will return a &lt;code>[]beam.PCollection&lt;/code>.&lt;/p>
+&lt;p class="language-typescript">While &lt;code>ParDo&lt;/code> always produces a main output &lt;code>PCollection&lt;/code> (as the return value
+from &lt;code>apply&lt;/code>). If you want to have multiple outputs, emit an object with distinct
+properties in your &lt;code>ParDo&lt;/code> operation and follow this operation with a &lt;code>Split&lt;/code>
+to break it into multiple &lt;code>PCollection&lt;/code>s.&lt;/p>
 &lt;h4 id="output-tags">4.5.1. Tags for multiple outputs&lt;/h4>
+&lt;p class="language-typescript">The &lt;code>Split&lt;/code> PTransform will take a PCollection of elements of the form
+&lt;code>{tagA?: A, tagB?: B, ...}&lt;/code> and return a object
+&lt;code>{tagA: PCollection&amp;lt;A&amp;gt;, tagB: PCollection&amp;lt;B&amp;gt;, ...}&lt;/code>.
+The set of expected tags is passed to the operation; how multiple or
+unknown tags are handled can be specified by passing a non-default
+&lt;code>SplitOptions&lt;/code> instance.&lt;/p>
 &lt;p class="language-go">The Go SDK doesn&amp;rsquo;t use output tags, and instead uses positional ordering for
 multiple output PCollections.&lt;/p>
 &lt;div class='language-java snippet'>
@@ -6678,13 +7177,24 @@ multiple output PCollections.&lt;/p>
 &lt;/span>&lt;span class="c1">&lt;/span>&lt;span class="nx">length&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">mixedMarked&lt;/span> &lt;span class="o">:=&lt;/span> &lt;span class="nx">beam&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">ParDo2&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">s&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">processWordsMixed&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">words&lt;/span>&lt;sp [...]
 &lt;/div>
 &lt;/div>
+&lt;div class='language-typescript snippet'>
+&lt;div class="notebook-skip code-snippet">
+&lt;a class="copy" type="button" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Copy to clipboard">
+&lt;img src="/images/copy-icon.svg"/>
+&lt;/a>
+&lt;div class="highlight">&lt;pre class="chroma">&lt;code class="language-typescript" data-lang="typescript">&lt;span class="err">#&lt;/span> &lt;span class="nx">Create&lt;/span> &lt;span class="nx">three&lt;/span> &lt;span class="nx">PCollections&lt;/span> &lt;span class="nx">from&lt;/span> &lt;span class="nx">a&lt;/span> &lt;span class="nx">single&lt;/span> &lt;span class="nx">input&lt;/span> &lt;span class="nx">PCollection&lt;/span>&lt;span class="p">.&lt;/span>
+&lt;span class="kr">const&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="nx">below&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">above&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">marked&lt;/span> &lt;span class="p">}&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">to_split&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">apply&lt;/span>&lt;span class="p">(&lt;/span>
+&lt;span class="nx">beam&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">split&lt;/span>&lt;span class="p">([&lt;/span>&lt;span class="s2">&amp;#34;below&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;above&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;marked&amp;#34;&lt;/span>&lt;span class="p">])&lt;/span>
+&lt;span class="p">);&lt;/span>
+&lt;/code>&lt;/pre>&lt;/div>
+&lt;/div>
+&lt;/div>
 &lt;h4 id="multiple-outputs-dofn">4.5.2. Emitting to multiple outputs in your DoFn&lt;/h4>
-&lt;p class="language-go">&lt;p>Call emitter functions as needed to produce 0 or more elements for its matching
+&lt;p class="language-go">Call emitter functions as needed to produce 0 or more elements for its matching
 &lt;code>PCollection&lt;/code>. The same value can be emitted with multiple emitters.
 As normal, do not mutate values after emitting them from any emitter.&lt;/p>
-&lt;p>All emitters should be registered using a generic &lt;code>register.EmitterX[...]&lt;/code>
+&lt;p class="language-go">All emitters should be registered using a generic &lt;code>register.EmitterX[...]&lt;/code>
 function. This optimizes runtime execution of the emitter.&lt;/p>
-&lt;/p>
 &lt;p class="language-go">DoFns can also return a single element via the standard return.
 The standard return is always the first PCollection returned from beam.ParDo.
 Other emitters output to their own PCollections in their defined parameter order.&lt;/p>
@@ -6781,11 +7291,31 @@ Other emitters output to their own PCollections in their defined parameter order
 &lt;span class="p">}&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
 &lt;/div>
 &lt;/div>
+&lt;div class='language-typescript snippet'>
+&lt;div class="notebook-skip code-snippet">
+&lt;a class="copy" type="button" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Copy to clipboard">
+&lt;img src="/images/copy-icon.svg"/>
+&lt;/a>
+&lt;div class="highlight">&lt;pre class="chroma">&lt;code class="language-typescript" data-lang="typescript">&lt;span class="kr">const&lt;/span> &lt;span class="nx">to_split&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">words&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">flatMap&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kd">function&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nx">word&lt;/span>&lt;span cla [...]
+&lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nx">word&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">length&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="mi">5&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
+&lt;span class="nx">yield&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="nx">below&lt;/span>: &lt;span class="kt">word&lt;/span> &lt;span class="p">};&lt;/span>
+&lt;span class="p">}&lt;/span> &lt;span class="k">else&lt;/span> &lt;span class="p">{&lt;/span>
+&lt;span class="nx">yield&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="nx">above&lt;/span>: &lt;span class="kt">word&lt;/span> &lt;span class="p">};&lt;/span>
+&lt;span class="p">}&lt;/span>
+&lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nx">isMarkedWord&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">word&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="p">{&lt;/span>
+&lt;span class="nx">yield&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="nx">marked&lt;/span>: &lt;span class="kt">word&lt;/span> &lt;span class="p">};&lt;/span>
+&lt;span class="p">}&lt;/span>
+&lt;span class="p">});&lt;/span>
+&lt;/code>&lt;/pre>&lt;/div>
+&lt;/div>
+&lt;/div>
 &lt;h4 id="other-dofn-parameters">4.5.3. Accessing additional parameters in your DoFn&lt;/h4>
 &lt;p class="language-java">In addition to the element and the &lt;code>OutputReceiver&lt;/code>, Beam will populate other parameters to your DoFn&amp;rsquo;s &lt;code>@ProcessElement&lt;/code> method.
 Any combination of these parameters can be added to your process method in any order.&lt;/p>
 &lt;p class="language-py">In addition to the element, Beam will populate other parameters to your DoFn&amp;rsquo;s &lt;code>process&lt;/code> method.
 Any combination of these parameters can be added to your process method in any order.&lt;/p>
+&lt;p class="language-typescript">In addition to the element, Beam will populate other parameters to your DoFn&amp;rsquo;s &lt;code>process&lt;/code> method.
+These are available by placing accessors in the context argument, just as for side inputs.&lt;/p>
 &lt;p class="language-go">In addition to the element, Beam will populate other parameters to your DoFn&amp;rsquo;s &lt;code>ProcessElement&lt;/code> method.
 Any combination of these parameters can be added to your process method in a standard order.&lt;/p>
 &lt;p class="language-go">&lt;strong>context.Context:&lt;/strong>
@@ -6805,6 +7335,8 @@ To access the timestamp of an input element, add a parameter annotated with &lt;
 To access the timestamp of an input element, add a keyword parameter default to &lt;code>DoFn.TimestampParam&lt;/code>. For example:&lt;/p>
 &lt;p class="language-go">&lt;strong>Timestamp:&lt;/strong>
 To access the timestamp of an input element, add a &lt;code>beam.EventTime&lt;/code> parameter before the element. For example:&lt;/p>
+&lt;p class="language-typescript">&lt;strong>Timestamp:&lt;/strong>
+To access the window an input element falls into, add a &lt;code>pardo.windowParam()&lt;/code> to the context argument.&lt;/p>
 &lt;div class='language-java snippet'>
 &lt;div class="notebook-skip code-snippet">
 &lt;a class="copy" type="button" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Copy to clipboard">
@@ -6835,6 +7367,18 @@ To access the timestamp of an input element, add a &lt;code>beam.EventTime&lt;/c
 &lt;div class="highlight">&lt;pre class="chroma">&lt;code class="language-go" data-lang="go">&lt;span class="kd">func&lt;/span> &lt;span class="nf">MyDoFn&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">ts&lt;/span> &lt;span class="nx">beam&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">EventTime&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">word&lt;/span> &lt;span class="kt">string&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="kt">string&lt [...]
 &lt;/div>
 &lt;/div>
+&lt;div class='language-typescript snippet'>
+&lt;div class="notebook-skip code-snippet">
+&lt;a class="copy" type="button" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Copy to clipboard">
+&lt;img src="/images/copy-icon.svg"/>
+&lt;/a>
+&lt;div class="highlight">&lt;pre class="chroma">&lt;code class="language-typescript" data-lang="typescript">&lt;span class="kd">function&lt;/span> &lt;span class="nx">processFn&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">element&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">context&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
+&lt;span class="k">return&lt;/span> &lt;span class="nx">context&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">timestamp&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">lookup&lt;/span>&lt;span class="p">();&lt;/span>
+&lt;span class="p">}&lt;/span>
+&lt;span class="nx">pcoll&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">map&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">processFn&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="nx">timestamp&lt;/span>: &lt;span class="kt">pardo.timestampParam&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">});&lt;/span>
+&lt;/code>&lt;/pre>&lt;/div>
+&lt;/div>
+&lt;/div>
 &lt;p class="language-java">&lt;strong>Window:&lt;/strong>
 To access the window an input element falls into, add a parameter of the type of the window used for the input &lt;code>PCollection&lt;/code>.
 If the parameter is a window type (a subclass of &lt;code>BoundedWindow&lt;/code>) that does not match the input &lt;code>PCollection&lt;/code>, then an error
@@ -6851,6 +7395,10 @@ If an element falls in multiple windows (for example, this will happen when usin
 then the &lt;code>ProcessElement&lt;/code> method will be invoked multiple time for the element, once for each window.
 Since &lt;code>beam.Window&lt;/code> is an interface it&amp;rsquo;s possible to type assert to the concrete implementation of the window.
 For example, when fixed windows are being used, the window is of type &lt;code>window.IntervalWindow&lt;/code>.&lt;/p>
+&lt;p class="language-typescript">&lt;strong>Window:&lt;/strong>
+To access the window an input element falls into, add a &lt;code>pardo.windowParam()&lt;/code> to the context argument.
+If an element falls in multiple windows (for example, this will happen when using &lt;code>SlidingWindows&lt;/code>), then the
+function will be invoked multiple time for the element, once for each window.&lt;/p>
 &lt;div class='language-java snippet'>
 &lt;div class="notebook-skip code-snippet">
 &lt;a class="copy" type="button" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Copy to clipboard">
@@ -6884,6 +7432,15 @@ For example, when fixed windows are being used, the window is of type &lt;code>w
 &lt;span class="p">}&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
 &lt;/div>
 &lt;/div>
+&lt;div class='language-typescript snippet'>
+&lt;div class="notebook-skip code-snippet">
+&lt;a class="copy" type="button" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Copy to clipboard">
+&lt;img src="/images/copy-icon.svg"/>
+&lt;/a>
+&lt;div class="highlight">&lt;pre class="chroma">&lt;code class="language-typescript" data-lang="typescript">&lt;span class="nx">pcoll&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">map&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">processFn&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="nx">timestamp&lt;/span>: &lt;span class="kt">pardo.windowParam&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">});&lt;/span>
+&lt;/code>&lt;/pre>&lt;/div>
+&lt;/div>
+&lt;/div>
 &lt;p class="language-java">&lt;strong>PaneInfo:&lt;/strong>
 When triggers are used, Beam provides a &lt;code>PaneInfo&lt;/code> object that contains information about the current firing. Using &lt;code>PaneInfo&lt;/code>
 you can determine whether this is an early or a late firing, and how many times this window has already fired for this key.&lt;/p>
@@ -6894,6 +7451,10 @@ This feature implementation in Python SDK is not fully completed; see more at &l
 &lt;p class="language-go">&lt;strong>PaneInfo:&lt;/strong>
 When triggers are used, Beam provides &lt;code>beam.PaneInfo&lt;/code> object that contains information about the current firing. Using &lt;code>beam.PaneInfo&lt;/code>
 you can determine whether this is an early or a late firing, and how many times this window has already fired for this key.&lt;/p>
+&lt;p class="language-typescript">&lt;strong>Window:&lt;/strong>
+To access the window an input element falls into, add a &lt;code>pardo.paneInfoParam()&lt;/code> to the context argument.
+Using &lt;code>beam.PaneInfo&lt;/code> you can determine whether this is an early or a late firing,
+and how many times this window has already fired for this key.&lt;/p>
 &lt;div class='language-java snippet'>
 &lt;div class="notebook-skip code-snippet">
 &lt;a class="copy" type="button" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Copy to clipboard">
@@ -6941,6 +7502,15 @@ you can determine whether this is an early or a late firing, and how many times
 &lt;span class="p">}&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
 &lt;/div>
 &lt;/div>
+&lt;div class='language-typescript snippet'>
+&lt;div class="notebook-skip code-snippet">
+&lt;a class="copy" type="button" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Copy to clipboard">
+&lt;img src="/images/copy-icon.svg"/>
+&lt;/a>
+&lt;div class="highlight">&lt;pre class="chroma">&lt;code class="language-typescript" data-lang="typescript">&lt;span class="nx">pcoll&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">map&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">processFn&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="nx">timestamp&lt;/span>: &lt;span class="kt">pardo.paneInfoParam&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">});&lt;/span>
+&lt;/code>&lt;/pre>&lt;/div>
+&lt;/div>
+&lt;/div>
 &lt;p class="language-java">&lt;strong>PipelineOptions:&lt;/strong>
 The &lt;code>PipelineOptions&lt;/code> for the current pipeline can always be accessed in a process method by adding it
 as a parameter:&lt;/p>
@@ -6965,6 +7535,9 @@ Timers and States are explained in more detail in the
 &lt;a href="/blog/2017/08/28/timely-processing.html">Timely (and Stateful) Processing with Apache Beam&lt;/a> blog post.&lt;/p>
 &lt;p class="language-go">&lt;strong>Timer and State:&lt;/strong>
 This feature isn&amp;rsquo;t implemented in the Go SDK; see more at &lt;a href="https://github.com/apache/beam/issues/20510">Issue 20510&lt;/a>. Once implemented, user defined Timer and State parameters can be used in a stateful DoFn.&lt;/p>
+&lt;p class="language-typescript">&lt;strong>Timer and State:&lt;/strong>
+This feature isn&amp;rsquo;t implemented in the Typescript SDK yet,
+but can be used from a cross-language transform.&lt;/p>
 &lt;div class='language-py snippet'>
 &lt;div class="notebook-skip code-snippet">
 &lt;a class="copy" type="button" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Copy to clipboard">
@@ -7117,11 +7690,30 @@ appeared in the original data.&lt;/li>
 &lt;span class="p">}&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
 &lt;/div>
 &lt;/div>
+&lt;div class='language-typescript snippet'>
+&lt;div class="notebook-skip code-snippet">
+&lt;a class="copy" type="button" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Copy to clipboard">
+&lt;img src="/images/copy-icon.svg"/>
+&lt;/a>
+&lt;div class="highlight">&lt;pre class="chroma">&lt;code class="language-typescript" data-lang="typescript">&lt;span class="kd">function&lt;/span> &lt;span class="nx">countWords&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">lines&lt;/span>: &lt;span class="kt">PCollection&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">string&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
+&lt;span class="k">return&lt;/span> &lt;span class="nx">lines&lt;/span> &lt;span class="c1">//
+&lt;/span>&lt;span class="c1">&lt;/span> &lt;span class="p">.&lt;/span>&lt;span class="nx">map&lt;/span>&lt;span class="p">((&lt;/span>&lt;span class="nx">s&lt;/span>: &lt;span class="kt">string&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">=&amp;gt;&lt;/span> &lt;span class="nx">s&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">toLowerCase&lt;/span>&lt;span class="p">())&lt;/span>
+&lt;span class="p">.&lt;/span>&lt;span class="nx">flatMap&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kd">function&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="nx">splitWords&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">line&lt;/span>: &lt;span class="kt">string&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
+&lt;span class="nx">yield&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="nx">line&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">split&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sr">/[^a-z]+/&lt;/span>&lt;span class="p">);&lt;/span>
+&lt;span class="p">})&lt;/span>
+&lt;span class="p">.&lt;/span>&lt;span class="nx">apply&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">beam&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">countPerElement&lt;/span>&lt;span class="p">());&lt;/span>
+&lt;span class="p">}&lt;/span>
+&lt;span class="kr">const&lt;/span> &lt;span class="nx">counted&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">lines&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">apply&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">countWords&lt;/span>&lt;span class="p">);&lt;/span>
+&lt;/code>&lt;/pre>&lt;/div>
+&lt;/div>
+&lt;/div>
 &lt;blockquote>
 &lt;p>&lt;strong>Note:&lt;/strong> Because &lt;code>Count&lt;/code> is itself a composite transform,
 &lt;code>CountWords&lt;/code> is also a nested composite transform.&lt;/p>
 &lt;/blockquote>
 &lt;h4 id="composite-transform-creation">4.6.2. Creating a composite transform&lt;/h4>
+&lt;p class="language-typescript">A PTransform in the Typescript SDK is simply a function that accepts and
+returns &lt;code>PValue&lt;/code>s such as &lt;code>PCollection&lt;/code>s.&lt;/p>
 &lt;p class="language-java language-py">To create your own composite transform, create a subclass of the &lt;code>PTransform&lt;/code>
 class and override the &lt;code>expand&lt;/code> method to specify the actual processing logic.
 You can then use this transform just as you would a built-in transform from the
diff --git a/website/generated-content/documentation/programming-guide/index.html b/website/generated-content/documentation/programming-guide/index.html
index 81505b2ee6b..5659b0353a3 100644
--- a/website/generated-content/documentation/programming-guide/index.html
+++ b/website/generated-content/documentation/programming-guide/index.html
@@ -28,7 +28,7 @@ guide to programmatically building your Beam pipeline. As the programming guide
 is filled out, the text will include code samples in multiple languages to help
 illustrate how to implement Beam concepts in your pipelines.</p><p>If you want a brief introduction to Beam&rsquo;s basic concepts before reading the
 programming guide, take a look at the
-<a href=/documentation/basics/>Basics of the Beam model</a> page.</p><nav class=language-switcher><strong>Adapt for:</strong><ul><li data-type=language-java class=active>Java SDK</li><li data-type=language-py>Python SDK</li><li data-type=language-go>Go SDK</li></ul></nav><p class=language-py>The Python SDK supports Python 3.7, 3.8, and 3.9.</p><p class=language-go>The Go SDK supports Go v1.18+. SDK release 2.32.0 is the last experimental version.</p><h2 id=overview>1. Overview</h2><p>To  [...]
+<a href=/documentation/basics/>Basics of the Beam model</a> page.</p><nav class=language-switcher><strong>Adapt for:</strong><ul><li data-type=language-java class=active>Java SDK</li><li data-type=language-py>Python SDK</li><li data-type=language-go>Go SDK</li><li data-type=language-typescript>Typescript SDK</li></ul></nav><p class=language-py>The Python SDK supports Python 3.7, 3.8, and 3.9.</p><p class=language-go>The Go SDK supports Go v1.18+. SDK release 2.32.0 is the last experiment [...]
 of the Beam SDKs. Your driver program <em>defines</em> your pipeline, including all of
 the inputs, transforms, and outputs; it also sets execution options for your
 pipeline (typically passed in using command-line options). These include the
@@ -81,7 +81,8 @@ class <code>Pipeline</code> (typically in the <code>main()</code> function). Whe
 <code>Pipeline</code>, you&rsquo;ll also need to set some <strong>configuration options</strong>. You can set
 your pipeline&rsquo;s configuration options programmatically, but it&rsquo;s often easier to
 set the options ahead of time (or read them from the command line) and pass them
-to the <code>Pipeline</code> object when you create the object.</p><div class="language-java snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-java data-lang=java><span class=c1>// Start by defining the options for the pipeline.
+to the <code>Pipeline</code> object when you create the object.</p><span class=language-typescript>A Pipeline in the Typescript API is simply a function that will be called
+with a single `root` object and is passed to a Runner's `run` method.</span><div class="language-java snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-java data-lang=java><span class=c1>// Start by defining the options for the pipeline.
 </span><span class=c1></span><span class=n>PipelineOptions</span> <span class=n>options</span> <span class=o>=</span> <span class=n>PipelineOptionsFactory</span><span class=o>.</span><span class=na>create</span><span class=o>();</span>
 
 <span class=c1>// Then create the pipeline.
@@ -93,7 +94,10 @@ to the <code>Pipeline</code> object when you create the object.</p><div class="l
 </span><span class=c1></span><span class=nx>beam</span><span class=p>.</span><span class=nf>Init</span><span class=p>()</span>
 
 <span class=c1>// Create the Pipeline object and root scope.
-</span><span class=c1></span><span class=nx>pipeline</span><span class=p>,</span> <span class=nx>scope</span> <span class=o>:=</span> <span class=nx>beam</span><span class=p>.</span><span class=nf>NewPipelineWithRoot</span><span class=p>()</span></code></pre></div></div></div><h3 id=configuring-pipeline-options>2.1. Configuring pipeline options</h3><p>Use the pipeline options to configure different aspects of your pipeline, such
+</span><span class=c1></span><span class=nx>pipeline</span><span class=p>,</span> <span class=nx>scope</span> <span class=o>:=</span> <span class=nx>beam</span><span class=p>.</span><span class=nf>NewPipelineWithRoot</span><span class=p>()</span></code></pre></div></div></div><div class="language-typescript snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a [...]
+  <span class=c1>// Use root to build a pipeline.
+</span><span class=c1></span><span class=p>});</span>
+</code></pre></div></div></div><h3 id=configuring-pipeline-options>2.1. Configuring pipeline options</h3><p>Use the pipeline options to configure different aspects of your pipeline, such
 as the pipeline runner that will execute your pipeline and any runner-specific
 configuration required by the chosen runner. Your pipeline options will
 potentially include information such as your project ID or a location for
@@ -103,20 +107,29 @@ to a DoFn&rsquo;s <code>@ProcessElement</code> method, it will be populated by t
 setting the fields directly, the Beam SDKs include a command-line parser that
 you can use to set fields in <code>PipelineOptions</code> using command-line arguments.</p><p class="language-java language-py">To read options from the command-line, construct your <code>PipelineOptions</code> object
 as demonstrated in the following example code:</p><p class=language-go>Use Go flags to parse command line arguments to configure your pipeline. Flags must be parsed
-before <code>beam.Init()</code> is called.</p><div class="language-java snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-java data-lang=java><span class=n>PipelineOptions</span> <span class=n>options</span> <span class=o>=</span>
+before <code>beam.Init()</code> is called.</p><p class=language-typescript>Any Javascript object can be used as pipeline options.
+One can either construct one manually, but it is also common to pass an object
+created from command line options such as <code>yargs.argv</code>.</p><div class="language-java snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-java data-lang=java><span class=n>PipelineOptions</span> <span class=n>options</span> <span class=o>=</span>
     <span class=n>PipelineOptionsFactory</span><span class=o>.</span><span class=na>fromArgs</span><span class=o>(</span><span class=n>args</span><span class=o>).</span><span class=na>withValidation</span><span class=o>().</span><span class=na>create</span><span class=o>();</span></code></pre></div></div></div><div class="language-py snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img sr [...]
 
 <span class=n>beam_options</span> <span class=o>=</span> <span class=n>PipelineOptions</span><span class=p>()</span></code></pre></div></div></div><div class="language-go snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-go data-lang=go><span class=c1>// If beamx or Go flags are used, flags must b [...]
 </span><span class=c1>// before beam.Init() is called.
-</span><span class=c1></span><span class=nx>flag</span><span class=p>.</span><span class=nf>Parse</span><span class=p>()</span></code></pre></div></div></div><p>This interprets command-line arguments that follow the format:</p><pre><code>--&lt;option&gt;=&lt;value&gt;
+</span><span class=c1></span><span class=nx>flag</span><span class=p>.</span><span class=nf>Parse</span><span class=p>()</span></code></pre></div></div></div><div class="language-typescript snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-typescript data-lang=typescript><span class=kr>const</span [...]
+  <span class=nx>runner</span><span class=o>:</span> <span class=s2>&#34;default&#34;</span><span class=p>,</span>
+  <span class=nx>project</span><span class=o>:</span> <span class=s2>&#34;my_project&#34;</span><span class=p>,</span>
+<span class=p>};</span>
+
+<span class=kr>const</span> <span class=nx>runner</span> <span class=o>=</span> <span class=nx>beam</span><span class=p>.</span><span class=nx>createRunner</span><span class=p>(</span><span class=nx>pipeline_options</span><span class=p>);</span>
+
+<span class=kr>const</span> <span class=nx>runnerFromCommandLineOptions</span> <span class=o>=</span> <span class=nx>beam</span><span class=p>.</span><span class=nx>createRunner</span><span class=p>(</span><span class=nx>yargs</span><span class=p>.</span><span class=nx>argv</span><span class=p>);</span>
+</code></pre></div></div></div><p>This interprets command-line arguments that follow the format:</p><pre><code>--&lt;option&gt;=&lt;value&gt;
 </code></pre><span class=language-java><blockquote><p>Appending the method <code>.withValidation</code> will check for required
 command-line arguments and validate argument values.</p></blockquote></span><p class="language-java language-py">Building your <code>PipelineOptions</code> this way lets you specify any of the options as
 a command-line argument.</p><p class=language-go>Defining flag variables this way lets you specify any of the options as a command-line argument.</p><blockquote><p><strong>Note:</strong> The <a href=/get-started/wordcount-example>WordCount example pipeline</a>
 demonstrates how to set pipeline options at runtime by using command-line
 options.</p></blockquote><h4 id=creating-custom-options>2.1.2. Creating custom options</h4><p>You can add your own custom options in addition to the standard
-<code>PipelineOptions</code>. To add your own options, define an interface with getter and
-setter methods for each option, as in the following example for
-adding <code>input</code> and <code>output</code> custom options:</p><div class="language-java snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-java data-lang=java><span class=kd>public</span> <span class=kd>interface</span> <span class=nc>MyOptions</span> <span class=kd>extends</span> <span clas [...]
+<code>PipelineOptions</code>.<p class=language-java>To add your own options, define an interface with getter and
+setter methods for each option.</p>The following example shows how to add <code>input</code> and <code>output</code> custom options:</p><div class="language-java snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-java data-lang=java><span class=kd>public</span> <span class=kd>interface</span> <span [...]
     <span class=n>String</span> <span class=nf>getInput</span><span class=o>();</span>
     <span class=kt>void</span> <span class=nf>setInput</span><span class=o>(</span><span class=n>String</span> <span class=n>input</span><span class=o>);</span>
 
@@ -127,13 +140,16 @@ adding <code>input</code> and <code>output</code> custom options:</p><div class=
 <span class=k>class</span> <span class=nc>MyOptions</span><span class=p>(</span><span class=n>PipelineOptions</span><span class=p>):</span>
   <span class=nd>@classmethod</span>
   <span class=k>def</span> <span class=nf>_add_argparse_args</span><span class=p>(</span><span class=bp>cls</span><span class=p>,</span> <span class=n>parser</span><span class=p>):</span>
-    <span class=n>parser</span><span class=o>.</span><span class=n>add_argument</span><span class=p>(</span><span class=s1>&#39;--input-file&#39;</span><span class=p>)</span>
-    <span class=n>parser</span><span class=o>.</span><span class=n>add_argument</span><span class=p>(</span><span class=s1>&#39;--output-path&#39;</span><span class=p>)</span></code></pre></div></div></div><div class="language-go snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-go data-lang=go><s [...]
+    <span class=n>parser</span><span class=o>.</span><span class=n>add_argument</span><span class=p>(</span><span class=s1>&#39;--input&#39;</span><span class=p>)</span>
+    <span class=n>parser</span><span class=o>.</span><span class=n>add_argument</span><span class=p>(</span><span class=s1>&#39;--output&#39;</span><span class=p>)</span></code></pre></div></div></div><div class="language-go snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-go data-lang=go><span c [...]
 </span><span class=c1></span><span class=kd>var</span> <span class=p>(</span>
 	<span class=nx>input</span>  <span class=p>=</span> <span class=nx>flag</span><span class=p>.</span><span class=nf>String</span><span class=p>(</span><span class=s>&#34;input&#34;</span><span class=p>,</span> <span class=s>&#34;&#34;</span><span class=p>,</span> <span class=s>&#34;&#34;</span><span class=p>)</span>
 	<span class=nx>output</span> <span class=p>=</span> <span class=nx>flag</span><span class=p>.</span><span class=nf>String</span><span class=p>(</span><span class=s>&#34;output&#34;</span><span class=p>,</span> <span class=s>&#34;&#34;</span><span class=p>,</span> <span class=s>&#34;&#34;</span><span class=p>)</span>
-<span class=p>)</span></code></pre></div></div></div><p>You can also specify a description, which appears when a user passes <code>--help</code> as
-a command-line argument, and a default value.</p><p>You set the description and default value using annotations, as follows:</p><div class="language-java snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-java data-lang=java><span class=kd>public</span> <span class=kd>interface</span> <span class=n [...]
+<span class=p>)</span></code></pre></div></div></div><div class="language-typescript snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-typescript data-lang=typescript><span class=kr>const</span> <span class=nx>options</span> <span class=o>=</span> <span class=nx>yargs</span><span class=p>.</span>< [...]
+</span><span class=c1></span>
+<span class=c1>// Use options.input and options.output during pipeline construction.
+</span></code></pre></div></div></div><p>You can also specify a description, which appears when a user passes <code>--help</code> as
+a command-line argument, and a default value.</p><p class="language-java language-py langauge-go">You set the description and default value using annotations, as follows:</p><div class="language-java snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-java data-lang=java><span class=kd>public</span> [...]
     <span class=nd>@Description</span><span class=o>(</span><span class=s>&#34;Input for the pipeline&#34;</span><span class=o>)</span>
     <span class=nd>@Default.String</span><span class=o>(</span><span class=s>&#34;gs://my-bucket/input&#34;</span><span class=o>)</span>
     <span class=n>String</span> <span class=nf>getInput</span><span class=o>();</span>
@@ -149,16 +165,15 @@ a command-line argument, and a default value.</p><p>You set the description and
   <span class=nd>@classmethod</span>
   <span class=k>def</span> <span class=nf>_add_argparse_args</span><span class=p>(</span><span class=bp>cls</span><span class=p>,</span> <span class=n>parser</span><span class=p>):</span>
     <span class=n>parser</span><span class=o>.</span><span class=n>add_argument</span><span class=p>(</span>
-        <span class=s1>&#39;--input-file&#39;</span><span class=p>,</span>
+        <span class=s1>&#39;--input&#39;</span><span class=p>,</span>
         <span class=n>default</span><span class=o>=</span><span class=s1>&#39;gs://dataflow-samples/shakespeare/kinglear.txt&#39;</span><span class=p>,</span>
         <span class=n>help</span><span class=o>=</span><span class=s1>&#39;The file path for the input text to process.&#39;</span><span class=p>)</span>
     <span class=n>parser</span><span class=o>.</span><span class=n>add_argument</span><span class=p>(</span>
-        <span class=s1>&#39;--output-path&#39;</span><span class=p>,</span>
-        <span class=n>required</span><span class=o>=</span><span class=bp>True</span><span class=p>,</span>
-        <span class=n>help</span><span class=o>=</span><span class=s1>&#39;The path prefix for output files.&#39;</span><span class=p>)</span></code></pre></div></div></div><div class="language-go snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-go data-lang=go><span class=kd>var</span> <span cla [...]
+        <span class=s1>&#39;--output&#39;</span><span class=p>,</span> <span class=n>required</span><span class=o>=</span><span class=bp>True</span><span class=p>,</span> <span class=n>help</span><span class=o>=</span><span class=s1>&#39;The path prefix for output files.&#39;</span><span class=p>)</span></code></pre></div></div></div><div class="language-go snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Co [...]
 	<span class=nx>input</span>  <span class=p>=</span> <span class=nx>flag</span><span class=p>.</span><span class=nf>String</span><span class=p>(</span><span class=s>&#34;input&#34;</span><span class=p>,</span> <span class=s>&#34;gs://my-bucket/input&#34;</span><span class=p>,</span> <span class=s>&#34;Input for the pipeline&#34;</span><span class=p>)</span>
 	<span class=nx>output</span> <span class=p>=</span> <span class=nx>flag</span><span class=p>.</span><span class=nf>String</span><span class=p>(</span><span class=s>&#34;output&#34;</span><span class=p>,</span> <span class=s>&#34;gs://my-bucket/output&#34;</span><span class=p>,</span> <span class=s>&#34;Output for the pipeline&#34;</span><span class=p>)</span>
-<span class=p>)</span></code></pre></div></div></div><p class=language-java>It&rsquo;s recommended that you register your interface with <code>PipelineOptionsFactory</code>
+<span class=p>)</span></code></pre></div></div></div><p class=language-py>For Python, you can also simply parse your custom options with argparse; there
+is no need to create a separate PipelineOptions subclass.</p><p class=language-java>It&rsquo;s recommended that you register your interface with <code>PipelineOptionsFactory</code>
 and then pass the interface when creating the <code>PipelineOptions</code> object. When you
 register your interface with <code>PipelineOptionsFactory</code>, the <code>--help</code> can find
 your custom options interface and add it to the output of the <code>--help</code> command.
@@ -189,12 +204,16 @@ represent the data records in that source.</p><p>Each data source adapter has a
 transform to the <code>Pipeline</code> object itself.
 <span class=language-java><code>TextIO.Read</code></span>
 <span class=language-py><code>io.TextFileSource</code></span>
-<span class=language-go><code>textio.Read</code></span>, for example, reads from an
+<span class=language-go><code>textio.Read</code></span>
+<span class=language-typescript><code>textio.ReadFromText</code></span>,
+for example, reads from an
 external text file and returns a <code>PCollection</code> whose elements are of type
 <code>String</code>, each <code>String</code> represents one line from the text file. Here&rsquo;s how you
 would apply <span class=language-java><code>TextIO.Read</code></span>
 <span class=language-py><code>io.TextFileSource</code></span>
-<span class=language-go><code>textio.Read</code></span> to your <code>Pipeline</code> to create
+<span class=language-go><code>textio.Read</code></span>
+<span class=language-typescript><code>textio.ReadFromText</code></span>
+to your <code>Pipeline</code> <span class=language-typescript>root</span> to create
 a <code>PCollection</code>:</p><div class="language-java snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-java data-lang=java><span class=kd>public</span> <span class=kd>static</span> <span class=kt>void</span> <span class=nf>main</span><span class=o>(</span><span class=n>String</span><span class [...]
     <span class=c1>// Create the pipeline.
 </span><span class=c1></span>    <span class=n>PipelineOptions</span> <span class=n>options</span> <span class=o>=</span>
@@ -209,7 +228,12 @@ a <code>PCollection</code>:</p><div class="language-java snippet"><div class="no
 </span><span class=c1>// the lines as a PCollection&lt;string&gt;.
 </span><span class=c1>// Notice the scope as the first variable when calling
 </span><span class=c1>// the method as is needed when calling all transforms.
-</span><span class=c1></span><span class=nx>lines</span> <span class=o>:=</span> <span class=nx>textio</span><span class=p>.</span><span class=nf>Read</span><span class=p>(</span><span class=nx>scope</span><span class=p>,</span> <span class=s>&#34;gs://some/inputData.txt&#34;</span><span class=p>)</span></code></pre></div></div></div><p>See the <a href=#pipeline-io>section on I/O</a> to learn more about how to read from the
+</span><span class=c1></span><span class=nx>lines</span> <span class=o>:=</span> <span class=nx>textio</span><span class=p>.</span><span class=nf>Read</span><span class=p>(</span><span class=nx>scope</span><span class=p>,</span> <span class=s>&#34;gs://some/inputData.txt&#34;</span><span class=p>)</span></code></pre></div></div></div><div class="language-go snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Co [...]
+  <span class=c1>// Note that textio.ReadFromText is an AsyncPTransform.
+</span><span class=c1></span>  <span class=kd>const</span> <span class=nx>pcoll</span><span class=p>:</span> <span class=nx>PCollection</span><span class=p>&lt;</span><span class=kt>string</span><span class=p>&gt;</span> <span class=p>=</span> <span class=nx>await</span> <span class=nx>root</span><span class=p>.</span><span class=nf>asyncApply</span><span class=p>(</span>
+    <span class=nx>textio</span><span class=p>.</span><span class=nf>ReadFromText</span><span class=p>(</span><span class=s>&#34;path/to/text_pattern&#34;</span><span class=p>)</span>
+  <span class=p>);</span>
+<span class=p>}</span></code></pre></div></div></div><p>See the <a href=#pipeline-io>section on I/O</a> to learn more about how to read from the
 various data sources supported by the Beam SDK.</p><h4 id=creating-pcollection-in-memory>3.1.2. Creating a PCollection from in-memory data</h4><p class=language-java>To create a <code>PCollection</code> from an in-memory Java <code>Collection</code>, you use the
 Beam-provided <code>Create</code> transform. Much like a data adapter&rsquo;s <code>Read</code>, you apply
 <code>Create</code> directly to your <code>Pipeline</code> object itself.</p><p class=language-java>As parameters, <code>Create</code> accepts the Java <code>Collection</code> and a <code>Coder</code> object. The
@@ -217,8 +241,12 @@ Beam-provided <code>Create</code> transform. Much like a data adapter&rsquo;s <c
 <a href=#element-type>encoded</a>.</p><p class=language-py>To create a <code>PCollection</code> from an in-memory <code>list</code>, you use the Beam-provided
 <code>Create</code> transform. Apply this transform directly to your <code>Pipeline</code> object
 itself.</p><p class=language-go>To create a <code>PCollection</code> from an in-memory <code>slice</code>, you use the Beam-provided
-<code>beam.CreateList</code> transform. Pass the pipeline <code>scope</code>, and the <code>slice</code> to this transform.</p><p>The following example code shows how to create a <code>PCollection</code> from an in-memory
-<span class=language-java><code>List</code></span><span class=language-py><code>list</code></span><span class=language-go><code>slice</code></span>:</p><div class="language-java snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-java data-lang=java><span class=kd>public</span> <span class=kd>static [...]
+<code>beam.CreateList</code> transform. Pass the pipeline <code>scope</code>, and the <code>slice</code> to this transform.</p><p class=language-typescript>To create a <code>PCollection</code> from an in-memory <code>array</code>, you use the Beam-provided
+<code>Create</code> transform. Apply this transform directly to your <code>Root</code> object.</p><p>The following example code shows how to create a <code>PCollection</code> from an in-memory
+<span class=language-java><code>List</code></span>
+<span class=language-py><code>list</code></span>
+<span class=language-go><code>slice</code></span>
+<span class=language-typescript><code>array</code></span>:</p><div class="language-java snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-java data-lang=java><span class=kd>public</span> <span class=kd>static</span> <span class=kt>void</span> <span class=nf>main</span><span class=o>(</span><span c [...]
     <span class=c1>// Create a Java Collection, in this case a List of Strings.
 </span><span class=c1></span>    <span class=kd>final</span> <span class=n>List</span><span class=o>&lt;</span><span class=n>String</span><span class=o>&gt;</span> <span class=n>LINES</span> <span class=o>=</span> <span class=n>Arrays</span><span class=o>.</span><span class=na>asList</span><span class=o>(</span>
       <span class=s>&#34;To be, or not to be: that is the question: &#34;</span><span class=o>,</span>
@@ -258,7 +286,17 @@ itself.</p><p class=language-go>To create a <code>PCollection</code> from an in-
 <span class=c1>// Pass the slice to beam.CreateList, to create the pcollection.
 </span><span class=c1>// The scope variable s is used to add the CreateList transform
 </span><span class=c1>// to the pipeline.
-</span><span class=c1></span><span class=nx>linesPCol</span> <span class=o>:=</span> <span class=nx>beam</span><span class=p>.</span><span class=nf>CreateList</span><span class=p>(</span><span class=nx>s</span><span class=p>,</span> <span class=nx>lines</span><span class=p>)</span></code></pre></div></div></div><h3 id=pcollection-characteristics>3.2. PCollection characteristics</h3><p>A <code>PCollection</code> is owned by the specific <code>Pipeline</code> object for which it is
+</span><span class=c1></span><span class=nx>linesPCol</span> <span class=o>:=</span> <span class=nx>beam</span><span class=p>.</span><span class=nf>CreateList</span><span class=p>(</span><span class=nx>s</span><span class=p>,</span> <span class=nx>lines</span><span class=p>)</span></code></pre></div></div></div><div class="language-typescript snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard [...]
+  <span class=kr>const</span> <span class=nx>pcoll</span> <span class=o>=</span> <span class=nx>root</span><span class=p>.</span><span class=nx>apply</span><span class=p>(</span>
+    <span class=nx>beam</span><span class=p>.</span><span class=nx>create</span><span class=p>([</span>
+      <span class=s2>&#34;To be, or not to be: that is the question: &#34;</span><span class=p>,</span>
+      <span class=s2>&#34;Whether &#39;tis nobler in the mind to suffer &#34;</span><span class=p>,</span>
+      <span class=s2>&#34;The slings and arrows of outrageous fortune, &#34;</span><span class=p>,</span>
+      <span class=s2>&#34;Or to take arms against a sea of troubles, &#34;</span><span class=p>,</span>
+    <span class=p>])</span>
+  <span class=p>);</span>
+<span class=p>}</span>
+</code></pre></div></div></div><h3 id=pcollection-characteristics>3.2. PCollection characteristics</h3><p>A <code>PCollection</code> is owned by the specific <code>Pipeline</code> object for which it is
 created; multiple pipelines cannot share a <code>PCollection</code>.
 <span class=language-java>In some respects, a <code>PCollection</code> functions like
 a <code>Collection</code> class. However, a <code>PCollection</code> can differ in a few key ways:</span></p><h4 id=element-type>3.2.1. Element type</h4><p>The elements of a <code>PCollection</code> may be of any type, but must all be of the same
@@ -332,7 +370,9 @@ transform in the Beam SDKs has a generic <code>apply</code> method <span class=l
 Invoking multiple Beam transforms is similar to <em>method chaining</em>, but with one
 slight difference: You apply the transform to the input <code>PCollection</code>, passing
 the transform itself as an argument, and the operation returns the output
-<code>PCollection</code>. This takes the general form:</p><div class="language-java snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-java data-lang=java><span class=o>[</span><span class=n>Output</span> <span class=n>PCollection</span><span class=o>]</span> <span class=o>=</span> <span class=o>[< [...]
+<code>PCollection</code>. This takes the general form:</p><div class="language-java snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-java data-lang=java><span class=o>[</span><span class=n>Output</span> <span class=n>PCollection</span><span class=o>]</span> <span class=o>=</span> <span class=o>[< [...]
+<span class=p>[</span><span class=nx>Output</span> <span class=nx>PCollection</span><span class=p>]</span> <span class=o>=</span> <span class=nx>await</span> <span class=p>[</span><span class=nx>Input</span> <span class=nx>PCollection</span><span class=p>].</span><span class=nx>asyncApply</span><span class=p>([</span><span class=nx>AsyncTransform</span><span class=p>])</span>
+</code></pre></div></div></div><p class="language-java language-py language-typescript">Because Beam uses a generic <code>apply</code> method for <code>PCollection</code>, you can both chain
 transforms sequentially and also apply transforms that contain other transforms
 nested within (called <a href=#composite-transforms>composite transforms</a> in the Beam
 SDKs).</p><p class=language-go>It&rsquo;s recommended to create a new variable for each new <code>PCollection</code> to
@@ -349,7 +389,10 @@ inputs and emit <code>PCollection</code> nodes as outputs.
               <span class=o>|</span> <span class=p>[</span><span class=n>Second</span> <span class=n>Transform</span><span class=p>]</span>
               <span class=o>|</span> <span class=p>[</span><span class=n>Third</span> <span class=n>Transform</span><span class=p>])</span></code></pre></div></div></div><div class="language-go snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-go data-lang=go><span class=p>[</span><span class=nx>S [...]
 <span class=p>[</span><span class=nx>Third</span> <span class=nx>PCollection</span><span class=p>]</span> <span class=o>:=</span> <span class=nx>beam</span><span class=p>.</span><span class=nf>ParDo</span><span class=p>(</span><span class=nx>scope</span><span class=p>,</span> <span class=p>[</span><span class=nx>Second</span> <span class=nx>Transform</span><span class=p>],</span> <span class=p>[</span><span class=nx>Second</span> <span class=nx>PCollection</span><span class=p>])</span>
-<span class=p>[</span><span class=nx>Final</span> <span class=nx>Output</span> <span class=nx>PCollection</span><span class=p>]</span> <span class=o>:=</span> <span class=nx>beam</span><span class=p>.</span><span class=nf>ParDo</span><span class=p>(</span><span class=nx>scope</span><span class=p>,</span> <span class=p>[</span><span class=nx>Third</span> <span class=nx>Transform</span><span class=p>],</span> <span class=p>[</span><span class=nx>Third</span> <span class=nx>PCollection</spa [...]
+<span class=p>[</span><span class=nx>Final</span> <span class=nx>Output</span> <span class=nx>PCollection</span><span class=p>]</span> <span class=o>:=</span> <span class=nx>beam</span><span class=p>.</span><span class=nf>ParDo</span><span class=p>(</span><span class=nx>scope</span><span class=p>,</span> <span class=p>[</span><span class=nx>Third</span> <span class=nx>Transform</span><span class=p>],</span> <span class=p>[</span><span class=nx>Third</span> <span class=nx>PCollection</spa [...]
+<span class=p>.</span><span class=nx>apply</span><span class=p>([</span><span class=nx>Second</span> <span class=nx>Transform</span><span class=p>])</span>
+<span class=p>.</span><span class=nx>apply</span><span class=p>([</span><span class=nx>Third</span> <span class=nx>Transform</span><span class=p>])</span>
+</code></pre></div></div></div><p>The graph of this pipeline looks like the following:</p><p><img src=/images/design-your-pipeline-linear.svg alt="This linear pipeline starts with one input collection, sequentially appliesthree transforms, and ends with one output collection."></p><p><em>Figure 1: A linear pipeline with three sequential transforms.</em></p><p>However, note that a transform <em>does not consume or otherwise alter</em> the input
 collection — remember that a <code>PCollection</code> is immutable by definition. This means
 that you can apply multiple transforms to the same input <code>PCollection</code> to create
 a branching pipeline, like so:</p><div class="language-java snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-java data-lang=java><span class=o>[</span><span class=n>PCollection</span> <span class=n>of</span> <span class=n>database</span> <span class=n>table</span> <span class=n>rows</span><span c [...]
@@ -358,12 +401,25 @@ a branching pipeline, like so:</p><div class="language-java snippet"><div class=
 <span class=p>[</span><span class=n>PCollection</span> <span class=n>of</span> <span class=s1>&#39;A&#39;</span> <span class=n>names</span><span class=p>]</span> <span class=o>=</span> <span class=p>[</span><span class=n>PCollection</span> <span class=n>of</span> <span class=n>database</span> <span class=n>table</span> <span class=n>rows</span><span class=p>]</span> <span class=o>|</span> <span class=p>[</span><span class=n>Transform</span> <span class=n>A</span><span class=p>]</span>
 <span class=p>[</span><span class=n>PCollection</span> <span class=n>of</span> <span class=s1>&#39;B&#39;</span> <span class=n>names</span><span class=p>]</span> <span class=o>=</span> <span class=p>[</span><span class=n>PCollection</span> <span class=n>of</span> <span class=n>database</span> <span class=n>table</span> <span class=n>rows</span><span class=p>]</span> <span class=o>|</span> <span class=p>[</span><span class=n>Transform</span> <span class=n>B</span><span class=p>]</span></c [...]
 <span class=p>[</span><span class=nx>PCollection</span> <span class=nx>of</span> <span class=sc>&#39;A&#39;</span> <span class=nx>names</span><span class=p>]</span> <span class=p>=</span> <span class=nx>beam</span><span class=p>.</span><span class=nf>ParDo</span><span class=p>(</span><span class=nx>scope</span><span class=p>,</span> <span class=p>[</span><span class=nx>Transform</span> <span class=nx>A</span><span class=p>],</span> <span class=p>[</span><span class=nx>PCollection</span>  [...]
-<span class=p>[</span><span class=nx>PCollection</span> <span class=nx>of</span> <span class=sc>&#39;B&#39;</span> <span class=nx>names</span><span class=p>]</span> <span class=p>=</span> <span class=nx>beam</span><span class=p>.</span><span class=nf>ParDo</span><span class=p>(</span><span class=nx>scope</span><span class=p>,</span> <span class=p>[</span><span class=nx>Transform</span> <span class=nx>B</span><span class=p>],</span> <span class=p>[</span><span class=nx>PCollection</span>  [...]
+<span class=p>[</span><span class=nx>PCollection</span> <span class=nx>of</span> <span class=sc>&#39;B&#39;</span> <span class=nx>names</span><span class=p>]</span> <span class=p>=</span> <span class=nx>beam</span><span class=p>.</span><span class=nf>ParDo</span><span class=p>(</span><span class=nx>scope</span><span class=p>,</span> <span class=p>[</span><span class=nx>Transform</span> <span class=nx>B</span><span class=p>],</span> <span class=p>[</span><span class=nx>PCollection</span>  [...]
+<span class=p>[</span><span class=nx>PCollection</span> <span class=nx>of</span> <span class=s1>&#39;A&#39;</span> <span class=nx>names</span><span class=p>]</span> <span class=o>=</span> <span class=p>[</span><span class=nx>PCollection</span> <span class=nx>of</span> <span class=nx>database</span> <span class=nx>table</span> <span class=nx>rows</span><span class=p>].</span><span class=nx>apply</span><span class=p>([</span><span class=nx>Transform</span> <span class=nx>A</span><span clas [...]
+<span class=p>[</span><span class=nx>PCollection</span> <span class=nx>of</span> <span class=s1>&#39;B&#39;</span> <span class=nx>names</span><span class=p>]</span> <span class=o>=</span> <span class=p>[</span><span class=nx>PCollection</span> <span class=nx>of</span> <span class=nx>database</span> <span class=nx>table</span> <span class=nx>rows</span><span class=p>].</span><span class=nx>apply</span><span class=p>([</span><span class=nx>Transform</span> <span class=nx>B</span><span clas [...]
+</code></pre></div></div></div><p>The graph of this branching pipeline looks like the following:</p><p><img src=/images/design-your-pipeline-multiple-pcollections.svg alt="This pipeline applies two transforms to a single input collection. Eachtransform produces an output collection."></p><p><em>Figure 2: A branching pipeline. Two transforms are applied to a single
 PCollection of database table rows.</em></p><p>You can also build your own <a href=#composite-transforms>composite transforms</a> that
 nest multiple transforms inside a single, larger transform. Composite transforms
 are particularly useful for building a reusable sequence of simple steps that
-get used in a lot of different places.</p><h3 id=core-beam-transforms>4.2. Core Beam transforms</h3><p>Beam provides the following core transforms, each of which represents a different
-processing paradigm:</p><ul><li><code>ParDo</code></li><li><code>GroupByKey</code></li><li><code>CoGroupByKey</code></li><li><code>Combine</code></li><li><code>Flatten</code></li><li><code>Partition</code></li></ul><h4 id=pardo>4.2.1. ParDo</h4><p><code>ParDo</code> is a Beam transform for generic parallel processing. The <code>ParDo</code>
+get used in a lot of different places.</p><p class=language-python>The pipe syntax allows one to apply PTransforms to <code>tuple</code>s and <code>dict</code>s of
+PCollections as well for those transforms accepting multiple inputs (such as
+<code>Flatten</code> and <code>CoGroupByKey</code>).</p><p class=language-typescript>PTransforms can also be applied to any <code>PValue</code>, which include the Root object,
+PCollections, arrays of <code>PValue</code>s, and objects with <code>PValue</code> values.
+One can apply transforms to these composite types by wrapping them with
+<code>beam.P</code>, e.g.
+<code>beam.P({left: pcollA, right: pcollB}).apply(transformExpectingTwoPCollections)</code>.</p><p class=language-typescript>PTransforms come in two flavors, synchronous and asynchronous, depending on
+whether their <em>application</em>* involves asynchronous invocations.
+An <code>AsyncTransform</code> must be applied with <code>asyncApply</code> and returns a <code>Promise</code>
+which must be awaited before further pipeline construction.</p><h3 id=core-beam-transforms>4.2. Core Beam transforms</h3><p>Beam provides the following core transforms, each of which represents a different
+processing paradigm:</p><ul><li><code>ParDo</code></li><li><code>GroupByKey</code></li><li><code>CoGroupByKey</code></li><li><code>Combine</code></li><li><code>Flatten</code></li><li><code>Partition</code></li></ul><p class=language-typescript>The Typescript SDK provides some of the most basic of these transforms
+as methods on <code>PCollection</code> itself.</p><h4 id=pardo>4.2.1. ParDo</h4><p><code>ParDo</code> is a Beam transform for generic parallel processing. The <code>ParDo</code>
 processing paradigm is similar to the &ldquo;Map&rdquo; phase of a
 <a href=https://en.wikipedia.org/wiki/MapReduce>Map/Shuffle/Reduce</a>-style
 algorithm: a <code>ParDo</code> transform considers each element in the input
@@ -449,7 +505,22 @@ as shown in the following example code:</p><div class="language-java snippet"><d
 <span class=c1>// words is an input PCollection of strings
 </span><span class=c1></span><span class=kd>var</span> <span class=nx>words</span> <span class=nx>beam</span><span class=p>.</span><span class=nx>PCollection</span> <span class=p>=</span> <span class=o>...</span>
 
-<span class=nx>wordLengths</span> <span class=o>:=</span> <span class=nx>beam</span><span class=p>.</span><span class=nf>ParDo</span><span class=p>(</span><span class=nx>s</span><span class=p>,</span> <span class=o>&amp;</span><span class=nx>ComputeWordLengthFn</span><span class=p>{},</span> <span class=nx>words</span><span class=p>)</span></code></pre></div></div></div><p>In the example, our input <code>PCollection</code> contains <span class="language-java language-py"><code>String</co [...]
+<span class=nx>wordLengths</span> <span class=o>:=</span> <span class=nx>beam</span><span class=p>.</span><span class=nf>ParDo</span><span class=p>(</span><span class=nx>s</span><span class=p>,</span> <span class=o>&amp;</span><span class=nx>ComputeWordLengthFn</span><span class=p>{},</span> <span class=nx>words</span><span class=p>)</span></code></pre></div></div></div><div class="language-typescript snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-togg [...]
+<span class=kr>const</span> <span class=nx>words</span> : <span class=kt>PCollection</span><span class=o>&lt;</span><span class=kt>string</span><span class=o>&gt;</span> <span class=o>=</span> <span class=p>...</span>
+
+<span class=err>#</span> <span class=nx>The</span> <span class=nx>DoFn</span> <span class=nx>to</span> <span class=nx>perform</span> <span class=nx>on</span> <span class=nx>each</span> <span class=nx>element</span> <span class=k>in</span> <span class=nx>the</span> <span class=nx>input</span> <span class=nx>PCollection</span><span class=p>.</span>
+
+<span class=kd>function</span> <span class=nx>computeWordLengthFn</span><span class=p>()</span><span class=o>:</span> <span class=nx>beam</span><span class=p>.</span><span class=nx>DoFn</span><span class=o>&lt;</span><span class=kt>string</span><span class=p>,</span> <span class=kt>number</span><span class=o>&gt;</span> <span class=p>{</span>
+  <span class=k>return</span> <span class=p>{</span>
+    <span class=nx>process</span>: <span class=kt>function</span><span class=o>*</span> <span class=p>(</span><span class=nx>element</span><span class=p>)</span> <span class=p>{</span>
+      <span class=nx>yield</span> <span class=nx>element</span><span class=p>.</span><span class=nx>length</span><span class=p>;</span>
+    <span class=p>},</span>
+  <span class=p>};</span>
+<span class=p>}</span>
+
+
+<span class=kr>const</span> <span class=nx>result</span> <span class=o>=</span> <span class=nx>words</span><span class=p>.</span><span class=nx>apply</span><span class=p>(</span><span class=nx>beam</span><span class=p>.</span><span class=nx>parDo</span><span class=p>(</span><span class=nx>computeWordLengthFn</span><span class=p>()));</span>
+</code></pre></div></div></div><p>In the example, our input <code>PCollection</code> contains <span class="language-java language-py"><code>String</code></span>
 <span class=language-go><code>string</code></span> values. We apply a
 <code>ParDo</code> transform that specifies a function (<code>ComputeWordLengthFn</code>) to compute
 the length of each string, and outputs the result to a new <code>PCollection</code> of
@@ -494,7 +565,7 @@ elements, the method can also take a parameter of type <code>OutputReceiver</cod
 provides a method for emitting elements. The parameter types must match the input
 and output types of your <code>DoFn</code> or the framework will raise an error. Note: <code>@Element</code> and
 <code>OutputReceiver</code> were introduced in Beam 2.5.0; if using an earlier release of Beam, a
-<code>ProcessContext</code> parameter should be used instead.</p><p class=language-py>Inside your <code>DoFn</code> subclass, you&rsquo;ll write a method <code>process</code> where you provide
+<code>ProcessContext</code> parameter should be used instead.</p><p class="language-py language-typescript">Inside your <code>DoFn</code> subclass, you&rsquo;ll write a method <code>process</code> where you provide
 the actual processing logic. You don&rsquo;t need to manually extract the elements
 from the input collection; the Beam SDKs handle that for you. Your <code>process</code> method
 should accept an argument <code>element</code>, which is the input element, and return an
@@ -530,7 +601,14 @@ or the framework will raise an error.</p><div class="language-java snippet"><div
 </span><span class=c1></span>	<span class=c1>// Input/output types are included in order in the brackets
 </span><span class=c1></span>	<span class=nx>register</span><span class=p>.</span><span class=nx>DoFn2x0</span><span class=p>[</span><span class=kt>string</span><span class=p>,</span> <span class=kd>func</span><span class=p>(</span><span class=kt>int</span><span class=p>)](</span><span class=o>&amp;</span><span class=nx>ComputeWordLengthFn</span><span class=p>{})</span>
 	<span class=nx>register</span><span class=p>.</span><span class=nx>Emitter1</span><span class=p>[</span><span class=kt>int</span><span class=p>]()</span>
-<span class=p>}</span></code></pre></div></div></div><p class=language-go>Simple DoFns can also be written as functions.</p><div class="language-go snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-go data-lang=go><span class=kd>func</span> <span class=nf>ComputeWordLengthFn</span><span class=p>(< [...]
+<span class=p>}</span></code></pre></div></div></div><div class="language-typescript snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-typescript data-lang=typescript><span class=kd>function</span> <span class=nx>computeWordLengthFn</span><span class=p>()</span><span class=o>:</span> <span class=n [...]
+  <span class=k>return</span> <span class=p>{</span>
+    <span class=nx>process</span>: <span class=kt>function</span><span class=o>*</span> <span class=p>(</span><span class=nx>element</span><span class=p>)</span> <span class=p>{</span>
+      <span class=nx>yield</span> <span class=nx>element</span><span class=p>.</span><span class=nx>length</span><span class=p>;</span>
+    <span class=p>},</span>
+  <span class=p>};</span>
+<span class=p>}</span>
+</code></pre></div></div></div><p class=language-go>Simple DoFns can also be written as functions.</p><div class="language-go snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-go data-lang=go><span class=kd>func</span> <span class=nf>ComputeWordLengthFn</span><span class=p>(</span><span class=nx>w [...]
 
 <span class=kd>func</span> <span class=nf>init</span><span class=p>()</span> <span class=p>{</span>
   <span class=c1>// 2 inputs and 0 outputs =&gt; DoFn2x0
@@ -555,7 +633,7 @@ serialize and cache the values in your pipeline. Your method should meet the
 following requirements:</p><span class=language-java><ul><li>You should not in any way modify an element returned by
 the <code>@Element</code> annotation or <code>ProcessContext.sideInput()</code> (the incoming
 elements from the input collection).</li><li>Once you output a value using <code>OutputReceiver.output()</code> you should not modify
-that value in any way.</li></ul></span><span class=language-py><ul><li>You should not in any way modify the <code>element</code> argument provided to the
+that value in any way.</li></ul></span><span class="language-py language-typescript"><ul><li>You should not in any way modify the <code>element</code> argument provided to the
 <code>process</code> method, or any side inputs.</li><li>Once you output a value using <code>yield</code> or <code>return</code>, you should not modify
 that value in any way.</li></ul></span><span class=language-go><ul><li>You should not in any way modify the parameters provided to the
 <code>ProcessElement</code> method, or any side inputs.</li><li>Once you output a value using an <code>emitter function</code>, you should not modify
@@ -563,11 +641,13 @@ that value in any way.</li></ul></span><h5 id=lightweight-dofns>4.2.1.3. Lightwe
 <code>ParDo</code> by providing a lightweight <code>DoFn</code> in-line, as
 <span class=language-java>an anonymous inner class instance</span>
 <span class=language-py>a lambda function</span>
-<span class=language-go>an anonymous function</span>.</p><p>Here&rsquo;s the previous example, <code>ParDo</code> with <code>ComputeLengthWordsFn</code>, with the
+<span class=language-go>an anonymous function</span>
+<span class=language-typescript>a function passed to <code>PCollection.map</code> or <code>PCollection.flatMap</code></span>.</p><p>Here&rsquo;s the previous example, <code>ParDo</code> with <code>ComputeLengthWordsFn</code>, with the
 <code>DoFn</code> specified as
 <span class=language-java>an anonymous inner class instance</span>
 <span class=language-py>a lambda function</span>
-<span class=language-go>an anonymous function</span>:</p><div class="language-java snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-java data-lang=java><span class=c1>// The input PCollection.
+<span class=language-go>an anonymous function</span>
+<span class=language-typescript>a function</span>:</p><div class="language-java snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-java data-lang=java><span class=c1>// The input PCollection.
 </span><span class=c1></span><span class=n>PCollection</span><span class=o>&lt;</span><span class=n>String</span><span class=o>&gt;</span> <span class=n>words</span> <span class=o>=</span> <span class=o>...;</span>
 
 <span class=c1>// Apply a ParDo with an anonymous DoFn to the PCollection words.
@@ -590,14 +670,18 @@ that value in any way.</li></ul></span><h5 id=lightweight-dofns>4.2.1.3. Lightwe
 
 <span class=nx>lengths</span> <span class=o>:=</span> <span class=nx>beam</span><span class=p>.</span><span class=nf>ParDo</span><span class=p>(</span><span class=nx>s</span><span class=p>,</span> <span class=kd>func</span> <span class=p>(</span><span class=nx>word</span> <span class=kt>string</span><span class=p>,</span> <span class=nx>emit</span> <span class=kd>func</span><span class=p>(</span><span class=kt>int</span><span class=p>))</span> <span class=p>{</span>
       <span class=nf>emit</span><span class=p>(</span><span class=nb>len</span><span class=p>(</span><span class=nx>word</span><span class=p>))</span>
-<span class=p>},</span> <span class=nx>words</span><span class=p>)</span></code></pre></div></div></div><p>If your <code>ParDo</code> performs a one-to-one mapping of input elements to output
+<span class=p>},</span> <span class=nx>words</span><span class=p>)</span></code></pre></div></div></div><div class="language-typescript snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-typescript data-lang=typescript><span class=c1>// The input PCollection of strings.
+</span><span class=c1></span><span class=nx>words</span> <span class=o>=</span> <span class=p>...</span>
+
+<span class=kr>const</span> <span class=nx>result</span> <span class=o>=</span> <span class=nx>words</span><span class=p>.</span><span class=nx>flatMap</span><span class=p>((</span><span class=nx>word</span><span class=p>)</span> <span class=o>=&gt;</span> <span class=p>[</span><span class=nx>word</span><span class=p>.</span><span class=nx>length</span><span class=p>]);</span>
+</code></pre></div></div></div><p>If your <code>ParDo</code> performs a one-to-one mapping of input elements to output
 elements&ndash;that is, for each input element, it applies a function that produces
 <em>exactly one</em> output element, <span class=language-go>you can return that
 element directly.</span><span class="language-java language-py">you can use the higher-level
-<span class=language-java><code>MapElements</code></span><span class=language-py><code>Map</code></span>
+<span class=language-java><code>MapElements</code></span><span class="language-py language-py"><code>Map</code></span>
 transform.</span><span class=language-java><code>MapElements</code> can accept an anonymous
 Java 8 lambda function for additional brevity.</span></p><p>Here&rsquo;s the previous example using <span class=language-java><code>MapElements</code></span>
-<span class=language-py><code>Map</code></span><span class=language-go>a direct return</span>:</p><div class="language-java snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-java data-lang=java><span class=c1>// The input PCollection.
+<span class="language-py language-typescript"><code>Map</code></span><span class=language-go>a direct return</span>:</p><div class="language-java snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-java data-lang=java><span class=c1>// The input PCollection.
 </span><span class=c1></span><span class=n>PCollection</span><span class=o>&lt;</span><span class=n>String</span><span class=o>&gt;</span> <span class=n>words</span> <span class=o>=</span> <span class=o>...;</span>
 
 <span class=c1>// Apply a MapElements with an anonymous lambda function to the PCollection words.
@@ -618,7 +702,11 @@ Java 8 lambda function for additional brevity.</span></p><p>Here&rsquo;s the pre
 </span><span class=c1>// Save the result as the PCollection wordLengths.
 </span><span class=c1></span><span class=nx>wordLengths</span> <span class=o>:=</span> <span class=nx>beam</span><span class=p>.</span><span class=nf>ParDo</span><span class=p>(</span><span class=nx>s</span><span class=p>,</span> <span class=kd>func</span><span class=p>(</span><span class=nx>word</span> <span class=kt>string</span><span class=p>)</span> <span class=kt>int</span> <span class=p>{</span>
 	<span class=k>return</span> <span class=nb>len</span><span class=p>(</span><span class=nx>word</span><span class=p>)</span>
-<span class=p>},</span> <span class=nx>words</span><span class=p>)</span></code></pre></div></div></div><p><span class=language-java></p><blockquote><p><strong>Note:</strong> You can use Java 8 lambda functions with several other Beam
+<span class=p>},</span> <span class=nx>words</span><span class=p>)</span></code></pre></div></div></div><div class="language-typescript snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-typescript data-lang=typescript><span class=c1>// The input PCollection of string.
+</span><span class=c1></span><span class=nx>words</span> <span class=o>=</span> <span class=p>...</span>
+
+<span class=kr>const</span> <span class=nx>result</span> <span class=o>=</span> <span class=nx>words</span><span class=p>.</span><span class=nx>map</span><span class=p>((</span><span class=nx>word</span><span class=p>)</span> <span class=o>=&gt;</span> <span class=nx>word</span><span class=p>.</span><span class=nx>length</span><span class=p>);</span>
+</code></pre></div></div></div><p><span class=language-java></p><blockquote><p><strong>Note:</strong> You can use Java 8 lambda functions with several other Beam
 transforms, including <code>Filter</code>, <code>FlatMapElements</code>, and <code>Partition</code>.</p></blockquote></span><p><span class=language-go></p><blockquote><p><strong>Note:</strong> Anonymous function DoFns may not work on distributed runners.
 It&rsquo;s recommended to use named functions and register them with <code>register.FunctionXxY</code> in
 an <code>init()</code> block.</p></blockquote></span><h5 id=dofn>4.2.1.4. DoFn lifecycle</h5><p>Here is a sequence diagram that shows the lifecycle of the DoFn during
@@ -662,16 +750,39 @@ jump, [3]
 tree, [2]
 ...
 </code></pre><p>Thus, <code>GroupByKey</code> represents a transform from a multimap (multiple keys to
-individual values) to a uni-map (unique keys to collections of values).</p><p><span class=language-java>Using <code>GroupByKey</code> is straightforward:</span></p><div class="language-java snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-java data-lang=java><span class=c1>// The input PCollection.
+individual values) to a uni-map (unique keys to collections of values).</p><p><span class=language-java>Using <code>GroupByKey</code> is straightforward:</span></p><p class="language-py language-typescript">While all SDKs have a <code>GroupByKey</code> transform, using <code>GroupBy</code> is
+generally more natural.
+The <code>GroupBy</code> transform can be parameterized by the name(s) of properties
+on which to group the elements of the PCollection, or a function taking
+the each element as input that maps to a key on which to do grouping.</p><div class="language-java snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-java data-lang=java><span class=c1>// The input PCollection.
 </span><span class=c1></span> <span class=n>PCollection</span><span class=o>&lt;</span><span class=n>KV</span><span class=o>&lt;</span><span class=n>String</span><span class=o>,</span> <span class=n>String</span><span class=o>&gt;&gt;</span> <span class=n>mapped</span> <span class=o>=</span> <span class=o>...;</span>
 
 <span class=c1>// Apply GroupByKey to the PCollection mapped.
 </span><span class=c1>// Save the result as the PCollection reduced.
 </span><span class=c1></span><span class=n>PCollection</span><span class=o>&lt;</span><span class=n>KV</span><span class=o>&lt;</span><span class=n>String</span><span class=o>,</span> <span class=n>Iterable</span><span class=o>&lt;</span><span class=n>String</span><span class=o>&gt;&gt;&gt;</span> <span class=n>reduced</span> <span class=o>=</span>
- <span class=n>mapped</span><span class=o>.</span><span class=na>apply</span><span class=o>(</span><span class=n>GroupByKey</span><span class=o>.&lt;</span><span class=n>String</span><span class=o>,</span> <span class=n>String</span><span class=o>&gt;</span><span class=n>create</span><span class=o>());</span></code></pre></div></div></div><div class="language-go snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom titl [...]
+ <span class=n>mapped</span><span class=o>.</span><span class=na>apply</span><span class=o>(</span><span class=n>GroupByKey</span><span class=o>.&lt;</span><span class=n>String</span><span class=o>,</span> <span class=n>String</span><span class=o>&gt;</span><span class=n>create</span><span class=o>());</span></code></pre></div></div></div><div class="language-py snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom titl [...]
+<span class=n>words_and_counts</span> <span class=o>=</span> <span class=o>...</span>
+
+
+<span class=n>grouped_words</span> <span class=o>=</span> <span class=n>words_and_counts</span> <span class=o>|</span> <span class=n>beam</span><span class=o>.</span><span class=n>GroupByKey</span><span class=p>()</span></code></pre></div></div></div><div class="language-go snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=c [...]
 </span><span class=c1>// from an input slice of stringPair (struct with K, V string fields).
 </span><span class=c1></span><span class=nx>pairs</span> <span class=o>:=</span> <span class=nf>CreateAndSplit</span><span class=p>(</span><span class=nx>s</span><span class=p>,</span> <span class=nx>input</span><span class=p>)</span>
-<span class=nx>keyed</span> <span class=o>:=</span> <span class=nx>beam</span><span class=p>.</span><span class=nf>GroupByKey</span><span class=p>(</span><span class=nx>s</span><span class=p>,</span> <span class=nx>pairs</span><span class=p>)</span></code></pre></div></div></div><h5 id=groupbykey-and-unbounded-pcollections>4.2.2.1 GroupByKey and unbounded PCollections</h5><p>If you are using unbounded <code>PCollection</code>s, you must use either <a href=#setting-your-pcollections-windo [...]
+<span class=nx>keyed</span> <span class=o>:=</span> <span class=nx>beam</span><span class=p>.</span><span class=nf>GroupByKey</span><span class=p>(</span><span class=nx>s</span><span class=p>,</span> <span class=nx>pairs</span><span class=p>)</span></code></pre></div></div></div><div class="language-typescript snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg> [...]
+</span><span class=c1>//    {word: &#34;cat&#34;, score: 1}, {word: &#34;dog&#34;, score: 5}, {word: &#34;cat&#34;, score: 5}, ...
+</span><span class=c1></span><span class=kr>const</span> <span class=nx>scores</span> : <span class=kt>PCollection</span><span class=o>&lt;</span><span class=p>{</span><span class=nx>word</span>: <span class=kt>string</span><span class=p>,</span> <span class=nx>score</span>: <span class=kt>number</span><span class=p>}</span><span class=o>&gt;</span> <span class=o>=</span> <span class=p>...</span>
+
+<span class=c1>// This will produce a PCollection with elements like
+</span><span class=c1>//   {key: &#34;cat&#34;, value: [{ word: &#34;cat&#34;, score: 1 },
+</span><span class=c1>//                        { word: &#34;cat&#34;, score: 5 }, ...]}
+</span><span class=c1>//   {key: &#34;dog&#34;, value: [{ word: &#34;dog&#34;, score: 5 }, ...]}
+</span><span class=c1></span><span class=kr>const</span> <span class=nx>grouped_by_word</span> <span class=o>=</span> <span class=nx>scores</span><span class=p>.</span><span class=nx>apply</span><span class=p>(</span><span class=nx>beam</span><span class=p>.</span><span class=nx>groupBy</span><span class=p>(</span><span class=s2>&#34;word&#34;</span><span class=p>));</span>
+
+<span class=c1>// This will produce a PCollection with elements like
+</span><span class=c1>//   {key: 3, value: [{ word: &#34;cat&#34;, score: 1 },
+</span><span class=c1>//                    { word: &#34;dog&#34;, score: 5 },
+</span><span class=c1>//                    { word: &#34;cat&#34;, score: 5 }, ...]}
+</span><span class=c1></span><span class=kr>const</span> <span class=nx>by_word_length</span> <span class=o>=</span> <span class=nx>scores</span><span class=p>.</span><span class=nx>apply</span><span class=p>(</span><span class=nx>beam</span><span class=p>.</span><span class=nx>groupBy</span><span class=p>((</span><span class=nx>x</span><span class=p>)</span> <span class=o>=&gt;</span> <span class=nx>x</span><span class=p>.</span><span class=nx>word</span><span class=p>.</span><span clas [...]
+</code></pre></div></div></div><h5 id=groupbykey-and-unbounded-pcollections>4.2.2.1 GroupByKey and unbounded PCollections</h5><p>If you are using unbounded <code>PCollection</code>s, you must use either <a href=#setting-your-pcollections-windowing-function>non-global
 windowing</a> or an
 <a href=#triggers>aggregation trigger</a> in order to perform a <code>GroupByKey</code> or
 <a href=#cogroupbykey>CoGroupByKey</a>. This is because a bounded <code>GroupByKey</code> or
@@ -785,7 +896,22 @@ data contains names and phone numbers.</p><div class="language-java snippet"><di
 	<span class=p>{</span><span class=s>&#34;carl&#34;</span><span class=p>,</span> <span class=s>&#34;444-555-6666&#34;</span><span class=p>},</span>
 <span class=p>}</span>
 <span class=nx>emails</span> <span class=o>:=</span> <span class=nf>CreateAndSplit</span><span class=p>(</span><span class=nx>s</span><span class=p>.</span><span class=nf>Scope</span><span class=p>(</span><span class=s>&#34;CreateEmails&#34;</span><span class=p>),</span> <span class=nx>emailSlice</span><span class=p>)</span>
-<span class=nx>phones</span> <span class=o>:=</span> <span class=nf>CreateAndSplit</span><span class=p>(</span><span class=nx>s</span><span class=p>.</span><span class=nf>Scope</span><span class=p>(</span><span class=s>&#34;CreatePhones&#34;</span><span class=p>),</span> <span class=nx>phoneSlice</span><span class=p>)</span></code></pre></div></div></div><p>After <code>CoGroupByKey</code>, the resulting data contains all data associated with each
+<span class=nx>phones</span> <span class=o>:=</span> <span class=nf>CreateAndSplit</span><span class=p>(</span><span class=nx>s</span><span class=p>.</span><span class=nf>Scope</span><span class=p>(</span><span class=s>&#34;CreatePhones&#34;</span><span class=p>),</span> <span class=nx>phoneSlice</span><span class=p>)</span></code></pre></div></div></div><div class="language-typescript snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data- [...]
+  <span class=p>{</span> <span class=nx>name</span><span class=o>:</span> <span class=s2>&#34;amy&#34;</span><span class=p>,</span> <span class=nx>email</span><span class=o>:</span> <span class=s2>&#34;amy@example.com&#34;</span> <span class=p>},</span>
+  <span class=p>{</span> <span class=nx>name</span><span class=o>:</span> <span class=s2>&#34;carl&#34;</span><span class=p>,</span> <span class=nx>email</span><span class=o>:</span> <span class=s2>&#34;carl@example.com&#34;</span> <span class=p>},</span>
+  <span class=p>{</span> <span class=nx>name</span><span class=o>:</span> <span class=s2>&#34;julia&#34;</span><span class=p>,</span> <span class=nx>email</span><span class=o>:</span> <span class=s2>&#34;julia@example.com&#34;</span> <span class=p>},</span>
+  <span class=p>{</span> <span class=nx>name</span><span class=o>:</span> <span class=s2>&#34;carl&#34;</span><span class=p>,</span> <span class=nx>email</span><span class=o>:</span> <span class=s2>&#34;carl@email.com&#34;</span> <span class=p>},</span>
+<span class=p>];</span>
+<span class=kr>const</span> <span class=nx>phones_list</span> <span class=o>=</span> <span class=p>[</span>
+  <span class=p>{</span> <span class=nx>name</span><span class=o>:</span> <span class=s2>&#34;amy&#34;</span><span class=p>,</span> <span class=nx>phone</span><span class=o>:</span> <span class=s2>&#34;111-222-3333&#34;</span> <span class=p>},</span>
+  <span class=p>{</span> <span class=nx>name</span><span class=o>:</span> <span class=s2>&#34;james&#34;</span><span class=p>,</span> <span class=nx>phone</span><span class=o>:</span> <span class=s2>&#34;222-333-4444&#34;</span> <span class=p>},</span>
+  <span class=p>{</span> <span class=nx>name</span><span class=o>:</span> <span class=s2>&#34;amy&#34;</span><span class=p>,</span> <span class=nx>phone</span><span class=o>:</span> <span class=s2>&#34;333-444-5555&#34;</span> <span class=p>},</span>
+  <span class=p>{</span> <span class=nx>name</span><span class=o>:</span> <span class=s2>&#34;carl&#34;</span><span class=p>,</span> <span class=nx>phone</span><span class=o>:</span> <span class=s2>&#34;444-555-6666&#34;</span> <span class=p>},</span>
+<span class=p>];</span>
+
+<span class=kr>const</span> <span class=nx>emails</span> <span class=o>=</span> <span class=nx>root</span><span class=p>.</span><span class=nx>apply</span><span class=p>(</span><span class=nx>beam</span><span class=p>.</span><span class=nx>create</span><span class=p>(</span><span class=nx>emails_list</span><span class=p>));</span>
+<span class=kr>const</span> <span class=nx>phones</span> <span class=o>=</span> <span class=nx>root</span><span class=p>.</span><span class=nx>apply</span><span class=p>(</span><span class=nx>beam</span><span class=p>.</span><span class=nx>create</span><span class=p>(</span><span class=nx>phones_list</span><span class=p>));</span>
+</code></pre></div></div></div><p>After <code>CoGroupByKey</code>, the resulting data contains all data associated with each
 unique key from any of the input collections.</p><div class="language-java snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-java data-lang=java><span class=kd>final</span> <span class=n>TupleTag</span><span class=o>&lt;</span><span class=n>String</span><span class=o>&gt;</span> <span class=n>emai [...]
 <span class=kd>final</span> <span class=n>TupleTag</span><span class=o>&lt;</span><span class=n>String</span><span class=o>&gt;</span> <span class=n>phonesTag</span> <span class=o>=</span> <span class=k>new</span> <span class=n>TupleTag</span><span class=o>&lt;&gt;();</span>
 
@@ -852,7 +978,43 @@ unique key from any of the input collections.</p><div class="language-java snipp
 		<span class=nx>Emails</span><span class=p>:</span> <span class=p>[]</span><span class=kt>string</span><span class=p>{</span><span class=s>&#34;julia@example.com&#34;</span><span class=p>},</span>
 		<span class=nx>Phones</span><span class=p>:</span> <span class=p>[]</span><span class=kt>string</span><span class=p>{},</span>
 	<span class=p>},</span>
-<span class=p>}</span></code></pre></div></div></div><p class="language-java language-py">The following code example joins the two <code>PCollection</code>s with <code>CoGroupByKey</code>,
+<span class=p>}</span></code></pre></div></div></div><div class="language-typescript snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-typescript data-lang=typescript><span class=kr>const</span> <span class=nx>results</span> <span class=o>=</span> <span class=p>[</span>
+  <span class=p>{</span>
+    <span class=nx>name</span><span class=o>:</span> <span class=s2>&#34;amy&#34;</span><span class=p>,</span>
+    <span class=nx>values</span><span class=o>:</span> <span class=p>{</span>
+      <span class=nx>emails</span><span class=o>:</span> <span class=p>[{</span> <span class=nx>name</span><span class=o>:</span> <span class=s2>&#34;amy&#34;</span><span class=p>,</span> <span class=nx>email</span><span class=o>:</span> <span class=s2>&#34;amy@example.com&#34;</span> <span class=p>}],</span>
+      <span class=nx>phones</span><span class=o>:</span> <span class=p>[</span>
+        <span class=p>{</span> <span class=nx>name</span><span class=o>:</span> <span class=s2>&#34;amy&#34;</span><span class=p>,</span> <span class=nx>phone</span><span class=o>:</span> <span class=s2>&#34;111-222-3333&#34;</span> <span class=p>},</span>
+        <span class=p>{</span> <span class=nx>name</span><span class=o>:</span> <span class=s2>&#34;amy&#34;</span><span class=p>,</span> <span class=nx>phone</span><span class=o>:</span> <span class=s2>&#34;333-444-5555&#34;</span> <span class=p>},</span>
+      <span class=p>],</span>
+    <span class=p>},</span>
+  <span class=p>},</span>
+  <span class=p>{</span>
+    <span class=nx>name</span><span class=o>:</span> <span class=s2>&#34;carl&#34;</span><span class=p>,</span>
+    <span class=nx>values</span><span class=o>:</span> <span class=p>{</span>
+      <span class=nx>emails</span><span class=o>:</span> <span class=p>[</span>
+        <span class=p>{</span> <span class=nx>name</span><span class=o>:</span> <span class=s2>&#34;carl&#34;</span><span class=p>,</span> <span class=nx>email</span><span class=o>:</span> <span class=s2>&#34;carl@example.com&#34;</span> <span class=p>},</span>
+        <span class=p>{</span> <span class=nx>name</span><span class=o>:</span> <span class=s2>&#34;carl&#34;</span><span class=p>,</span> <span class=nx>email</span><span class=o>:</span> <span class=s2>&#34;carl@email.com&#34;</span> <span class=p>},</span>
+      <span class=p>],</span>
+      <span class=nx>phones</span><span class=o>:</span> <span class=p>[{</span> <span class=nx>name</span><span class=o>:</span> <span class=s2>&#34;carl&#34;</span><span class=p>,</span> <span class=nx>phone</span><span class=o>:</span> <span class=s2>&#34;444-555-6666&#34;</span> <span class=p>}],</span>
+    <span class=p>},</span>
+  <span class=p>},</span>
+  <span class=p>{</span>
+    <span class=nx>name</span><span class=o>:</span> <span class=s2>&#34;james&#34;</span><span class=p>,</span>
+    <span class=nx>values</span><span class=o>:</span> <span class=p>{</span>
+      <span class=nx>emails</span><span class=o>:</span> <span class=p>[],</span>
+      <span class=nx>phones</span><span class=o>:</span> <span class=p>[{</span> <span class=nx>name</span><span class=o>:</span> <span class=s2>&#34;james&#34;</span><span class=p>,</span> <span class=nx>phone</span><span class=o>:</span> <span class=s2>&#34;222-333-4444&#34;</span> <span class=p>}],</span>
+    <span class=p>},</span>
+  <span class=p>},</span>
+  <span class=p>{</span>
+    <span class=nx>name</span><span class=o>:</span> <span class=s2>&#34;julia&#34;</span><span class=p>,</span>
+    <span class=nx>values</span><span class=o>:</span> <span class=p>{</span>
+      <span class=nx>emails</span><span class=o>:</span> <span class=p>[{</span> <span class=nx>name</span><span class=o>:</span> <span class=s2>&#34;julia&#34;</span><span class=p>,</span> <span class=nx>email</span><span class=o>:</span> <span class=s2>&#34;julia@example.com&#34;</span> <span class=p>}],</span>
+      <span class=nx>phones</span><span class=o>:</span> <span class=p>[],</span>
+    <span class=p>},</span>
+  <span class=p>},</span>
+<span class=p>];</span>
+</code></pre></div></div></div><p class="language-java language-py language-typescript">The following code example joins the two <code>PCollection</code>s with <code>CoGroupByKey</code>,
 followed by a <code>ParDo</code> to consume the result. Then, the code uses tags to look up
 and format data from each collection.</p><p class=language-go>The following code example joins the two <code>PCollection</code>s with <code>CoGroupByKey</code>,
 followed by a <code>ParDo</code> to consume the result. The ordering of the <code>DoFn</code> iterator
@@ -932,7 +1094,15 @@ parameters maps to the ordering of the <code>CoGroupByKey</code> inputs.</p><div
 		<span class=nx>Emails</span><span class=p>:</span> <span class=p>[]</span><span class=kt>string</span><span class=p>{</span><span class=s>&#34;julia@example.com&#34;</span><span class=p>},</span>
 		<span class=nx>Phones</span><span class=p>:</span> <span class=p>[]</span><span class=kt>string</span><span class=p>{},</span>
 	<span class=p>},</span>
-<span class=p>}</span></code></pre></div></div></div><p>The formatted data looks like this:</p><div class="language-java snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-java data-lang=java><span class=kd>final</span> <span class=n>List</span><span class=o>&lt;</span><span class=n>String</span><s [...]
+<span class=p>}</span></code></pre></div></div></div><div class="language-typescript snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-typescript data-lang=typescript><span class=kr>const</span> <span class=nx>formatted_results_pcoll</span> <span class=o>=</span> <span class=nx>beam</span>
+  <span class=p>.</span><span class=nx>P</span><span class=p>({</span> <span class=nx>emails</span><span class=p>,</span> <span class=nx>phones</span> <span class=p>})</span>
+  <span class=p>.</span><span class=nx>apply</span><span class=p>(</span><span class=nx>beam</span><span class=p>.</span><span class=nx>coGroupBy</span><span class=p>(</span><span class=s2>&#34;name&#34;</span><span class=p>))</span>
+  <span class=p>.</span><span class=nx>map</span><span class=p>(</span><span class=kd>function</span> <span class=nx>formatResults</span><span class=p>({</span> <span class=nx>key</span><span class=p>,</span> <span class=nx>values</span> <span class=p>})</span> <span class=p>{</span>
+    <span class=kr>const</span> <span class=nx>emails</span> <span class=o>=</span> <span class=nx>values</span><span class=p>.</span><span class=nx>emails</span><span class=p>.</span><span class=nx>map</span><span class=p>((</span><span class=nx>x</span><span class=p>)</span> <span class=o>=&gt;</span> <span class=nx>x</span><span class=p>.</span><span class=nx>email</span><span class=p>).</span><span class=nx>sort</span><span class=p>();</span>
+    <span class=kr>const</span> <span class=nx>phones</span> <span class=o>=</span> <span class=nx>values</span><span class=p>.</span><span class=nx>phones</span><span class=p>.</span><span class=nx>map</span><span class=p>((</span><span class=nx>x</span><span class=p>)</span> <span class=o>=&gt;</span> <span class=nx>x</span><span class=p>.</span><span class=nx>phone</span><span class=p>).</span><span class=nx>sort</span><span class=p>();</span>
+    <span class=k>return</span> <span class=sb>`</span><span class=si>${</span><span class=nx>key</span><span class=si>}</span><span class=sb>; [</span><span class=si>${</span><span class=nx>emails</span><span class=si>}</span><span class=sb>]; [</span><span class=si>${</span><span class=nx>phones</span><span class=si>}</span><span class=sb>]`</span><span class=p>;</span>
+  <span class=p>});</span>
+</code></pre></div></div></div><p>The formatted data looks like this:</p><div class="language-java snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-java data-lang=java><span class=kd>final</span> <span class=n>List</span><span class=o>&lt;</span><span class=n>String</span><span class=o>&gt;</span [...]
     <span class=n>Arrays</span><span class=o>.</span><span class=na>asList</span><span class=o>(</span>
         <span class=s>&#34;amy; [&#39;amy@example.com&#39;]; [&#39;111-222-3333&#39;, &#39;333-444-5555&#39;]&#34;</span><span class=o>,</span>
         <span class=s>&#34;carl; [&#39;carl@email.com&#39;, &#39;carl@example.com&#39;]; [&#39;444-555-6666&#39;]&#34;</span><span class=o>,</span>
@@ -947,9 +1117,16 @@ parameters maps to the ordering of the <code>CoGroupByKey</code> inputs.</p><div
 	<span class=s>&#34;carl; [&#39;carl@email.com&#39;, &#39;carl@example.com&#39;]; [&#39;444-555-6666&#39;]&#34;</span><span class=p>,</span>
 	<span class=s>&#34;james; []; [&#39;222-333-4444&#39;]&#34;</span><span class=p>,</span>
 	<span class=s>&#34;julia; [&#39;julia@example.com&#39;]; []&#34;</span><span class=p>,</span>
-<span class=p>}</span></code></pre></div></div></div><h4 id=combine>4.2.4. Combine</h4><p><span class=language-java><a href=https://beam.apache.org/releases/javadoc/2.40.0/index.html?org/apache/beam/sdk/transforms/Combine.html><code>Combine</code></a></span>
+<span class=p>}</span></code></pre></div></div></div><div class="language-typescript snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-typescript data-lang=typescript><span class=kr>const</span> <span class=nx>formatted_results</span> <span class=o>=</span> <span class=p>[</span>
+  <span class=s2>&#34;amy; [amy@example.com]; [111-222-3333,333-444-5555]&#34;</span><span class=p>,</span>
+  <span class=s2>&#34;carl; [carl@email.com,carl@example.com]; [444-555-6666]&#34;</span><span class=p>,</span>
+  <span class=s2>&#34;james; []; [222-333-4444]&#34;</span><span class=p>,</span>
+  <span class=s2>&#34;julia; [julia@example.com]; []&#34;</span><span class=p>,</span>
+<span class=p>];</span>
+</code></pre></div></div></div><h4 id=combine>4.2.4. Combine</h4><p><span class=language-java><a href=https://beam.apache.org/releases/javadoc/2.40.0/index.html?org/apache/beam/sdk/transforms/Combine.html><code>Combine</code></a></span>
 <span class=language-py><a href=https://github.com/apache/beam/blob/master/sdks/python/apache_beam/transforms/core.py><code>Combine</code></a></span>
 <span class=language-go><a href=https://github.com/apache/beam/blob/master/sdks/go/pkg/beam/combine.go#L27><code>Combine</code></a></span>
+<span class=language-typescript><a href=https://github.com/apache/beam/blob/master/sdks/typescript/src/apache_beam/transforms/group_and_combine.ts><code>Combine</code></a></span>
 is a Beam transform for combining collections of elements or values in your
 data. <code>Combine</code> has variants that work on entire <code>PCollection</code>s, and some that
 combine the values for each key in <code>PCollection</code>s of key/value pairs.</p><p>When you apply a <code>Combine</code> transform, you must provide the function that
@@ -971,7 +1148,12 @@ term for this optimization is &ldquo;mapper-side combine.&rdquo;</li><li><strong
 size by a lot, it is useful to combine elements as they emerge from a
 streaming shuffle. This spreads out the cost of doing combines over the time
 that your streaming computation might be idle. Incremental combining also
-reduces the storage of intermediate accumulators.</li></ul><h5 id=simple-combines>4.2.4.1. Simple combinations using simple functions</h5><p>The following example code shows a simple combine function.</p><div class="language-java snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-java data-lang=jav [...]
+reduces the storage of intermediate accumulators.</li></ul><h5 id=simple-combines>4.2.4.1. Simple combinations using simple functions</h5><p>The following example code shows a simple combine function.
+<span class=language-typescript>Combining is done by modifying a grouping transform with the <code>combining</code> method.
+This method takes three parameters: the value to combine (either as a named
+property of the input elements, or a function of the entire input),
+the combining operation (either a binary function or a <code>CombineFn</code>),
+and finally a name for the combined value in the output object.</span></p><div class="language-java snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-java data-lang=java><span class=c1>// Sum a collection of Integer values. The function SumInts implements the interface SerializableFunction.
 </span><span class=c1></span><span class=kd>public</span> <span class=kd>static</span> <span class=kd>class</span> <span class=nc>SumInts</span> <span class=kd>implements</span> <span class=n>SerializableFunction</span><span class=o>&lt;</span><span class=n>Iterable</span><span class=o>&lt;</span><span class=n>Integer</span><span class=o>&gt;,</span> <span class=n>Integer</span><span class=o>&gt;</span> <span class=o>{</span>
   <span class=nd>@Override</span>
   <span class=kd>public</span> <span class=n>Integer</span> <span class=nf>apply</span><span class=o>(</span><span class=n>Iterable</span><span class=o>&lt;</span><span class=n>Integer</span><span class=o>&gt;</span> <span class=n>input</span><span class=o>)</span> <span class=o>{</span>
@@ -1027,7 +1209,15 @@ the type of the output.</p></p><div class="language-go snippet"><div class="note
 
 <span class=kd>func</span> <span class=nf>globallyBoundedSumInts</span><span class=p>(</span><span class=nx>s</span> <span class=nx>beam</span><span class=p>.</span><span class=nx>Scope</span><span class=p>,</span> <span class=nx>bound</span> <span class=kt>int</span><span class=p>,</span> <span class=nx>ints</span> <span class=nx>beam</span><span class=p>.</span><span class=nx>PCollection</span><span class=p>)</span> <span class=nx>beam</span><span class=p>.</span><span class=nx>PCollec [...]
 	<span class=k>return</span> <span class=nx>beam</span><span class=p>.</span><span class=nf>Combine</span><span class=p>(</span><span class=nx>s</span><span class=p>,</span> <span class=o>&amp;</span><span class=nx>boundedSum</span><span class=p>{</span><span class=nx>Bound</span><span class=p>:</span> <span class=nx>bound</span><span class=p>},</span> <span class=nx>ints</span><span class=p>)</span>
-<span class=p>}</span></code></pre></div></div></div><h5 id=advanced-combines>4.2.4.2. Advanced combinations using CombineFn</h5><p>For more complex combine functions, you can define a
+<span class=p>}</span></code></pre></div></div></div><div class="language-typescript snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-typescript data-lang=typescript><span class=kr>const</span> <span class=nx>pcoll</span> <span class=o>=</span> <span class=nx>root</span><span class=p>.</span><spa [...]
+<span class=kr>const</span> <span class=nx>result</span> <span class=o>=</span> <span class=nx>pcoll</span><span class=p>.</span><span class=nx>apply</span><span class=p>(</span>
+  <span class=nx>beam</span>
+    <span class=p>.</span><span class=nx>groupGlobally</span><span class=p>()</span>
+    <span class=p>.</span><span class=nx>combining</span><span class=p>((</span><span class=nx>c</span><span class=p>)</span> <span class=o>=&gt;</span> <span class=nx>c</span><span class=p>,</span> <span class=p>(</span><span class=nx>x</span><span class=p>,</span> <span class=nx>y</span><span class=p>)</span> <span class=o>=&gt;</span> <span class=nx>x</span> <span class=o>+</span> <span class=nx>y</span><span class=p>,</span> <span class=s2>&#34;sum&#34;</span><span class=p>)</span>
+    <span class=p>.</span><span class=nx>combining</span><span class=p>((</span><span class=nx>c</span><span class=p>)</span> <span class=o>=&gt;</span> <span class=nx>c</span><span class=p>,</span> <span class=p>(</span><span class=nx>x</span><span class=p>,</span> <span class=nx>y</span><span class=p>)</span> <span class=o>=&gt;</span> <span class=nx>x</span> <span class=o>*</span> <span class=nx>y</span><span class=p>,</span> <span class=s2>&#34;product&#34;</span><span class=p>)</span>
+<span class=p>);</span>
+<span class=kr>const</span> <span class=nx>expected</span> <span class=o>=</span> <span class=p>{</span> <span class=nx>sum</span>: <span class=kt>1111</span><span class=p>,</span> <span class=nx>product</span>: <span class=kt>1000000</span> <span class=p>}</span>
+</code></pre></div></div></div><h5 id=advanced-combines>4.2.4.2. Advanced combinations using CombineFn</h5><p>For more complex combine functions, you can define a
 <span class="language-java language-py">subclass of</span><code>CombineFn</code>.
 You should use a <code>CombineFn</code> if the combine function requires a more sophisticated
 accumulator, must perform additional pre- or post-processing, might change the
@@ -1120,7 +1310,20 @@ mean average:</p><div class="language-java snippet"><div class="notebook-skip co
 
 <span class=kd>func</span> <span class=nf>init</span><span class=p>()</span> <span class=p>{</span>
 	<span class=nx>register</span><span class=p>.</span><span class=nx>Combiner3</span><span class=p>[</span><span class=nx>averageAccum</span><span class=p>,</span> <span class=kt>int</span><span class=p>,</span> <span class=kt>float64</span><span class=p>](</span><span class=o>&amp;</span><span class=nx>averageFn</span><span class=p>{})</span>
-<span class=p>}</span></code></pre></div></div></div><span class=language-go><blockquote><p><strong>Note</strong>: Only <code>MergeAccumulators</code> is a required method. The others will have a default interpretation
+<span class=p>}</span></code></pre></div></div></div><div class="language-go snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-go data-lang=go><span class=kd>const</span> <span class=nx>meanCombineFn</span><span class=p>:</span> <span class=nx>beam</span><span class=p>.</span><span class=nx>Combin [...]
+  <span class=p>{</span>
+    <span class=nx>createAccumulator</span><span class=p>:</span> <span class=p>()</span> <span class=p>=&gt;</span> <span class=p>[</span><span class=mi>0</span><span class=p>,</span> <span class=mi>0</span><span class=p>],</span>
+    <span class=nx>addInput</span><span class=p>:</span> <span class=p>([</span><span class=nx>sum</span><span class=p>,</span> <span class=nx>count</span><span class=p>]:</span> <span class=p>[</span><span class=nx>number</span><span class=p>,</span> <span class=nx>number</span><span class=p>],</span> <span class=nx>i</span><span class=p>:</span> <span class=nx>number</span><span class=p>)</span> <span class=p>=&gt;</span> <span class=p>[</span>
+      <span class=nx>sum</span> <span class=o>+</span> <span class=nx>i</span><span class=p>,</span>
+      <span class=nx>count</span> <span class=o>+</span> <span class=mi>1</span><span class=p>,</span>
+    <span class=p>],</span>
+    <span class=nx>mergeAccumulators</span><span class=p>:</span> <span class=p>(</span><span class=nx>accumulators</span><span class=p>:</span> <span class=p>[</span><span class=nx>number</span><span class=p>,</span> <span class=nx>number</span><span class=p>][])</span> <span class=p>=&gt;</span>
+      <span class=nx>accumulators</span><span class=p>.</span><span class=nf>reduce</span><span class=p>(([</span><span class=nx>sum0</span><span class=p>,</span> <span class=nx>count0</span><span class=p>],</span> <span class=p>[</span><span class=nx>sum1</span><span class=p>,</span> <span class=nx>count1</span><span class=p>])</span> <span class=p>=&gt;</span> <span class=p>[</span>
+        <span class=nx>sum0</span> <span class=o>+</span> <span class=nx>sum1</span><span class=p>,</span>
+        <span class=nx>count0</span> <span class=o>+</span> <span class=nx>count1</span><span class=p>,</span>
+      <span class=p>]),</span>
+    <span class=nx>extractOutput</span><span class=p>:</span> <span class=p>([</span><span class=nx>sum</span><span class=p>,</span> <span class=nx>count</span><span class=p>]:</span> <span class=p>[</span><span class=nx>number</span><span class=p>,</span> <span class=nx>number</span><span class=p>])</span> <span class=p>=&gt;</span> <span class=nx>sum</span> <span class=o>/</span> <span class=nx>count</span><span class=p>,</span>
+  <span class=p>};</span></code></pre></div></div></div><span class=language-go><blockquote><p><strong>Note</strong>: Only <code>MergeAccumulators</code> is a required method. The others will have a default interpretation
 based on the accumulator type.</p></blockquote></span><h5 id=combining-pcollection>4.2.4.3. Combining a PCollection into a single value</h5><p>Use the global combine to transform all of the elements in a given <code>PCollection</code>
 into a single value, represented in your pipeline as a new <code>PCollection</code>
 containing one element. The following example code shows how to apply the Beam
@@ -1134,7 +1337,10 @@ of integers.</p><div class="language-java snippet"><div class="notebook-skip cod
 <span class=c1># the elements in the input PCollection.</span>
 <span class=n>pc</span> <span class=o>=</span> <span class=o>...</span>
 
-<span class=n>average</span> <span class=o>=</span> <span class=n>pc</span> <span class=o>|</span> <span class=n>beam</span><span class=o>.</span><span class=n>CombineGlobally</span><span class=p>(</span><span class=n>AverageFn</span><span class=p>())</span></code></pre></div></div></div><div class="language-go snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg [...]
+<span class=n>average</span> <span class=o>=</span> <span class=n>pc</span> <span class=o>|</span> <span class=n>beam</span><span class=o>.</span><span class=n>CombineGlobally</span><span class=p>(</span><span class=n>AverageFn</span><span class=p>())</span></code></pre></div></div></div><div class="language-go snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg [...]
+<span class=kd>const</span> <span class=nx>result</span> <span class=p>=</span> <span class=nx>pcoll</span><span class=p>.</span><span class=nf>apply</span><span class=p>(</span>
+  <span class=nx>beam</span><span class=p>.</span><span class=nf>groupGlobally</span><span class=p>().</span><span class=nf>combining</span><span class=p>((</span><span class=nx>c</span><span class=p>)</span> <span class=p>=&gt;</span> <span class=nx>c</span><span class=p>,</span> <span class=nx>meanCombineFn</span><span class=p>,</span> <span class=s>&#34;mean&#34;</span><span class=p>)</span>
+<span class=p>);</span></code></pre></div></div></div><h5 id=combine-global-windowing>4.2.4.4. Combine and global windowing</h5><p>If your input <code>PCollection</code> uses the default global windowing, the default
 behavior is to return a <code>PCollection</code> containing one item. That item&rsquo;s value
 comes from the accumulator in the combine function that you specified when
 applying <code>Combine</code>. For example, the Beam provided sum combine function returns
@@ -1206,9 +1412,29 @@ PerKey must be an associative reduction function or a
 </span><span class=c1></span>
 <span class=nx>avgAccuracyPerPlayer</span> <span class=o>:=</span> <span class=nx>stats</span><span class=p>.</span><span class=nf>MeanPerKey</span><span class=p>(</span><span class=nx>s</span><span class=p>,</span> <span class=nx>playerAccuracies</span><span class=p>)</span>
 
-<span class=o>//</span> <span class=nx>avgAccuracyPerPlayer</span> <span class=nx>is</span> <span class=nx>a</span> <span class=nx>PCollection</span><span class=p>&lt;</span><span class=kt>string</span><span class=p>,</span><span class=kt>float64</span><span class=p>&gt;</span></code></pre></div></div></div><h4 id=flatten>4.2.5. Flatten</h4><p><span class=language-java><a href=https://beam.apache.org/releases/javadoc/2.40.0/index.html?org/apache/beam/sdk/transforms/Flatten.html><code>Fla [...]
+<span class=o>//</span> <span class=nx>avgAccuracyPerPlayer</span> <span class=nx>is</span> <span class=nx>a</span> <span class=nx>PCollection</span><span class=p>&lt;</span><span class=kt>string</span><span class=p>,</span><span class=kt>float64</span><span class=p>&gt;</span></code></pre></div></div></div><div class="language-typescript snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><i [...]
+  <span class=nx>beam</span><span class=p>.</span><span class=nx>create</span><span class=p>([</span>
+    <span class=p>{</span> <span class=nx>player</span><span class=o>:</span> <span class=s2>&#34;alice&#34;</span><span class=p>,</span> <span class=nx>accuracy</span>: <span class=kt>1.0</span> <span class=p>},</span>
+    <span class=p>{</span> <span class=nx>player</span><span class=o>:</span> <span class=s2>&#34;bob&#34;</span><span class=p>,</span> <span class=nx>accuracy</span>: <span class=kt>0.99</span> <span class=p>},</span>
+    <span class=p>{</span> <span class=nx>player</span><span class=o>:</span> <span class=s2>&#34;eve&#34;</span><span class=p>,</span> <span class=nx>accuracy</span>: <span class=kt>0.5</span> <span class=p>},</span>
+    <span class=p>{</span> <span class=nx>player</span><span class=o>:</span> <span class=s2>&#34;eve&#34;</span><span class=p>,</span> <span class=nx>accuracy</span>: <span class=kt>0.25</span> <span class=p>},</span>
+  <span class=p>])</span>
+<span class=p>);</span>
+<span class=kr>const</span> <span class=nx>result</span> <span class=o>=</span> <span class=nx>pcoll</span><span class=p>.</span><span class=nx>apply</span><span class=p>(</span>
+  <span class=nx>beam</span>
+    <span class=p>.</span><span class=nx>groupBy</span><span class=p>(</span><span class=s2>&#34;player&#34;</span><span class=p>)</span>
+    <span class=p>.</span><span class=nx>combining</span><span class=p>(</span><span class=s2>&#34;accuracy&#34;</span><span class=p>,</span> <span class=nx>combiners</span><span class=p>.</span><span class=nx>mean</span><span class=p>,</span> <span class=s2>&#34;mean&#34;</span><span class=p>)</span>
+    <span class=p>.</span><span class=nx>combining</span><span class=p>(</span><span class=s2>&#34;accuracy&#34;</span><span class=p>,</span> <span class=nx>combiners</span><span class=p>.</span><span class=nx>max</span><span class=p>,</span> <span class=s2>&#34;max&#34;</span><span class=p>)</span>
+<span class=p>);</span>
+<span class=kr>const</span> <span class=nx>expected</span> <span class=o>=</span> <span class=p>[</span>
+  <span class=p>{</span> <span class=nx>player</span><span class=o>:</span> <span class=s2>&#34;alice&#34;</span><span class=p>,</span> <span class=nx>mean</span>: <span class=kt>1.0</span><span class=p>,</span> <span class=nx>max</span>: <span class=kt>1.0</span> <span class=p>},</span>
+  <span class=p>{</span> <span class=nx>player</span><span class=o>:</span> <span class=s2>&#34;bob&#34;</span><span class=p>,</span> <span class=nx>mean</span>: <span class=kt>0.99</span><span class=p>,</span> <span class=nx>max</span>: <span class=kt>0.99</span> <span class=p>},</span>
+  <span class=p>{</span> <span class=nx>player</span><span class=o>:</span> <span class=s2>&#34;eve&#34;</span><span class=p>,</span> <span class=nx>mean</span>: <span class=kt>0.375</span><span class=p>,</span> <span class=nx>max</span>: <span class=kt>0.5</span> <span class=p>},</span>
+<span class=p>];</span>
+</code></pre></div></div></div><h4 id=flatten>4.2.5. Flatten</h4><p><span class=language-java><a href=https://beam.apache.org/releases/javadoc/2.40.0/index.html?org/apache/beam/sdk/transforms/Flatten.html><code>Flatten</code></a></span>
 <span class=language-py><a href=https://github.com/apache/beam/blob/master/sdks/python/apache_beam/transforms/core.py><code>Flatten</code></a></span>
 <span class=language-go><a href=https://github.com/apache/beam/blob/master/sdks/go/pkg/beam/flatten.go><code>Flatten</code></a></span>
+<span class=language-typescript><code>Flatten</code></span>
 is a Beam transform for <code>PCollection</code> objects that store the same data type.
 <code>Flatten</code> merges multiple <code>PCollection</code> objects into a single logical
 <code>PCollection</code>.</p><p>The following example shows how to apply a <code>Flatten</code> transform to merge multiple
@@ -1228,7 +1454,13 @@ is a Beam transform for <code>PCollection</code> objects that store the same dat
     <span class=o>|</span> <span class=n>beam</span><span class=o>.</span><span class=n>Flatten</span><span class=p>())</span></code></pre></div></div></div><div class="language-go snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-go data-lang=go><span class=c1>// Flatten accepts any number of PCo [...]
 </span><span class=c1>// Returns a single PCollection that contains all of the elements in input PCollections.
 </span><span class=c1></span>
-<span class=nx>merged</span> <span class=o>:=</span> <span class=nx>beam</span><span class=p>.</span><span class=nf>Flatten</span><span class=p>(</span><span class=nx>s</span><span class=p>,</span> <span class=nx>pcol1</span><span class=p>,</span> <span class=nx>pcol2</span><span class=p>,</span> <span class=nx>pcol3</span><span class=p>)</span></code></pre></div></div></div><h5 id=data-encoding-merged-collections>4.2.5.1. Data encoding in merged collections</h5><p>By default, the coder  [...]
+<span class=nx>merged</span> <span class=o>:=</span> <span class=nx>beam</span><span class=p>.</span><span class=nf>Flatten</span><span class=p>(</span><span class=nx>s</span><span class=p>,</span> <span class=nx>pcol1</span><span class=p>,</span> <span class=nx>pcol2</span><span class=p>,</span> <span class=nx>pcol3</span><span class=p>)</span></code></pre></div></div></div><div class="language-typescript snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs [...]
+</span><span class=c1>// Returns a single PCollection that contains a union of all of the elements in all input PCollections.
+</span><span class=c1></span>
+<span class=kr>const</span> <span class=nx>fib</span> <span class=o>=</span> <span class=nx>root</span><span class=p>.</span><span class=nx>apply</span><span class=p>(</span><span class=nx>beam</span><span class=p>.</span><span class=nx>create</span><span class=p>([</span><span class=mi>1</span><span class=p>,</span> <span class=mi>1</span><span class=p>,</span> <span class=mi>2</span><span class=p>,</span> <span class=mi>3</span><span class=p>,</span> <span class=mi>5</span><span class= [...]
+<span class=kr>const</span> <span class=nx>pow</span> <span class=o>=</span> <span class=nx>root</span><span class=p>.</span><span class=nx>apply</span><span class=p>(</span><span class=nx>beam</span><span class=p>.</span><span class=nx>create</span><span class=p>([</span><span class=mi>1</span><span class=p>,</span> <span class=mi>2</span><span class=p>,</span> <span class=mi>4</span><span class=p>,</span> <span class=mi>8</span><span class=p>,</span> <span class=mi>16</span><span class [...]
+<span class=kr>const</span> <span class=nx>result</span> <span class=o>=</span> <span class=nx>beam</span><span class=p>.</span><span class=nx>P</span><span class=p>([</span><span class=nx>fib</span><span class=p>,</span> <span class=nx>pow</span><span class=p>]).</span><span class=nx>apply</span><span class=p>(</span><span class=nx>beam</span><span class=p>.</span><span class=nx>flatten</span><span class=p>());</span>
+</code></pre></div></div></div><h5 id=data-encoding-merged-collections>4.2.5.1. Data encoding in merged collections</h5><p>By default, the coder for the output <code>PCollection</code> is the same as the coder for
 the first <code>PCollection</code> in the input <code>PCollectionList</code>. However, the input
 <code>PCollection</code> objects can each use different coders, as long as they all contain
 the same data type in your chosen language.</p><h5 id=merging-windowed-collections>4.2.5.2. Merging windowed collections</h5><p>When using <code>Flatten</code> to merge <code>PCollection</code> objects that have a windowing
@@ -1240,9 +1472,10 @@ incompatible windows, Beam generates an <code>IllegalStateException</code> error
 pipeline is constructed.</p><h4 id=partition>4.2.6. Partition</h4><p><span class=language-java><a href=https://beam.apache.org/releases/javadoc/2.40.0/index.html?org/apache/beam/sdk/transforms/Partition.html><code>Partition</code></a></span>
 <span class=language-py><a href=https://github.com/apache/beam/blob/master/sdks/python/apache_beam/transforms/core.py><code>Partition</code></a></span>
 <span class=language-go><a href=https://github.com/apache/beam/blob/master/sdks/go/pkg/beam/partition.go><code>Partition</code></a></span>
+<span class=language-typescript><code>Partition</code></span>
 is a Beam transform for <code>PCollection</code> objects that store the same data
 type. <code>Partition</code> splits a single <code>PCollection</code> into a fixed number of smaller
-collections.</p><p><code>Partition</code> divides the elements of a <code>PCollection</code> according to a partitioning
+collections.</p><p class=language-typescript>Often in the Typescript SDK the <code>Split</code> transform is more natural to use.</p><p><code>Partition</code> divides the elements of a <code>PCollection</code> according to a partitioning
 function that you provide. The partitioning function contains the logic that
 determines how to split up the elements of the input <code>PCollection</code> into each
 resulting partition <code>PCollection</code>. The number of partitions must be determined
@@ -1288,7 +1521,15 @@ for instance).</p><p>The following example divides a <code>PCollection</code> in
 <span class=c1>// Partition returns a slice of PCollections
 </span><span class=c1></span><span class=nx>studentsByPercentile</span> <span class=o>:=</span> <span class=nx>beam</span><span class=p>.</span><span class=nf>Partition</span><span class=p>(</span><span class=nx>s</span><span class=p>,</span> <span class=mi>10</span><span class=p>,</span> <span class=nx>decileFn</span><span class=p>,</span> <span class=nx>students</span><span class=p>)</span>
 <span class=c1>// Each partition can be extracted by indexing into the slice.
-</span><span class=c1></span><span class=nx>fortiethPercentile</span> <span class=o>:=</span> <span class=nx>studentsByPercentile</span><span class=p>[</span><span class=mi>4</span><span class=p>]</span></code></pre></div></div></div><h3 id=requirements-for-writing-user-code-for-beam-transforms>4.3. Requirements for writing user code for Beam transforms</h3><p>When you build user code for a Beam transform, you should keep in mind the
+</span><span class=c1></span><span class=nx>fortiethPercentile</span> <span class=o>:=</span> <span class=nx>studentsByPercentile</span><span class=p>[</span><span class=mi>4</span><span class=p>]</span></code></pre></div></div></div><div class="language-typescript snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><co [...]
+  <span class=nx>beam</span><span class=p>.</span><span class=nx>partition</span><span class=p>(</span>
+    <span class=p>(</span><span class=nx>student</span><span class=p>,</span> <span class=nx>numPartitions</span><span class=p>)</span> <span class=o>=&gt;</span>
+      <span class=nb>Math</span><span class=p>.</span><span class=nx>floor</span><span class=p>((</span><span class=nx>getPercentile</span><span class=p>(</span><span class=nx>student</span><span class=p>)</span> <span class=o>/</span> <span class=mi>100</span><span class=p>)</span> <span class=o>*</span> <span class=nx>numPartitions</span><span class=p>),</span>
+    <span class=mi>10</span>
+  <span class=p>)</span>
+<span class=p>);</span>
+<span class=kr>const</span> <span class=nx>topDecile</span>: <span class=kt>PCollection</span><span class=o>&lt;</span><span class=nx>Student</span><span class=o>&gt;</span> <span class=o>=</span> <span class=nx>deciles</span><span class=p>[</span><span class=mi>9</span><span class=p>];</span>
+</code></pre></div></div></div><h3 id=requirements-for-writing-user-code-for-beam-transforms>4.3. Requirements for writing user code for Beam transforms</h3><p>When you build user code for a Beam transform, you should keep in mind the
 distributed nature of execution. For example, there might be many copies of your
 function running on a lot of different machines in parallel, and those copies
 function independently, without communicating or sharing state with any of the
@@ -1314,7 +1555,20 @@ however, your subclass must not add any non-serializable members.</span>
 they are registered with <code>register.FunctionXxY</code> (for simple functions) or
 <code>register.DoFnXxY</code> (for sturctural DoFns), and are not closures. Structural
 <code>DoFn</code>s will have all exported fields serialized. Unexported fields are unable to
-be serialized, and will be silently ignored.</span></p><p>Some other serializability factors you should keep in mind are:</p><ul><li><span class="language-java language-py">Transient</span><span class=langauage-go>Unexported</span>
+be serialized, and will be silently ignored.</span>
+<span class=language-typescript>The Typescript SDK use <a href=https://github.com/nokia/ts-serialize-closures>ts-serialize-closures</a>
+to serialize functions (and other objects).
+This works out of the box for functions that are not closures, and also works
+for closures as long as the function in question (and any closures it references)
+are compiled with the
+<a href=https://github.com/apache/beam/blob/master/sdks/typescript/tsconfig.json><code>ts-closure-transform</code> hooks</a>
+(e.g. by using <code>ttsc</code> in place of <code>tsc</code>).
+One can alternatively call
+<code>requireForSerialization("importableModuleDefiningFunc", {func})</code>
+to <a href=https://github.com/apache/beam/blob/master/sdks/typescript/src/apache_beam/serialization.ts>register a function directly</a> by name which can be less error-prone.
+Note that if, as is often the case in Javascript, <code>func</code> returns objects that
+contain closures, it is not sufficient to register <code>func</code> alone&ndash;its return
+value must be registered if used.</span></p><p>Some other serializability factors you should keep in mind are:</p><ul><li><span class="language-java language-py">Transient</span><span class=langauage-go>Unexported</span>
 fields in your function object are <em>not</em> transmitted to worker
 instances, because they are not automatically serialized.</li><li>Avoid loading a field with a large amount of data before serialization.</li><li>Individual instances of your function object cannot share data.</li><li>Mutating a function object after it gets applied will have no effect.</li></ul><span class=language-java><blockquote><p><strong>Note:</strong> Take care when declaring your function object inline by using an anonymous
 inner class instance. In a non-static context, your inner class instance will
@@ -1469,7 +1723,38 @@ function. This optimizes runtime execution of the iterable.</p><h4 id=side-input
 
 <span class=c1>// The Go SDK doesn&#39;t support custom ViewFns.
 </span><span class=c1>// See https://github.com/apache/beam/issues/18602 for details
-</span><span class=c1></span><span class=o>//</span> <span class=nx>on</span> <span class=nx>how</span> <span class=nx>to</span> <span class=nx>contribute</span> <span class=nx>them</span><span class=p>!</span></code></pre></div></div></div><h4 id=side-inputs-windowing>4.4.2. Side inputs and windowing</h4><p>A windowed <code>PCollection</code> may be infinite and thus cannot be compressed into a
+</span><span class=c1></span><span class=o>//</span> <span class=nx>on</span> <span class=nx>how</span> <span class=nx>to</span> <span class=nx>contribute</span> <span class=nx>them</span><span class=p>!</span></code></pre></div></div></div><div class="language-typescript snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chr [...]
+</span><span class=c1>// `map`, `flatMap`, or `parDo` transforms.  This object will get passed as an
+</span><span class=c1>// extra argument to the provided function (or `process` method of the `DoFn`).
+</span><span class=c1>// `SideInputParam` properties (generally created with `pardo.xxxSideInput(...)`)
+</span><span class=c1>// have a `lookup` method that can be invoked from within the process method.
+</span><span class=c1></span>
+<span class=c1>// Let words be a PCollection of strings.
+</span><span class=c1></span><span class=kr>const</span> <span class=nx>words</span> : <span class=kt>PCollection</span><span class=o>&lt;</span><span class=kt>string</span><span class=o>&gt;</span> <span class=o>=</span> <span class=p>...</span>
+
+<span class=c1>// meanLengthPColl will contain a single number whose value is the
+</span><span class=c1>// average length of the words
+</span><span class=c1></span><span class=kr>const</span> <span class=nx>meanLengthPColl</span>: <span class=kt>PCollection</span><span class=o>&lt;</span><span class=kt>number</span><span class=o>&gt;</span> <span class=o>=</span> <span class=nx>words</span>
+  <span class=p>.</span><span class=nx>apply</span><span class=p>(</span>
+    <span class=nx>beam</span>
+      <span class=p>.</span><span class=nx>groupGlobally</span><span class=o>&lt;</span><span class=kt>string</span><span class=o>&gt;</span><span class=p>()</span>
+      <span class=p>.</span><span class=nx>combining</span><span class=p>((</span><span class=nx>word</span><span class=p>)</span> <span class=o>=&gt;</span> <span class=nx>word</span><span class=p>.</span><span class=nx>length</span><span class=p>,</span> <span class=nx>combiners</span><span class=p>.</span><span class=nx>mean</span><span class=p>,</span> <span class=s2>&#34;mean&#34;</span><span class=p>)</span>
+  <span class=p>)</span>
+  <span class=p>.</span><span class=nx>map</span><span class=p>(({</span> <span class=nx>mean</span> <span class=p>})</span> <span class=o>=&gt;</span> <span class=nx>mean</span><span class=p>);</span>
+
+<span class=c1>// Now we use this as a side input to yield only words that are
+</span><span class=c1>// smaller than average.
+</span><span class=c1></span><span class=kr>const</span> <span class=nx>smallWords</span> <span class=o>=</span> <span class=nx>words</span><span class=p>.</span><span class=nx>flatMap</span><span class=p>(</span>
+  <span class=c1>// This is the function, taking context as a second argument.
+</span><span class=c1></span>  <span class=kd>function</span><span class=o>*</span> <span class=nx>keepSmall</span><span class=p>(</span><span class=nx>word</span><span class=p>,</span> <span class=nx>context</span><span class=p>)</span> <span class=p>{</span>
+    <span class=k>if</span> <span class=p>(</span><span class=nx>word</span><span class=p>.</span><span class=nx>length</span> <span class=o>&lt;</span> <span class=nx>context</span><span class=p>.</span><span class=nx>meanLength</span><span class=p>.</span><span class=nx>lookup</span><span class=p>())</span> <span class=p>{</span>
+      <span class=nx>yield</span> <span class=nx>word</span><span class=p>;</span>
+    <span class=p>}</span>
+  <span class=p>},</span>
+  <span class=c1>// This is the context that will be passed as a second argument.
+</span><span class=c1></span>  <span class=p>{</span> <span class=nx>meanLength</span>: <span class=kt>pardo.singletonSideInput</span><span class=p>(</span><span class=nx>meanLengthPColl</span><span class=p>)</span> <span class=p>}</span>
+<span class=p>);</span>
+</code></pre></div></div></div><h4 id=side-inputs-windowing>4.4.2. Side inputs and windowing</h4><p>A windowed <code>PCollection</code> may be infinite and thus cannot be compressed into a
 single value (or single collection class). When you create a <code>PCollectionView</code>
 of a windowed <code>PCollection</code>, the <code>PCollectionView</code> represents a single entity
 per window (one singleton per window, one list per window, etc.).</p><p>Beam uses the window(s) for the main input element to look up the appropriate
@@ -1495,7 +1780,15 @@ number of additional output <code>PCollections</code>s, or even none at all.
 If you choose to have multiple outputs, your <code>DoFn</code> needs to be called with the <code>ParDo</code>
 function that matches the number of outputs. <code>beam.ParDo2</code> for two output <code>PCollection</code>s,
 <code>beam.ParDo3</code> for three and so on until <code>beam.ParDo7</code>. If you need more, you can
-use <code>beam.ParDoN</code> which will return a <code>[]beam.PCollection</code>.</p><h4 id=output-tags>4.5.1. Tags for multiple outputs</h4><p class=language-go>The Go SDK doesn&rsquo;t use output tags, and instead uses positional ordering for
+use <code>beam.ParDoN</code> which will return a <code>[]beam.PCollection</code>.</p><p class=language-typescript>While <code>ParDo</code> always produces a main output <code>PCollection</code> (as the return value
+from <code>apply</code>). If you want to have multiple outputs, emit an object with distinct
+properties in your <code>ParDo</code> operation and follow this operation with a <code>Split</code>
+to break it into multiple <code>PCollection</code>s.</p><h4 id=output-tags>4.5.1. Tags for multiple outputs</h4><p class=language-typescript>The <code>Split</code> PTransform will take a PCollection of elements of the form
+<code>{tagA?: A, tagB?: B, ...}</code> and return a object
+<code>{tagA: PCollection&lt;A>, tagB: PCollection&lt;B>, ...}</code>.
+The set of expected tags is passed to the operation; how multiple or
+unknown tags are handled can be specified by passing a non-default
+<code>SplitOptions</code> instance.</p><p class=language-go>The Go SDK doesn&rsquo;t use output tags, and instead uses positional ordering for
 multiple output PCollections.</p><div class="language-java snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-java data-lang=java><span class=c1>// To emit elements to multiple output PCollections, create a TupleTag object to identify each collection
 </span><span class=c1>// that your ParDo produces. For example, if your ParDo produces three output PCollections (the main output
 </span><span class=c1>// and two additional outputs), you must create three TupleTags. The following example code shows how to
@@ -1573,10 +1866,15 @@ multiple output PCollections.</p><div class="language-java snippet"><div class="
 <span class=c1>// processWordsMixed uses both a standard return and an emitter function.
 </span><span class=c1>// The standard return produces the first PCollection from beam.ParDo2,
 </span><span class=c1>// and the emitter produces the second PCollection.
-</span><span class=c1></span><span class=nx>length</span><span class=p>,</span> <span class=nx>mixedMarked</span> <span class=o>:=</span> <span class=nx>beam</span><span class=p>.</span><span class=nf>ParDo2</span><span class=p>(</span><span class=nx>s</span><span class=p>,</span> <span class=nx>processWordsMixed</span><span class=p>,</span> <span class=nx>words</span><span class=p>)</span></code></pre></div></div></div><h4 id=multiple-outputs-dofn>4.5.2. Emitting to multiple outputs in  [...]
+</span><span class=c1></span><span class=nx>length</span><span class=p>,</span> <span class=nx>mixedMarked</span> <span class=o>:=</span> <span class=nx>beam</span><span class=p>.</span><span class=nf>ParDo2</span><span class=p>(</span><span class=nx>s</span><span class=p>,</span> <span class=nx>processWordsMixed</span><span class=p>,</span> <span class=nx>words</span><span class=p>)</span></code></pre></div></div></div><div class="language-typescript snippet"><div class="notebook-skip c [...]
+
+<span class=kr>const</span> <span class=p>{</span> <span class=nx>below</span><span class=p>,</span> <span class=nx>above</span><span class=p>,</span> <span class=nx>marked</span> <span class=p>}</span> <span class=o>=</span> <span class=nx>to_split</span><span class=p>.</span><span class=nx>apply</span><span class=p>(</span>
+  <span class=nx>beam</span><span class=p>.</span><span class=nx>split</span><span class=p>([</span><span class=s2>&#34;below&#34;</span><span class=p>,</span> <span class=s2>&#34;above&#34;</span><span class=p>,</span> <span class=s2>&#34;marked&#34;</span><span class=p>])</span>
+<span class=p>);</span>
+</code></pre></div></div></div><h4 id=multiple-outputs-dofn>4.5.2. Emitting to multiple outputs in your DoFn</h4><p class=language-go>Call emitter functions as needed to produce 0 or more elements for its matching
 <code>PCollection</code>. The same value can be emitted with multiple emitters.
-As normal, do not mutate values after emitting them from any emitter.</p><p>All emitters should be registered using a generic <code>register.EmitterX[...]</code>
-function. This optimizes runtime execution of the emitter.</p></p><p class=language-go>DoFns can also return a single element via the standard return.
+As normal, do not mutate values after emitting them from any emitter.</p><p class=language-go>All emitters should be registered using a generic <code>register.EmitterX[...]</code>
+function. This optimizes runtime execution of the emitter.</p><p class=language-go>DoFns can also return a single element via the standard return.
 The standard return is always the first PCollection returned from beam.ParDo.
 Other emitters output to their own PCollections in their defined parameter order.</p><div class="language-java snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-java data-lang=java><span class=c1>// Inside your ParDo&#39;s DoFn, you can emit an element to a specific output PCollection by providing a
 </span><span class=c1>// MultiOutputReceiver to your process method, and passing in the appropriate TupleTag to obtain an OutputReceiver.
@@ -1658,15 +1956,27 @@ Other emitters output to their own PCollections in their defined parameter order
 	<span class=nx>register</span><span class=p>.</span><span class=nf>Function2x1</span><span class=p>(</span><span class=nx>processWordsMixed</span><span class=p>)</span>
 	<span class=c1>// 1 input of type string =&gt; Emitter1[string]
 </span><span class=c1></span>	<span class=nx>register</span><span class=p>.</span><span class=nx>Emitter1</span><span class=p>[</span><span class=kt>string</span><span class=p>]()</span>
-<span class=p>}</span></code></pre></div></div></div><h4 id=other-dofn-parameters>4.5.3. Accessing additional parameters in your DoFn</h4><p class=language-java>In addition to the element and the <code>OutputReceiver</code>, Beam will populate other parameters to your DoFn&rsquo;s <code>@ProcessElement</code> method.
+<span class=p>}</span></code></pre></div></div></div><div class="language-typescript snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-typescript data-lang=typescript><span class=kr>const</span> <span class=nx>to_split</span> <span class=o>=</span> <span class=nx>words</span><span class=p>.</span> [...]
+  <span class=k>if</span> <span class=p>(</span><span class=nx>word</span><span class=p>.</span><span class=nx>length</span> <span class=o>&lt;</span> <span class=mi>5</span><span class=p>)</span> <span class=p>{</span>
+    <span class=nx>yield</span> <span class=p>{</span> <span class=nx>below</span>: <span class=kt>word</span> <span class=p>};</span>
+  <span class=p>}</span> <span class=k>else</span> <span class=p>{</span>
+    <span class=nx>yield</span> <span class=p>{</span> <span class=nx>above</span>: <span class=kt>word</span> <span class=p>};</span>
+  <span class=p>}</span>
+  <span class=k>if</span> <span class=p>(</span><span class=nx>isMarkedWord</span><span class=p>(</span><span class=nx>word</span><span class=p>))</span> <span class=p>{</span>
+    <span class=nx>yield</span> <span class=p>{</span> <span class=nx>marked</span>: <span class=kt>word</span> <span class=p>};</span>
+  <span class=p>}</span>
+<span class=p>});</span>
+</code></pre></div></div></div><h4 id=other-dofn-parameters>4.5.3. Accessing additional parameters in your DoFn</h4><p class=language-java>In addition to the element and the <code>OutputReceiver</code>, Beam will populate other parameters to your DoFn&rsquo;s <code>@ProcessElement</code> method.
 Any combination of these parameters can be added to your process method in any order.</p><p class=language-py>In addition to the element, Beam will populate other parameters to your DoFn&rsquo;s <code>process</code> method.
-Any combination of these parameters can be added to your process method in any order.</p><p class=language-go>In addition to the element, Beam will populate other parameters to your DoFn&rsquo;s <code>ProcessElement</code> method.
+Any combination of these parameters can be added to your process method in any order.</p><p class=language-typescript>In addition to the element, Beam will populate other parameters to your DoFn&rsquo;s <code>process</code> method.
+These are available by placing accessors in the context argument, just as for side inputs.</p><p class=language-go>In addition to the element, Beam will populate other parameters to your DoFn&rsquo;s <code>ProcessElement</code> method.
 Any combination of these parameters can be added to your process method in a standard order.</p><p class=language-go><strong>context.Context:</strong>
 To support consolidated logging and user defined metrics, a <code>context.Context</code> parameter can be requested.
 Per Go conventions, if present it&rsquo;s required to be the first parameter of the <code>DoFn</code> method.</p><div class="language-go snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-go data-lang=go><span class=kd>func</span> <span class=nf>MyDoFn</span><span class=p>(</span><span class=nx>ctx [...]
 To access the timestamp of an input element, add a parameter annotated with <code>@Timestamp</code> of type <code>Instant</code>. For example:</p><p class=language-py><strong>Timestamp:</strong>
 To access the timestamp of an input element, add a keyword parameter default to <code>DoFn.TimestampParam</code>. For example:</p><p class=language-go><strong>Timestamp:</strong>
-To access the timestamp of an input element, add a <code>beam.EventTime</code> parameter before the element. For example:</p><div class="language-java snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-java data-lang=java><span class=o>.</span><span class=na>of</span><span class=o>(</span><span cla [...]
+To access the timestamp of an input element, add a <code>beam.EventTime</code> parameter before the element. For example:</p><p class=language-typescript><strong>Timestamp:</strong>
+To access the window an input element falls into, add a <code>pardo.windowParam()</code> to the context argument.</p><div class="language-java snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-java data-lang=java><span class=o>.</span><span class=na>of</span><span class=o>(</span><span class=k>new [...]
      <span class=kd>public</span> <span class=kt>void</span> <span class=nf>processElement</span><span class=o>(</span><span class=nd>@Element</span> <span class=n>String</span> <span class=n>word</span><span class=o>,</span> <span class=nd>@Timestamp</span> <span class=n>Instant</span> <span class=n>timestamp</span><span class=o>)</span> <span class=o>{</span>
   <span class=o>}})</span></code></pre></div></div></div><div class="language-py snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-py data-lang=py><span class=kn>import</span> <span class=nn>apache_beam</span> <span class=kn>as</span> <span class=nn>beam</span>
 
@@ -1674,7 +1984,12 @@ To access the timestamp of an input element, add a <code>beam.EventTime</code> p
 
   <span class=k>def</span> <span class=nf>process</span><span class=p>(</span><span class=bp>self</span><span class=p>,</span> <span class=n>element</span><span class=p>,</span> <span class=n>timestamp</span><span class=o>=</span><span class=n>beam</span><span class=o>.</span><span class=n>DoFn</span><span class=o>.</span><span class=n>TimestampParam</span><span class=p>):</span>
      <span class=c1># access timestamp of element.</span>
-     <span class=k>pass</span></code></pre></div></div></div><div class="language-go snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-go data-lang=go><span class=kd>func</span> <span class=nf>MyDoFn</span><span class=p>(</span><span class=nx>ts</span> <span class=nx>beam</span><span class=p>.</sp [...]
+     <span class=k>pass</span></code></pre></div></div></div><div class="language-go snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-go data-lang=go><span class=kd>func</span> <span class=nf>MyDoFn</span><span class=p>(</span><span class=nx>ts</span> <span class=nx>beam</span><span class=p>.</sp [...]
+  <span class=k>return</span> <span class=nx>context</span><span class=p>.</span><span class=nx>timestamp</span><span class=p>.</span><span class=nx>lookup</span><span class=p>();</span>
+<span class=p>}</span>
+
+<span class=nx>pcoll</span><span class=p>.</span><span class=nx>map</span><span class=p>(</span><span class=nx>processFn</span><span class=p>,</span> <span class=p>{</span> <span class=nx>timestamp</span>: <span class=kt>pardo.timestampParam</span><span class=p>()</span> <span class=p>});</span>
+</code></pre></div></div></div><p class=language-java><strong>Window:</strong>
 To access the window an input element falls into, add a parameter of the type of the window used for the input <code>PCollection</code>.
 If the parameter is a window type (a subclass of <code>BoundedWindow</code>) that does not match the input <code>PCollection</code>, then an error
 will be raised. If an element falls in multiple windows (for example, this will happen when using <code>SlidingWindows</code>), then the
@@ -1687,7 +2002,10 @@ To access the window an input element falls into, add a <code>beam.Window</code>
 If an element falls in multiple windows (for example, this will happen when using SlidingWindows),
 then the <code>ProcessElement</code> method will be invoked multiple time for the element, once for each window.
 Since <code>beam.Window</code> is an interface it&rsquo;s possible to type assert to the concrete implementation of the window.
-For example, when fixed windows are being used, the window is of type <code>window.IntervalWindow</code>.</p><div class="language-java snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-java data-lang=java><span class=o>.</span><span class=na>of</span><span class=o>(</span><span class=k>new</span>  [...]
+For example, when fixed windows are being used, the window is of type <code>window.IntervalWindow</code>.</p><p class=language-typescript><strong>Window:</strong>
+To access the window an input element falls into, add a <code>pardo.windowParam()</code> to the context argument.
+If an element falls in multiple windows (for example, this will happen when using <code>SlidingWindows</code>), then the
+function will be invoked multiple time for the element, once for each window.</p><div class="language-java snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-java data-lang=java><span class=o>.</span><span class=na>of</span><span class=o>(</span><span class=k>new</span> <span class=n>DoFn</span><sp [...]
      <span class=kd>public</span> <span class=kt>void</span> <span class=nf>processElement</span><span class=o>(</span><span class=nd>@Element</span> <span class=n>String</span> <span class=n>word</span><span class=o>,</span> <span class=n>IntervalWindow</span> <span class=n>window</span><span class=o>)</span> <span class=o>{</span>
   <span class=o>}})</span></code></pre></div></div></div><div class="language-py snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-py data-lang=py><span class=kn>import</span> <span class=nn>apache_beam</span> <span class=kn>as</span> <span class=nn>beam</span>
 
@@ -1698,14 +2016,18 @@ For example, when fixed windows are being used, the window is of type <code>wind
      <span class=k>pass</span></code></pre></div></div></div><div class="language-go snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-go data-lang=go><span class=kd>func</span> <span class=nf>MyDoFn</span><span class=p>(</span><span class=nx>w</span> <span class=nx>beam</span><span class=p>.</spa [...]
   <span class=nx>iw</span> <span class=o>:=</span> <span class=nx>w</span><span class=p>.(</span><span class=nx>window</span><span class=p>.</span><span class=nx>IntervalWindow</span><span class=p>)</span>
   <span class=o>...</span>
-<span class=p>}</span></code></pre></div></div></div><p class=language-java><strong>PaneInfo:</strong>
+<span class=p>}</span></code></pre></div></div></div><div class="language-typescript snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-typescript data-lang=typescript><span class=nx>pcoll</span><span class=p>.</span><span class=nx>map</span><span class=p>(</span><span class=nx>processFn</span><spa [...]
+</code></pre></div></div></div><p class=language-java><strong>PaneInfo:</strong>
 When triggers are used, Beam provides a <code>PaneInfo</code> object that contains information about the current firing. Using <code>PaneInfo</code>
 you can determine whether this is an early or a late firing, and how many times this window has already fired for this key.</p><p class=language-py><strong>PaneInfo:</strong>
 When triggers are used, Beam provides a <code>DoFn.PaneInfoParam</code> object that contains information about the current firing. Using <code>DoFn.PaneInfoParam</code>
 you can determine whether this is an early or a late firing, and how many times this window has already fired for this key.
 This feature implementation in Python SDK is not fully completed; see more at <a href=https://github.com/apache/beam/issues/18721>Issue 17821</a>.</p><p class=language-go><strong>PaneInfo:</strong>
 When triggers are used, Beam provides <code>beam.PaneInfo</code> object that contains information about the current firing. Using <code>beam.PaneInfo</code>
-you can determine whether this is an early or a late firing, and how many times this window has already fired for this key.</p><div class="language-java snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-java data-lang=java><span class=o>.</span><span class=na>of</span><span class=o>(</span><span c [...]
+you can determine whether this is an early or a late firing, and how many times this window has already fired for this key.</p><p class=language-typescript><strong>Window:</strong>
+To access the window an input element falls into, add a <code>pardo.paneInfoParam()</code> to the context argument.
+Using <code>beam.PaneInfo</code> you can determine whether this is an early or a late firing,
+and how many times this window has already fired for this key.</p><div class="language-java snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-java data-lang=java><span class=o>.</span><span class=na>of</span><span class=o>(</span><span class=k>new</span> <span class=n>DoFn</span><span class=o>&lt; [...]
      <span class=kd>public</span> <span class=kt>void</span> <span class=nf>processElement</span><span class=o>(</span><span class=nd>@Element</span> <span class=n>String</span> <span class=n>word</span><span class=o>,</span> <span class=n>PaneInfo</span> <span class=n>paneInfo</span><span class=o>)</span> <span class=o>{</span>
   <span class=o>}})</span></code></pre></div></div></div><div class="language-py snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-py data-lang=py><span class=kn>import</span> <span class=nn>apache_beam</span> <span class=kn>as</span> <span class=nn>beam</span>
 
@@ -1731,7 +2053,8 @@ you can determine whether this is an early or a late firing, and how many times
 	<span class=k>for</span> <span class=nx>_</span><span class=p>,</span> <span class=nx>w</span> <span class=o>:=</span> <span class=k>range</span> <span class=nx>words</span> <span class=p>{</span>
 		<span class=nf>emitWords</span><span class=p>(</span><span class=nx>w</span><span class=p>)</span>
 	<span class=p>}</span>
-<span class=p>}</span></code></pre></div></div></div><p class=language-java><strong>PipelineOptions:</strong>
+<span class=p>}</span></code></pre></div></div></div><div class="language-typescript snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-typescript data-lang=typescript><span class=nx>pcoll</span><span class=p>.</span><span class=nx>map</span><span class=p>(</span><span class=nx>processFn</span><spa [...]
+</code></pre></div></div></div><p class=language-java><strong>PipelineOptions:</strong>
 The <code>PipelineOptions</code> for the current pipeline can always be accessed in a process method by adding it
 as a parameter:</p><div class="language-java snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-java data-lang=java><span class=o>.</span><span class=na>of</span><span class=o>(</span><span class=k>new</span> <span class=n>DoFn</span><span class=o>&lt;</span><span class=n>String</span><span class=o [...]
      <span class=kd>public</span> <span class=kt>void</span> <span class=nf>processElement</span><span class=o>(</span><span class=nd>@Element</span> <span class=n>String</span> <span class=n>word</span><span class=o>,</span> <span class=n>PipelineOptions</span> <span class=n>options</span><span class=o>)</span> <span class=o>{</span>
@@ -1743,7 +2066,9 @@ Timers are explained in more detail in the
 In addition to aforementioned parameters, user defined Timer and State parameters can be used in a stateful DoFn.
 Timers and States are explained in more detail in the
 <a href=/blog/2017/08/28/timely-processing.html>Timely (and Stateful) Processing with Apache Beam</a> blog post.</p><p class=language-go><strong>Timer and State:</strong>
-This feature isn&rsquo;t implemented in the Go SDK; see more at <a href=https://github.com/apache/beam/issues/20510>Issue 20510</a>. Once implemented, user defined Timer and State parameters can be used in a stateful DoFn.</p><div class="language-py snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=languag [...]
+This feature isn&rsquo;t implemented in the Go SDK; see more at <a href=https://github.com/apache/beam/issues/20510>Issue 20510</a>. Once implemented, user defined Timer and State parameters can be used in a stateful DoFn.</p><p class=language-typescript><strong>Timer and State:</strong>
+This feature isn&rsquo;t implemented in the Typescript SDK yet,
+but can be used from a cross-language transform.</p><div class="language-py snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-py data-lang=py><span class=k>class</span> <span class=nc>StatefulDoFn</span><span class=p>(</span><span class=n>beam</span><span class=o>.</span><span class=n>DoFn</span>< [...]
   <span class=s2>&#34;&#34;&#34;An example stateful DoFn with state and timer&#34;&#34;&#34;</span>
 
   <span class=n>BUFFER_STATE_1</span> <span class=o>=</span> <span class=n>BagStateSpec</span><span class=p>(</span><span class=s1>&#39;buffer1&#39;</span><span class=p>,</span> <span class=n>beam</span><span class=o>.</span><span class=n>BytesCoder</span><span class=p>())</span>
@@ -1856,8 +2181,19 @@ appeared in the original data.</li></ol><div class="language-java snippet"><div
 	<span class=c1>// Return any PCollections that should be available after
 </span><span class=c1></span>	<span class=c1>// the composite transform.
 </span><span class=c1></span>	<span class=k>return</span> <span class=nx>wordCounts</span>
-<span class=p>}</span></code></pre></div></div></div><blockquote><p><strong>Note:</strong> Because <code>Count</code> is itself a composite transform,
-<code>CountWords</code> is also a nested composite transform.</p></blockquote><h4 id=composite-transform-creation>4.6.2. Creating a composite transform</h4><p class="language-java language-py">To create your own composite transform, create a subclass of the <code>PTransform</code>
+<span class=p>}</span></code></pre></div></div></div><div class="language-typescript snippet"><div class="notebook-skip code-snippet"><a class=copy type=button data-bs-toggle=tooltip data-bs-placement=bottom title="Copy to clipboard"><img src=/images/copy-icon.svg></a><div class=highlight><pre class=chroma><code class=language-typescript data-lang=typescript><span class=kd>function</span> <span class=nx>countWords</span><span class=p>(</span><span class=nx>lines</span>: <span class=kt>PC [...]
+  <span class=k>return</span> <span class=nx>lines</span> <span class=c1>//
+</span><span class=c1></span>    <span class=p>.</span><span class=nx>map</span><span class=p>((</span><span class=nx>s</span>: <span class=kt>string</span><span class=p>)</span> <span class=o>=&gt;</span> <span class=nx>s</span><span class=p>.</span><span class=nx>toLowerCase</span><span class=p>())</span>
+    <span class=p>.</span><span class=nx>flatMap</span><span class=p>(</span><span class=kd>function</span><span class=o>*</span> <span class=nx>splitWords</span><span class=p>(</span><span class=nx>line</span>: <span class=kt>string</span><span class=p>)</span> <span class=p>{</span>
+      <span class=nx>yield</span><span class=o>*</span> <span class=nx>line</span><span class=p>.</span><span class=nx>split</span><span class=p>(</span><span class=sr>/[^a-z]+/</span><span class=p>);</span>
+    <span class=p>})</span>
+    <span class=p>.</span><span class=nx>apply</span><span class=p>(</span><span class=nx>beam</span><span class=p>.</span><span class=nx>countPerElement</span><span class=p>());</span>
+<span class=p>}</span>
+
+<span class=kr>const</span> <span class=nx>counted</span> <span class=o>=</span> <span class=nx>lines</span><span class=p>.</span><span class=nx>apply</span><span class=p>(</span><span class=nx>countWords</span><span class=p>);</span>
+</code></pre></div></div></div><blockquote><p><strong>Note:</strong> Because <code>Count</code> is itself a composite transform,
+<code>CountWords</code> is also a nested composite transform.</p></blockquote><h4 id=composite-transform-creation>4.6.2. Creating a composite transform</h4><p class=language-typescript>A PTransform in the Typescript SDK is simply a function that accepts and
+returns <code>PValue</code>s such as <code>PCollection</code>s.</p><p class="language-java language-py">To create your own composite transform, create a subclass of the <code>PTransform</code>
 class and override the <code>expand</code> method to specify the actual processing logic.
 You can then use this transform just as you would a built-in transform from the
 Beam SDK.</p><p class=language-java>For the <code>PTransform</code> class type parameters, you pass the <code>PCollection</code> types
@@ -4488,7 +4824,7 @@ functions as shortcuts for single, unnamed inputs/outputs or define a map for na
 <span class=nx>outT</span> <span class=o>:=</span> <span class=nx>beam</span><span class=p>.</span><span class=nf>UnnamedOutput</span><span class=p>(</span><span class=nx>typex</span><span class=p>.</span><span class=nf>New</span><span class=p>(</span><span class=nx>reflectx</span><span class=p>.</span><span class=nx>String</span><span class=p>))</span>
 <span class=nx>res</span> <span class=o>:=</span> <span class=nx>beam</span><span class=p>.</span><span class=nf>CrossLanguage</span><span class=p>(</span><span class=nx>s</span><span class=p>,</span> <span class=nx>urn</span><span class=p>,</span> <span class=nx>payload</span><span class=p>,</span> <span class=nx>expansionAddr</span><span class=p>,</span> <span class=nx>beam</span><span class=p>.</span><span class=nf>UnnamedInput</span><span class=p>(</span><span class=nx>inputPCol</spa [...]
 </code></pre></div></li><li><p>After the job has been submitted to the Beam runner, shutdown the expansion service by
-terminating the expansion service process.</p></li></ol><h3 id=x-lang-transform-runner-support>13.3. Runner Support</h3><p>Currently, portable runners such as Flink, Spark, and the direct runner can be used with multi-language pipelines.</p><p>Dataflow supports multi-language pipelines through the Dataflow Runner v2 backend architecture.</p><h3 id=x-lang-transform-tips-troubleshooting>13.4 Tips and Troubleshooting</h3><p>For additional tips and troubleshooting information, see <a href=ht [...]
+terminating the expansion service process.</p></li></ol><h3 id=x-lang-transform-runner-support>13.3. Runner Support</h3><p>Currently, portable runners such as Flink, Spark, and the direct runner can be used with multi-language pipelines.</p><p>Dataflow supports multi-language pipelines through the Dataflow Runner v2 backend architecture.</p><h3 id=x-lang-transform-tips-troubleshooting>13.4 Tips and Troubleshooting</h3><p>For additional tips and troubleshooting information, see <a href=ht [...]
 <a href=http://www.apache.org>The Apache Software Foundation</a>
 | <a href=/privacy_policy>Privacy Policy</a>
 | <a href=/feed.xml>RSS Feed</a><br><br>Apache Beam, Apache, Beam, the Beam logo, and the Apache feather logo are either registered trademarks or trademarks of The Apache Software Foundation. All other products or name brands are trademarks of their respective holders, including The Apache Software Foundation.</div></div><div class="footer__cols__col footer__cols__col__logos"><div class=footer__cols__col--group><div class=footer__cols__col__logo><a href=https://github.com/apache/beam><im [...]
\ No newline at end of file
diff --git a/website/generated-content/sitemap.xml b/website/generated-content/sitemap.xml
index a63abbc22dd..08f13c12777 100644
--- a/website/generated-content/sitemap.xml
+++ b/website/generated-content/sitemap.xml
@@ -1 +1 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?><urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml"><url><loc>/blog/go-2.40/</loc><lastmod>2022-07-06T14:03:32-04:00</lastmod></url><url><loc>/categories/blog/</loc><lastmod>2022-07-06T14:03:32-04:00</lastmod></url><url><loc>/blog/</loc><lastmod>2022-07-06T14:03:32-04:00</lastmod></url><url><loc>/categories/</loc><lastmod>2022-07-06T14:03:32-04:00</lastmod></url><url><loc>/categories [...]
\ No newline at end of file
+<?xml version="1.0" encoding="utf-8" standalone="yes"?><urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml"><url><loc>/blog/go-2.40/</loc><lastmod>2022-07-06T14:03:32-04:00</lastmod></url><url><loc>/categories/blog/</loc><lastmod>2022-07-06T14:03:32-04:00</lastmod></url><url><loc>/blog/</loc><lastmod>2022-07-06T14:03:32-04:00</lastmod></url><url><loc>/categories/</loc><lastmod>2022-07-06T14:03:32-04:00</lastmod></url><url><loc>/categories [...]
\ No newline at end of file