{"id":13393279,"url":"https://github.com/tc39/proposal-pattern-matching","last_synced_at":"2025-05-14T08:06:08.085Z","repository":{"id":37740659,"uuid":"96151448","full_name":"tc39/proposal-pattern-matching","owner":"tc39","description":"Pattern matching syntax for ECMAScript","archived":false,"fork":false,"pushed_at":"2024-09-27T08:08:16.000Z","size":2019,"stargazers_count":5616,"open_issues_count":24,"forks_count":89,"subscribers_count":300,"default_branch":"main","last_synced_at":"2025-04-13T12:41:20.970Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://tc39.es/proposal-pattern-matching/","language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tc39.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-07-03T21:21:23.000Z","updated_at":"2025-04-13T10:35:06.000Z","dependencies_parsed_at":"2022-07-10T18:00:41.686Z","dependency_job_id":"fcc5759b-f05c-420f-92c8-b336c86decc0","html_url":"https://github.com/tc39/proposal-pattern-matching","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tc39%2Fproposal-pattern-matching","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tc39%2Fproposal-pattern-matching/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tc39%2Fproposal-pattern-matching/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tc39%2Fproposal-pattern-matching/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tc39","download_url":"https://codeload.github.com/tc39/proposal-pattern-matching/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254101615,"owners_count":22014909,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-30T17:00:48.547Z","updated_at":"2025-05-14T08:06:03.072Z","avatar_url":"https://github.com/tc39.png","language":"HTML","funding_links":[],"categories":["HTML","Others"],"sub_categories":[],"readme":"# ECMAScript Pattern Matching\n\n## [Status](https://tc39.github.io/process-document/)\n\n**Stage**: 1\n\n**Spec Text**: \u003chttps://tc39.github.io/proposal-pattern-matching\u003e\n\n**Authors**: Originally Kat Marchán (Microsoft,\n[@zkat\\_\\_](https://twitter.com/zkat__)); now, the below champions.\n\n**Champions**: (in alphabetical order)\n\n- Daniel Rosenwasser (Microsoft,\n  [@drosenwasser](https://twitter.com/drosenwasser))\n- Jack Works (Sujitech, [@Jack-Works](https://github.com/Jack-Works))\n- Jordan Harband (HeroDevs, [@ljharb](https://twitter.com/ljharb))\n- Mark Cohen ([@mpcsh\\_](https://twitter.com/mpcsh_))\n- Ross Kirsling (Sony, [@rkirsling](https://twitter.com/rkirsling))\n- Tab Atkins-Bittner (Google, [@tabatkins](https://twitter.com/tabatkins))\n\n# Introduction\n\n## Problem\n\nThere are many ways to match *values* in the language,\nbut there are no ways to match *patterns*\nbeyond regular expressions for strings.\nHowever, wanting to take different actions\nbased on patterns in a given value\nis a very common desire:\ndo X if the value has a `foo` property,\ndo Y if it contains three or more items,\netc.\n\n### Current Approaches\n\n`switch` has the desired *structure* --\na value is given,\nand several possible match criteria are offered,\neach with a different associated action.\nBut it's severely lacking in practice:\nit may not appear in expression position;\nan explicit `break` is required in each `case` to avoid accidental fallthrough;\nscoping is ambiguous\n(block-scoped variables inside one `case` are available in the scope of the others,\nunless curly braces are used);\nthe only comparison it can do is `===`; etc.\n\n`if/else` has the necessary *power*\n(you can perform any comparison you like),\nbut it's overly verbose even for common cases,\nrequiring the author to explicitly list paths into the value's structure multiple times,\nonce per test performed.\nIt's also statement-only\n(unless the author opts for the harder-to-understand ternary syntax)\nand requires the value under test to be stored in a (possibly temporary) variable.\n\n## Priorities for a solution\n\nThis section details this proposal’s priorities. Note that not every champion\nmay agree with each priority.\n\n### _Pattern_ matching\n\nThe pattern matching construct is a full conditional logic construct that can do\nmore than just pattern matching. As such, there have been (and there will be\nmore) trade-offs that need to be made. In those cases, we should prioritize the\nergonomics of structural pattern matching over other capabilities of this\nconstruct.\n\n### Subsumption of `switch`\n\nThis feature must be easily searchable, so that tutorials and documentation are\neasy to locate, and so that the feature is easy to learn and recognize. As such,\nthere must be no syntactic overlap with the `switch` statement.\n\nThis proposal seeks to preserve the good parts of `switch`, and eliminate any\nreasons to reach for it.\n\n### Be better than `switch`\n\n`switch` contains a plethora of footguns such as accidental case fallthrough and\nambiguous scoping. This proposal should eliminate those footguns, while also\nintroducing new capabilities that `switch` currently can not provide.\n\n### Expression semantics\n\nThe pattern matching construct should be usable as an expression:\n\n- `return match { ... }`\n- `let foo = match { ... }`\n- `() =\u003e match { ... }`\n- etc.\n\nThe value of the whole expression is the value of whatever [clause](#clause) is\nmatched.\n\n### Exhaustiveness and ordering\n\nIf the developer wants to ignore certain possible cases, they should specify\nthat explicitly. A development-time error is less costly than a production-time\nerror from something further down the stack.\n\nIf the developer wants two cases to share logic (what we know as \"fall-through\"\nfrom `switch`), they should specify it explicitly. Implicit fall-through\ninevitably silently accepts buggy code.\n\n[Clauses](#clause) should always be checked in the order they’re written, i.e.\nfrom top to bottom.\n\n### User extensibility\n\nUserland objects should be able to encapsulate their own matching semantics,\nwithout unnecessarily privileging builtins. This includes regular expressions\n(as opposed to the literal pattern syntax), numeric ranges, etc.\n\n## Prior Art\n\nThis proposal adds a pattern matching expression to the language, based in part\non the existing\n[Destructuring Binding Patterns](https://tc39.github.io/ecma262/#sec-destructuring-binding-patterns).\n\nThis proposal was approved for Stage 1 in the May 2018 TC39 meeting, and slides\nfor that presentation are available\n[here](https://docs.google.com/presentation/d/1WPyAO4pHRsfwGoiIZupz_-tzAdv8mirw-aZfbxbAVcQ).\nIts current form was presented to TC39 in the April 2021 meeting\n([slides](https://hackmd.io/@mpcsh/HkZ712ig_#/)).\n\nThis proposal draws from, and partially overlaps with, corresponding features in\n[CoffeeScript](https://coffeescript.org/#switch),\n[Rust](https://doc.rust-lang.org/1.6.0/book/patterns.html),\n[Python](https://www.python.org/dev/peps/pep-0622/),\n[F#](https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/pattern-matching),\n[Scala](http://www.scala-lang.org/files/archive/spec/2.11/08-pattern-matching.html),\n[Elixir/Erlang](https://elixir-lang.org/getting-started/pattern-matching.html),\nand [C++](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1371r2.pdf).\n\n### Userland matching\n\nA list of community libraries that provide similar matching functionality:\n\n- [Optionals](https://github.com/OliverBrotchie/optionals) — Rust-like error handling, options and exhaustive pattern matching for TypeScript and Deno\n- [ts-pattern](https://github.com/gvergnaud/ts-pattern) — Exhaustive Pattern Matching library for TypeScript, with smart type inference.\n- [babel-plugin-proposal-pattern-matching](https://github.com/iptop/babel-plugin-proposal-pattern-matching) — Minimal grammar, high performance JavaScript pattern matching implementation.\n- [match-iz](https://github.com/shuckster/match-iz) — A tiny functional pattern-matching library inspired by the TC39 proposal.\n- [patcom](https://github.com/concept-not-found/patcom) — Feature parity with TC39 proposal without any new syntax\n\n# Specification\n\nThis proposal introduces three new concepts to Javascript:\n\n* the \"matcher pattern\",\n    a new DSL closely related to destructuring patterns,\n    which allows recursively testing the structure and contents of a value\n    in multiple ways at once,\n    and extracting some of that structure into local bindings at the same time\n* the `match(){}` expression,\n    a general replacement for the `switch` statement\n    that uses matcher patterns\n    to resolve to one of several values,\n* the `is` boolean operator,\n    which allows for one-off testing of a value against a matcher pattern,\n    potentially also introducing bindings from that test into the local environment.\n\n\n# Matcher Patterns\n\nMatcher patterns are a new DSL,\nclosely inspired by destructuring patterns,\nfor recursively testing the structure and contents of a value\nwhile simultaneously extracting some parts of that value\nas local bindings for use by other code.\n\nMatcher patterns can be divided into three general varieties:\n* Value patterns, which test that the subject matches some criteria, like \"is the string `\"foo\"`\" or \"matches the variable `bar`\".\n* Structure patterns, which test the subject matches some structural criteria like \"has the property `foo`\" or \"is at least length 3\", and also let you recursively apply additional matchers to parts of that structure.\n* Combinator patterns, which let you match several patterns in parallel on the same subject, with simple boolean `and`/`or` logic.\n\n## Value Matchers\n\nThere are several types of value patterns, performing different types of tests.\n\n### Primitive Patterns\n\nAll primitive values can be used directly as matcher patterns,\nrepresenting a test that the subject matches the specified value,\nusing [`SameValue`](https://tc39.es/ecma262/#sec-samevalue) semantics\n(except when otherwise noted).\n\nFor example, `1` tests that the subject is `SameValue` to `1`,\n`\"foo\"` tests that it's `SameValue` to `\"foo\"`,\netc.\n\nSpecifically,\nboolean literals,\nnumeric literals,\nstring literals,\nuntagged template literals,\nand the null literal\ncan all be used.\n\n* Numeric literals can additionally be prefixed with a `+` or `-` unary operator:\n    `+` is a no-op (but see the note about `0`, below),\n    but `-` negates the value,\n    as you'd expect.\n* Within the interpolation expressions of template literals,\n    see [Bindings](#bindings) for details on what bindings are visible.\n\nThe one exception to `SameValue` matching semantics\nis that the pattern `0` is matched using `SameValueZero` semantics.\n`+0` and `-0` are matched with `SameValue`, as normal.\n(This has the effect that an \"unsigned\" zero pattern\nwill match both positive and negative zero values,\nwhile the \"signed\" zero patterns\nwill only match the appropriately signed zero values.)\n\n(Additional notes for `SameValue` semantics:\nit works \"as expected\" for NaN values,\ncorrectly matching NaN values against NaN patterns;\nit does not do any implicit type coercion,\nso a `1` value will not match a `\"1\"` pattern.)\n\nNote: No coercion takes place in these matches:\nif you match against a string literal, for example,\nyour subject must already be a string\nor else it'll automatically fail the match,\neven if it would stringify to a matching string.\n\n#### Examples\n\n```js\n```\n\n\n### Variable Patterns\n\nA variable pattern is a \"ident expression\": `foo`, `foo.bar`, `foo[bar]` etc.,\nexcluding those that are already primitives like `null`,\nand optionally prefixed by a `+` or `-` unary operator.\n\nA variable pattern resolves the identifier against the visible bindings\n(see [Bindings](#bindings) for details),\nand if it has a `+` or `-` prefix,\nconverts it to a number (via `toValue`)\nand possibly negates it.\nIf the result is an object with a `Symbol.customMatcher` property,\nor is a function,\nthen it represents a custom matcher test.\nSee [custom matchers](#custom-matchers) for details.\nOtherwise, it represents a test that the subject is `SameValue` with the result,\nsimilar to a [Primitive Pattern](#primitive-patterns).\n\nNote: This implies that, for example,\na variable holding an array will only match that exact array,\nvia object equivalence;\nit is not equivalent to an [array pattern](#array-patterns)\ndoing a structural match.\n\nNote that several values which are often *thought of* as literals,\nlike `Infinity` or `undefined`,\nare in fact bindings.\nSince Primitive Patterns and Variable Patterns are treated largely identically,\nthe distinction can fortunately remain academic here.\n\nNote: Just like with Primitive Patterns,\nno coercion is performed on the subjects\n(or on the pattern value,\nexcept for the effect of `+`/`-`,\nwhich is explicitly asking for a numeric coercion),\nso the type has to already match.\n\n\n#### Examples\n\n```js\n```\n\n\n### Custom Matchers\n\nIf the object that the variable pattern resolves to\nhas a `Symbol.customMatcher` property in its prototype chain,\nthen it is a \"custom matcher\".\n\nTo determine whether the pattern matches or not,\nthe custom matcher function is invoked\nwith the subject as its first argument,\nand an object with the key `\"matchType\"` set to `\"boolean\"`\nas its second argument.\n\nIf it returns a truthy value\n(one which becomes `true` when `!!` is used on it)\nthe match is successful;\notherwise,\nthe match fails.\nIf it throws,\nit passes the error up.\n\nNote: [Extractor patterns](#extractor-patterns) use the identical machinery,\nbut allow further matching against the returned value,\nrather than being limited to just returning true/false.\n\n#### Examples\n\n```js\n```\n\n\n#### Built-in Custom Matchers\n\nSeveral JS objects have custom matchers installed on them by default.\n\nAll of the classes for primitive types\n(Boolean, String, Number, BigInt, Symbol)\nexpose a built-in Symbol.customMatcher static method,\nmatching if and only if the subject is\na primitive (or a boxed object) corresponding to that type\nThe return value of a successful match\n(for the purpose of [extractor patterns](#extractor-patterns))\nis an iterator containing the (possibly auto-unboxed) primitive value.\n\n```js\nclass Boolean {\n    static [Symbol.customMatcher](subject) {\n        return typeof subject == \"boolean\";\n    }\n}\n/* et cetera for the other primitives */\n```\n\n`Function.prototype` has a custom matcher\nthat checks if the function has an `[[IsClassConstructor]]` slot\n(meaning it's the `constructor()` function from a `class` block);\nif so, it tests whether the subject is an object of that class\n(using brand-checking to verify, similar to `Array.isArray()`);\nif not, it invokes the function as a predicate,\npassing it the subject,\nand returns the return value:\n\n```js\n/* roughly */\nFunction.prototype[Symbol.customMatcher] = function(subject) {\n    if(isClassConstructor(this)) {\n        return hasCorrectBrand(this, subject);\n    } else {\n        return this(subject);\n    }\n}\n```\n\nThis way, predicate functions can be used directly as matchers,\nlike `x is upperAlpha`,\nand classes can also be used directly as matchers\nto test if objects are of that class,\nlike `x is Option.Some`.\n\n`RegExp.prototype` has a custom matcher\nthat executes the regexp on the subject,\nand matches if the match was successful:\n\n```js\nRegExp.prototype[Symbol.customMatcher] = function(subject, {matchType}) {\n    const result = this.exec(subject);\n    if(matchType == \"boolean\") return result;\n    if(matchType == \"extractor\") return [result, ...result.slice(1)];\n}\n```\n\n\n#### Examples\n\n```js\n```\n\n\n### Binding Patterns\n\nA `let`, `const`, or `var` keyword followed by a valid variable name\n(identical to binding statements anywhere else).\nBinding patterns always match,\nand additionally introduce a binding,\nbinding the subject to the given name\nwith the given binding semantics.\n\n\n#### Binding Behavior Details\n\nAs with normal binding statements,\nthe bindings introduced by binding patterns\nare established in the nearest block scope\n(for `let`/`const`)\nor the nearest function scope (for `var`).\n\nIssue: Or in the obvious scope, when used in a for/while header or a function arglist.\nDon't know the right term for this off the top of my head.\n\nBindings are established according to their *presence* in a pattern;\nwhether or not the binding pattern itself is ever executed is irrelevant.\n(For example, `[1, 2] is [\"foo\", let foo]`\nwill still establish a `foo` binding in the block scope,\ndespite the first pattern failing to match\nand thus skipping the binding pattern.)\n\nStandard TDZ rules apply before the binding pattern is actually executed.\n(For example, `when [x, let x]` is an early `ReferenceError`,\nsince the `x` binding has not yet been initialized\nwhen the first pattern is run\nand attempts to dereference `x`.)\n\nUnlike standard binding rules,\nwithin the scope of an entire top-level pattern,\na given name can appear in multiple binding patterns,\nas long as all instances use the same binding type keyword.\nIt is a runtime `ReferenceError`\nif more than one of these binding patterns actually execute, however\n(with one exception - see [`or` patterns](#or-patterns)).\n(This behavior has precedent:\nit was previously the case that named capture groups\nhad to be completely unique within a regexp.\nNow they're allowed to be repeated\nas long as they're in different branches of an alternative,\nlike `/foo(?\u003cpart\u003e.*)|(?\u003cpart\u003e.*)foo/`.)\n\n\n#### Examples\n\n```js\n(x or [let y]) and (z or {key: let y})\n```\n\nValid at parse-time: both binding patterns name `y`\nwith `let` semantics.\nThis establishes a `y` binding in the nearest block scope.\n\nIf x *or* z matches, but not both,\nthen `y` gets bound appropriately.\nIf neither matches, `y` remains uninitialized\n(so it's a runtime ReferenceError to use it).\nIf both match, a runtime ReferenceError is thrown\nwhile executing the second `let y` pattern,\nas its binding has already been initialized.\n\n```js\n(x or [let y]) and (z or {key: const y})\n```\nEarly ReferenceError, as `y` is being bound twice\nwith differing semantics.\n\n```js\nx and let y and z and if(y == \"foo\")\n```\nValid at parse-time, establishes a `y` binding in block scope.\n\nIf x doesn't match,\n`y` remains uninitialized,\nbut the guard pattern is also skipped,\nso no runtime error (yet).\nIf z doesn't match,\n`y` is initialized to the match subject,\nbut the `if()` test never runs.\n\n```js\n[let x and String] or {length: let x}\n```\nValid at parse-time, establishes an `x` binding.\n\n[`or` pattern](#or-patterns) semantics allow overriding an already-initialized binding,\nif that binding came from an earlier failed sub-pattern,\nto avoid forcing authors to awkwardly arrange their binding patterns\nafter the fallible tests.\n\nSo in this example, if passed an object like `[5]`,\nit will pass the initial length check,\nexecute the `let x` pattern and bind it to `5`,\nthen fail the `String` pattern,\nas the subject is a `Number`.\nIt will then continue to the next `or` sub-pattern,\nand successfully bind `x` to 1,\nas the existing binding was initialized in a failed sub-pattern.\n\n\n\n## Structure Patterns\n\nStructure patterns let you test the structure of the subject\n(its properties, its length, etc)\nand then recurse into that structure with additional matcher patterns.\n\n### Array Patterns\n\nA comma-separated list of zero or more patterns, surrounded by square brackets.\nIt represents a test that:\n\n1. The subject is iterable.\n2. The subject contains exactly as many iteration items\n  as the length of the array pattern.\n3. Each item matches the associated sub-pattern.\n\nFor example, `[\"foo\", {bar}]` will match\nwhen the subject is an iterable with exactly two items,\nthe first item is the string `\"foo\"`,\nand the second item has a `bar` property.\n\nThe final item in the array pattern can optionally be a \"rest pattern\":\neither a literal `...`,\nor a `...` followed by another pattern.\nIn either case, the presence of a rest pattern relaxes the length test\n(2 in the list above)\nto merely check that the subject has *at least* as many items\nas the array pattern,\nignoring the rest pattern.\nThat is, `[a, b, ...]` will only match a subject\nwho contains 2 or more items.\n\nIf the `...` is followed by a pattern,\nlike `[a, b, ...let c]`,\nthen the iterator is fully exhausted,\nall the leftover items are collected into an `Array`,\nand that array is then applied as the subject of the rest pattern's test.\n\nNote: The above implies that `[a, b]` will pull three items from the subject:\ntwo to match against the sub-patterns,\nand a third to verify that the subject doesn't *have* a third item.\n`[a, b, ...]` will pull only two items from the subject,\nto match against the sub-patterns.\n`[a, b, ...c]` will exhaust the subject's iterator,\nverifying it has at least two items\n(to match against the sub-patterns)\nand then pulling the rest to match against the rest pattern.\n\nArray pattern execution order is as follows:\n\n1. Obtain an iterator from the subject. Return failure if this fails.\n2. For each expected item up to the number of sub-patterns (ignoring the rest pattern, if present):\n    1. Pull one item from the iterator. Return failure if this fails.\n    2. Execute the corresponding pattern. Return failure if this doesn't match.\n3. If there is no rest pattern, pull one more item from the iterator, verifying that it's a `{done: true}` result. If so, return success; if not, return failure.\n4. If there is a `...` rest pattern, return success.\n5. If there is a `...\u003cpattern\u003e` rest pattern, pull the remaining items of the iterator into a fresh `Array`, then match the pattern against that. If it matches, return success; otherwise return failure.\n\nIssue: Or should we pull all the necessary values from the iterator first,\n*then* do all the matchers?\n\n#### Examples\n\n```js\nmatch (res) {\n  when isEmpty: ...;\n  when {data: [let page] }: ...;\n  when {data: [let frontPage, ...let pages] }: ...;\n  default: ...;\n}\n```\n\n[**Array patterns**](#array-patterns) implicitly check the length of the subject.\n\nThe first arm is a [variable pattern](#variable-patterns),\ninvoking the default `Function.prototype` custom matcher\nwhich calls `isEmpty(res)`\nand matches if that returns `true`.\n\nThe second arm is an [object pattern](#object-patterns)\nwhich contains an [array pattern](#array-patterns),\nwhich matches if `data` has exactly one element,\nand binds that element to `page` for the RHS.\n\nThe third arm matches if `data` has **at least one** element,\nbinding that first element to `frontPage`,\nand binding an array of any remaining elements to `pages`\nusing a rest pattern.\n\n\n#### Array Pattern Caching\n\nTo allow for idiomatic uses of generators\nand other \"single-shot\" iterators\nto be reasonably matched against several array patterns,\nthe iterators and their results are cached over the scope of the match construct.\n\nSpecifically, whenever a subject is matched against an array pattern,\nthe subject is used as the key in a cache,\nwhose value is the iterator obtained from the subject,\nand all items pulled from the subject by an array pattern.\n\nWhenever something would be matched against an array pattern,\nthe cache is first checked,\nand the already-pulled items stored in the cache are used for the pattern,\nwith new items pulled from the iterator only if necessary.\n\nFor example:\n\n```js\nfunction* integers(to) {\n  for(var i = 1; i \u003c= to; i++) yield i;\n}\n\nconst fiveIntegers = integers(5);\nmatch (fiveIntegers) {\n  when [let a]:\n    console.log(`found one int: ${a}`);\n    // Matching a generator against an array pattern.\n    // Obtain the iterator (which is just the generator itself),\n    // then pull two items:\n    // one to match against the `a` pattern (which succeeds),\n    // the second to verify the iterator only has one item\n    // (which fails).\n  when [let a, let b]:\n    console.log(`found two ints: ${a} and ${b}`);\n    // Matching against an array pattern again.\n    // The generator object has already been cached,\n    // so we fetch the cached results.\n    // We need three items in total;\n    // two to check against the patterns,\n    // and the third to verify the iterator has only two items.\n    // Two are already in the cache,\n    // so we’ll just pull one more (and fail the pattern).\n  default: console.log(\"more than two ints\");\n}\nconsole.log([...fiveIntegers]);\n// logs [4, 5]\n// The match construct pulled three elements from the generator,\n// so there’s two leftover afterwards.\n```\n\nWhen execution of the match construct finishes, all cached iterators are closed.\n\n\n### Object Patterns\n\nA comma-separated list of zero or more \"object pattern clauses\", wrapped in curly braces.\nEach \"object pattern clause\" is either `\u003ckey\u003e`, `let/var/const \u003cident\u003e` or `\u003ckey\u003e: \u003cpattern\u003e`,\nwhere `\u003ckey\u003e` is an identifier or a computed-key expression like `[Symbol.foo]`.\nIt represents a test that the subject:\n\n1. Has every specified property in its prototype chain.\n2. If the key has an associated sub-pattern,\n    then the value of that property matches the sub-pattern.\n\nA `\u003ckey\u003e` object pattern clause\nis exactly equivalent to `\u003ckey\u003e: void`.\nA `let/var/const \u003cident\u003e` object pattern clause\nis exactly equivalent to `\u003cident\u003e: let/var/const \u003cident\u003e`.\n\nThat is, `when {foo, let bar, baz: \"qux\"}`\nis equivalent to `when {foo: void, bar: let bar, baz: \"qux\"}`:\nit tests that the subject has `foo`, `bar`, and `baz` properties,\nintroduces a `bar` binding for the value of the `bar` property,\nand verifies that the value of the `baz` property is the string `\"qux\"`.\n\nAdditionally, object patterns can contain a \"rest pattern\":\na `...` followed by a pattern.\nUnlike array patterns, a lone `...` is not valid in an object pattern\n(since there's no strict check to relax).\nIf the rest pattern exists,\nthen all *enumerable own properties*\nthat aren't already matched by object pattern clauses\nare collected into a fresh object,\nwhich is then matched against the rest pattern.\n(This matches the behavior of object destructuring.)\n\nIssue: Do we want a `key?: pattern` pattern clause as well?\nMakes it an optional test -\n*if* the subject has this property,\nverify that it matches the pattern.\nIf the pattern is skipped because the property doesn't exist,\ntreat any bindings coming from the pattern\nthe same as ones coming from skipped `or` patterns.\n\nIssue: Ban `__proto__`? Do something funky?\n\nObject pattern execution order is as follows:\n\n1. For each non-rest object pattern clause `key: sub-pattern`, in source order:\n    1. Check that the subject has the property `key` (using `in`, or `HasProperty()`, semantics). If it doesn't, return failure.\n    2. Get the value of the `key` property, and match it against `sub-pattern`. If that fails to match, return failure.\n2. If there's a rest pattern clause,\n    collect all enumerable own properties of the subject\n    that weren't tested in the previous step,\n    and put them into a fresh `Object`.\n    Match that against the rest pattern.\n    If that fails, return failure.\n3. Return success.\n\n#### Examples\n\n```js\n```\n\n#### Object Pattern Caching\n\nSimilar to [array pattern caching](#array-pattern-caching),\nobject patterns cache their results over the scope of the match construct,\nso that multiple clauses don’t observably retrieve the same property multiple times.\n\n(Unlike array pattern caching,\nwhich is necessary for this proposal to work with iterators,\nobject pattern caching is a nice-to-have.\nIt does guard against some weirdness like non-idempotent getters\n(including, notably, getters that return iterators),\nand helps make idempotent-but-expensive getters usable in pattern matching\nwithout contortions,\nbut mostly it’s just for conceptual consistency.)\n\nWhenever a subject is matched against an object pattern,\nfor each property name in the object pattern,\na `(\u003csubject\u003e, \u003cproperty name\u003e)` tuple is used as the key in a cache,\nwhose value is the value of the property.\n\nWhenever something would be matched against an object pattern,\nthe cache is first checked,\nand if the subject and that property name are already in the cache,\nthe value is retrieved from cache instead of by a fresh Get against the subject.\n\nFor example:\n\n```js\nconst randomItem = {\n  get numOrString() { return Math.random() \u003c .5 ? 1 : \"1\"; }\n};\n\nmatch (randomItem) {\n  when {numOrString: Number}:\n    console.log(\"Only matches half the time.\");\n    // Whether the pattern matches or not,\n    // we cache the (randomItem, \"numOrString\") pair\n    // with the result.\n  when {numOrString: String}:\n    console.log(\"Guaranteed to match the other half of the time.\");\n    // Since (randomItem, \"numOrString\") has already been cached,\n    // we reuse the result here;\n    // if it was a string for the first clause,\n    // it’s the same string here.\n}\n```\n\nIssue: This potentially introduces a lot more caching,\nand the major use-case is just making sure that iterator caching\nworks both at the top-level and when nested in an object.\nExpensive or non-idempotent getters benefit,\nbut that's a much less important benefit.\nThis caching *is* potentially droppable,\nbut it will mean that we only cache iterables at the top level.\n\n### Extractor Patterns\n\nA dotted-ident followed by a parenthesized \"argument list\"\ncontaining the same syntax as an [array matcher](#array-matcher).\nRepresents a combination of a [custom matcher pattern](#custom-matcher-pattern)\nand an [array pattern](#array-patterns):\n\n1. The dotted-ident is resolved against the visible bindings.\n    If that results in an object with a `Symbol.customMatcher` property,\n    and the value of that property is a function,\n    then continue;\n    otherwise, this throws an XXX error.\n\n2. The custom matcher function is invoked with the subject as its first argument,\n    and an object with the key `\"matchType\"` set to `\"extractor\"`\n    as its second argument.\n    Let \u003cvar\u003eresult\u003c/var\u003e be the return value.\n\n3. Match \u003cvar\u003eresult\u003c/var\u003e against the [arglist pattern](#arglist-patterns).\n\nNote: While [custom matchers](#custom-matchers) only require the return value be *truthy* or *falsey*,\nextractor patterns are stricter about types:\nthe value must be *exactly* `true` or `false`,\nor an `Array`,\nor an iterable.\n\n#### Arglist Patterns\n\nAn arglist pattern is a sub-pattern of an Extractor Pattern,\nand is mostly identical to an [Array Pattern](#array-patterns).\nIt has identical syntax,\nexcept it's bounded by parentheses (`()`)\nrather than square brackets (`[]`).\nIt behaves slightly differently with a few subjects, as well:\n\n* a `false` subject always fails to match\n* a `true` subject matches as if it were an empty Array\n* an `Array` subject is matched per-index,\n    rather than invoking the iterator protocol.\n\nIf the subject is an `Array`,\nthen it's matched as follows:\n\n1. If the arglist pattern doesn't end in a rest pattern,\n    then the subject's `length` property must exactly equal\n    the length of the pattern,\n    or it fails to match.\n\n2. If the arglist pattern *does* end in a rest pattern,\n    then the subject's `length` property must be equal or greater\n    than the length of the pattern - 1,\n    or it fails to match.\n\n3. For each non-rest sub-pattern of the arglist pattern,\n    the corresponding integer-valued property of the subject is fetched,\n    and matched against the corresponding sub-pattern.\n\n4. If the final sub-pattern is a `...\u003cpattern\u003e`,\n    collect the remaining integer-valued properties of the subject,\n    up to but not including its `length` value,\n    into a fresh Array,\n    and match against that pattern.\n\n5. If any of the matches failed,\n    the entire arglist pattern fails to match.\n    Otherwise, it succeeds.\n\nOther than the above exceptions,\narglist patterns are matched\nexactly the same as array patterns.\n\nIssue: Do we cache arglists the same way we cache array patterns?\n\nNote: The `Array` behavior here\nis for performance, based on implementor feedback.\nInvoking the iterator protocol is expensive,\nand we don't want to discourage use of custom matchers\nwhen the *by far* expected usage pattern\nis to just return an `Array`,\nrather than some more complex iterable.\nWe're (currently) still sticking with iterator protocol for array matchers,\nto match destructuring,\nbut could potentially change that.\n\n\n\n#### Examples\n\n```js\nclass Option {\n  constructor() { throw new TypeError(); }\n  static Some = class extends Option {\n    constructor(value) { this.value = value; }\n    map(cb) { return new Option.Some(cb(this.value)); }\n    // etc\n    static [Symbol.customMatcher](subject) {\n      if (subject instanceof Option.Some) { return [subject.value]; }\n      return false;\n    }\n  };\n\n  static None = class extends Option {\n    constructor() { }\n    map(cb) { return this; }\n    // Use the default custom matcher,\n    // which just checks that the subject matches the class.\n  };\n}\n\nlet val = Option.Some(5);\nmatch(val) {\n  when Option.Some(String and let a): console.log(`Got a string \"${a}\".`);\n  when Option.Some(Number and let a): console.log(`Got a number ${a}.`);\n  when Option.Some(...): console.log(`Got something unexpected.`);\n  // Or `Option.Some`, either works.\n  // `Option.Some()` will never match, as the return value\n  // is a 1-item array, which doesn't match `[]`\n  when Option.None(): console.log(`Operation failed.`);\n  // or `Option.None`, either works\n  default: console.log(`Didn't get an Option at all.`)\n}\n```\n\nIssue: We don't have an easy way to get access to the \"built-in\" custom matcher,\nso the above falls back to doing an instanceof test\n(rather than the technically more correct branding test\nthat the built-in one does).\nTo work \"properly\" I'd have to define the class without a custom matcher,\nthen pull off the custom matcher,\nsave it to a local variable,\nand define a new custom matcher that invokes the original one\nand returns the `[subject.value]` on success.\nThat's a silly amount of work for correctness.\n\n\n## Combinator Patterns\n\nSometimes you need to match multiple patterns on a single value,\nor pass a value that matches any of several patterns,\nor just negate a pattern.\nAll of these can be achieved with combinator patterns.\n\n### And Patterns\n\nTwo or more patterns, each separated by the keyword `and`.\nThis represents a test\nthat the subject passes *all* of the sub-patterns.\nAny pattern can be\n(and in some cases must be, see [combining combinators](#combining-combinator-patterns))\nwrapped in parentheses.\n\nShort-circuiting applies; if any sub-pattern fails to match the subject,\nmatching stops immediately.\n\n`and` pattern execution order is as follows:\n\n1. For each sub-pattern, in source order, match the subject against the sub-pattern. If that fails to match, return failure.\n2. Return success.\n\n\n### Or Patterns\n\nTwo or more patterns, each separated by the keyword `or`.\nThis represents a test\nthat the subject passes *at least one* of the sub-patterns.\nAny pattern can be\n(and in some cases must be, see [combining combinators](#combining-combinator-patterns))\nwrapped in parentheses.\n\nShort-circuiting applies; if any sub-pattern successfully matches the subject,\nmatching stops immediately.\n\n`or` pattern execution order is as follows:\n\n1. For each sub-pattern, in source order, match the subject against the sub-pattern. If that successfully matches, return success.\n2. Return failure.\n\nNote: As defined in [Binding Behavior Details](#binding-behavior-details),\na [binding pattern](#binding-patterns) in a failed sub-pattern\ncan be overridden by a binding pattern in a later sub-pattern\nwithout error.\nThat is, `[let foo] or {length: let foo}` is valid\nboth at parse-time and run-time,\neven tho the `foo` binding is potentially initialized twice\n(given a subject like `[1, 2]`).\n\n\n### Not Patterns\n\nA pattern preceded by the keyword `not`.\nThis represents a test that the subject *does not* match the sub-pattern.\nThe pattern can be\n(and in some cases must be, see [combining combinators](#combining-combinator-patterns))\nwrapped in parentheses.\n\n\n### Combining Combinator Patterns\n\nCombinator patterns cannot be combined at the same \"level\";\nthere is no precedence relationship between them.\nInstead, parentheses must be used to explicitly provide an ordering.\n\nThat is, `foo and bar or baz` is a syntax error;\nit must be written `(foo and bar) or baz`\nor `foo and (bar or baz)`.\n\nSimilarly, `not foo and bar` is a syntax error;\nit must be written `(not foo) and bar`\nor `not (foo and bar)`.\n\n\n## Guard Patterns\n\nA guard pattern has the syntax `if(\u003cexpression\u003e)`,\nand represents a test that the expression is truthy.\nThis is an arbitrary JS expression,\n*not* a pattern.\n\n\n\n# `match` expression\n\n`match` expressions are a new type of expression\nthat makes use of [patterns](#patterns)\nto select one of several expressions to resolve to.\n\nA match expression looks like:\n\n```js\nmatch(\u003csubject-expression\u003e) {\n    when \u003cpattern\u003e: \u003cvalue-expression\u003e;\n    when \u003cpattern\u003e: \u003cvalue-expression\u003e;\n    ...\n    default: \u003cvalue-expression\u003e;\n}\n```\n\nThat is, the `match` head contains a `\u003csubject-expression\u003e`,\nwhich is an arbitrary JS expression\nthat evaluates to a \"subject\".\n\nThe `match` block contains zero or more \"match arms\",\nconsisting of:\n* the keyword `when`\n* a [pattern](#patterns)\n* a literal colon\n* an arbitrary JS expression\n* a semicolon (yes, required)\n\nAfter the match arms,\nit can optionally contain default a \"default arm\",\nconsisting of:\n* the keyword `default`\n* a literal colon\n* an arbitrary JS expression\n* a semicolon\n\nAfter obtaining the subject,\neach match arm is tested in turn,\nmatching the subject against the arm's pattern.\nIf the match is successful,\nthe arm's expression is evaluated,\nand the `match` expression resolves to that result.\n\nIf all match arms fail to match,\nand there is a default arm,\nthe default arm's expression is evaluated,\nand the `match` expression resolves to that result.\nIf there is no default arm,\nthe `match` expression throws a `TypeError`.\n\n## Bindings\n\nThe `\u003csubject-expression\u003e` is part of the nearest block scope.\n\nEach match arm and the default arm\nare independent nested block scopes,\ncovering both the pattern and the expression of the arm.\n(That is, different arms can't see each other's bindings,\nand the bindings don't escape the `match` expression.\nWithin each arm, they shadow the outer scope's bindings.)\n\n## Examples\n\n```jsx\nmatch (res) {\n  when { status: 200, let body, ...let rest }: handleData(body, rest);\n  when { const status, destination: let url } and if (300 \u003c= status \u0026\u0026 status \u003c 400):\n    handleRedirect(url);\n  when { status: 500 } and if (!this.hasRetried): do {\n    retry(req);\n    this.hasRetried = true;\n  };\n  default: throwSomething();\n}\n```\n\nThis example tests a \"response\" object against several patterns,\nbranching based on the `.status` property,\nand extracting different parts from the response in each branch\nto process in various handler functions.\n\n-----\n\n```js\nmatch (command) {\n  when ['go', let dir and ('north' or 'east' or 'south' or 'west')]: go(dir);\n  when ['take', /[a-z]+ ball/ and {let weight}: takeBall(weight);\n  default: lookAround()\n}\n```\n\nThis sample is a contrived parser for a text-based adventure game.\n\nThe first match arm matches if the command is an array with exactly two items.\nThe first must be exactly the string `'go'`,\nand the second must be one of the given cardinal directions.\nNote the use of the [**and pattern**](#and-patterns)\nto bind the second item in the array to `dir`\nusing a [**binding pattern**](#binding-patterns)\nbefore verifying (using the [or pattern](#or-patterns))\nthat it’s one of the given directions.\n\nThe second match arm is slightly more complex.\nFirst, a [regex pattern](#regex-patterns) is used\nto verify that the object stringifies to `\"something ball\"`,\nthen an [object patterns](#object-patterns)\nverifies that it has a `.weight` property\nand binds it to `weight`,\nso that the weight is available to the arm's expression.\n\n## Statement vs Expression\n\nFor maximum expressivity,\nthe `match` expression is an expression, not a statement.\nThis allows for easy use in expression contexts\nlike `return match(val){...}`.\n\nIt can, of course, be used in statement context,\nas in the first example above.\nHowever, the match arms still contain expressions only.\n\nIt is *expected* that do-expressions will allow\nfor match arms to execute statements\n(again, as in the first example above).\nIf that proposal does not end up advancing,\na future iteration of this proposal will include some way\nto have a match arm contain statements.\n(Probably just by inlining do-expr's functionality.)\n\n# `is` operator\n\nThe `is` operator is a new boolean operator,\nof the form `\u003csubject-expression\u003e is \u003cpattern\u003e`.\nIt returns a boolean result,\nindicating whether the subject matched the pattern or not.\n\n## Bindings\n\nBindings established in the pattern of an `is`\nare visible in the nearest block scope,\nas defined in [Binding Patterns](#binding-patterns).\n\nThis includes when used in the head of an `if()` statement:\n\n```js\nfunction foo(x) {\n    if(x is [let head, ...let rest]) {\n        console.log(head, rest);\n    } else {\n        // `head` and `rest` are defined here,\n        // but will throw a ReferenceError if dereferenced,\n        // since if the pattern failed\n        // the binding patterns must not have been executed.\n    }\n}\n\nfunction bar(x) {\n    if(x is not {let necessaryProperty}) {\n        // Pattern succeeded, because `x.necessaryProperty`\n        // doesn't exist.\n        return;\n    }\n    // Here the pattern failed because `x.necessaryProperty`\n    // *does* exist, so the binding pattern was executed,\n    // and the `necessaryProperty` binding is visible here.\n    console.log(necessaryProperty);\n}\n```\n\nWhen used in the head of a `for()`,\nthe usual binding scopes apply:\nthe bindings are scoped to the `for()` head+block,\nand in the case of `for-of`,\nare copied to the inner per-iteration binding scopes.\n\n`while` and `do-while` do not currently have any special scoping rules\nfor things in their heads.\nWe propose that they adopt the same rules as `for-of` blocks:\nthe head is in a new scope surrounding the rule,\nand its bindings are copied to a per-iteration scope\nsurrounding the `{}` block.\nFor do-while,\nthe bindings are TDZ on the first iteration,\nbefore the head is executed.\n\n\n\n\n\n\n# Motivating examples\n\nBelow are selected situations where we expect pattern matching will be widely\nused. As such, we want to optimize the ergonomics of such cases to the best of\nour ability.\n\n------\n\nValidating JSON structure.\n\nHere's the simple destructuring version of the code,\nwhich does zero checks on the data ahead of time,\njust pulls it apart and hopes everything is correct:\n\n```js\nvar json = {\n  'user': ['Lily', 13]\n};\nvar {user: [name, age]} = json;\nprint(`User ${name} is ${age} years old.`);\n```\n\nDestructuring with checks that everything is correct and of the expected shape:\n\n```js\nif ( json.user !== undefined ) {\n  var user = json.user;\n  if (Array.isArray(user) \u0026\u0026\n      user.length == 2 \u0026\u0026\n      typeof user[0] == \"string\" \u0026\u0026\n      typeof user[1] == \"number\") {\n    var [name, age] = user;\n    print(`User ${name} is ${age} years old.`);\n  }\n}\n```\n\nExactly the same checks, but using pattern-matching:\n\n```js\nif( json is {user: [String and let name, Number and let age]} ) {\n  print(`User ${name} is ${age} years old.`);\n}\n```\n\n------\n\nMatching `fetch()` responses:\n\n```jsx\nconst res = await fetch(jsonService)\nmatch (res) {\n  when { status: 200, headers: { 'Content-Length': let s } }:\n    console.log(`size is ${s}`);\n  when { status: 404 }:\n    console.log('JSON not found');\n  when { let status } and if (status \u003e= 400): do {\n    throw new RequestError(res);\n  }\n};\n```\n\n---\n\nMore concise, more functional handling of Redux reducers (compare with\n[this same example in the Redux documentation](https://redux.js.org/basics/reducers#splitting-reducers)):\n\n```jsx\nfunction todosReducer(state = initialState, action) {\n  return match (action) {\n    when { type: 'set-visibility-filter', payload: let visFilter }:\n      { ...state, visFilter };\n    when { type: 'add-todo', payload: let text }:\n      { ...state, todos: [...state.todos, { text, completed: false }] };\n    when { type: 'toggle-todo', payload: let index }: do {\n      const newTodos = state.todos.map((todo, i) =\u003e {\n        return i !== index ? todo : {\n          ...todo,\n          completed: !todo.completed\n        };\n      });\n\n      ({\n        ...state,\n        todos: newTodos,\n      });\n    }\n    default: state // ignore unknown actions\n  }\n}\n```\n\n---\n\nConcise conditional logic in JSX (via\n[Divjot Singh](https://twitter.com/bogas04/status/977499729557839873)):\n\n```jsx\n\u003cFetch url={API_URL}\u003e\n  {props =\u003e match (props) {\n    when {loading}: \u003cLoading /\u003e;\n    when {let error}: do {\n      console.err(\"something bad happened\");\n      \u003cError error={error} /\u003e\n    };\n    when {let data}: \u003cPage data={data} /\u003e;\n  }}\n\u003c/Fetch\u003e\n```\n\n\n# Possible future enhancements\n\n## Void Patterns\n\nThe keyword `void` is a pattern\nthat always matches,\nand does nothing else.\nIt's useful in structure patterns,\nwhen you want to test for the existence of a property\nwithout caring what its value is.\n\nThis is the most likely proposal to move back into the main proposal;\nit's pulled out solely because we want to make sure\nthat it stays consistent\nwith [Void Bindings](https://github.com/tc39/proposal-discard-binding).\n\n## `async match`\n\nIf the `match` construct appears inside a context where `await` is allowed,\n`await` can already be used inside it, just like inside `do` expressions.\nHowever, just like `async do` expressions, there’s uses of being able to use\n`await` and produce a Promise, even when not already inside an `async function`.\n\n```js\nasync match (await subject) {\n  when { let a }: await a;\n  when { let b }: b.then(() =\u003e 42);\n  default: await somethingThatRejects();\n} // produces a Promise\n```\n\n## Relational Patterns\n\nCurrently there are patterns for expressing various types of equality,\nand kinda an instanceof (for custom matchers against a class).\nWe could express more types of operator-based checks,\nlike:\n\n```js\nmatch(val) {\n    when \u003c 10: console.log(\"small\");\n    when \u003e= 10 and \u003c 20: console.log(\"mid\");\n    default: \"large\";\n}\n```\n\nGenerally, all the binary boolean operators could be used,\nwith the subject as the implicit LHS of the operator.\n\n(This would slightly tie our hands on future syntax expansions for patterns,\nbut it's unlikely we'd ever *want* to reuse existing operators\nin a way that's different from how they work in expression contexts.)\n\n## Default Values\n\nDestructuring can supply a default value with `= \u003cexpr\u003e` which is used when a\nkey isn’t present. Is this useful for pattern matching?\n\nOptional keys seem reasonable; right now they’d require duplicating the pattern\nlike `({a, b} or {a})` (`b` will be bound to undefined in the RHS if not present).\n\nDo we need/want full defaulting? Does it complicate the syntax to much to have\narbitrary JS expressions there, without anything like wrapper characters to\ndistinguish it from surrounding patterns?\n\nThis would bring us into closer alignment with destructuring, which is nice.\n\n\n## Destructuring enhancements\n\nBoth destructuring and pattern matching should remain in sync, so enhancements\nto one would need to work for the other.\n\n## Integration with `catch`\n\nAllow a `catch` statement to conditionally catch an exception, saving a level of\nindentation:\n\n```js\ntry {\n  throw new TypeError('a');\n} catch match (e) {\n  when RangeError: ...;\n  when /^abc$/: ...;\n  // unmatched, default to rethrowing e\n}\n```\n\nOr possibly just allow an `is` check in the catch head:\n\n```js\ntry {\n  throw new TypeError('a');\n} catch (e is RangeError) {\n    ...\n} catch (e is /^abc$/) {\n    ...\n}\n```\n\n(In both cases, the name used for the subject automatically creates a binding,\nsame as `catch (e)` does today.)\n\n## Chaining guards\n\nSome reasonable use-cases require repetition of patterns today, like:\n\n```js\nmatch (res) {\n  when { status: 200 or 201, let pages, let data } and if (pages \u003e 1):\n    handlePagedData(pages, data);\n  when { status: 200 or 201, let pages, let data } and if (pages === 1):\n    handleSinglePage(data);\n  default: handleError(res);\n}\n```\n\nWe might want to allow match constructs to be chained, where the child match\nconstruct sees the bindings introduced in their parent clause, and which will\ncause the entire parent clause to fail if none of the sub-classes match.\n\nThe above would then be written as:\n\n```js\nmatch (res) {\n  when { status: 200 or 201, let data } match {\n    when { pages: 1 }: handleSinglePage(data);\n    when { pages: \u003e= 2 and let pages }: handlePagedData(pages, data);\n  };\n  default: handleError(res);\n  // runs if the status indicated an error,\n  // or if the data didn't match one of the above cases,\n  // notably if pages == 0\n}\n```\n\nNote the lack of a `\u003csubject-expression\u003e` in the child (just `match {...}`), to\nsignify that it’s chaining from the `when` rather than just being part an\nindependent match construct in the RHS (which would, instead, throw if none of\nthe clauses match):\n\n```js\nmatch (res) {\n  when { status: 200 or 201, let data }: match(res) {\n    when { pages: 1}: handleSinglePage(data);\n    when { pages: \u003e= 2 and let pages}: handlePagedData(pages, data);\n    // just an RHS, so if pages == 0,\n    // the inner construct fails to match anything\n    // and throws a TypeError\n  };\n  default: handleError(res);\n}\n```\n\nThe presence or absence of the separator colon also distinguishes these cases,\nof course.\n\n\n\u003c!--\n## Implementations\n\n* [Babel Plugin](https://github.com/babel/babel/pull/9318)\n* [Sweet.js macro](https://github.com/natefaubion/sparkler) (NOTE: this isn’t based on the proposal, this proposal is partially based on it!)\n--\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftc39%2Fproposal-pattern-matching","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftc39%2Fproposal-pattern-matching","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftc39%2Fproposal-pattern-matching/lists"}