diff --git a/pages/docs/manual/v12.0.0/pattern-matching-destructuring.mdx b/pages/docs/manual/v12.0.0/pattern-matching-destructuring.mdx index b6b0ed587..9983fab00 100644 --- a/pages/docs/manual/v12.0.0/pattern-matching-destructuring.mdx +++ b/pages/docs/manual/v12.0.0/pattern-matching-destructuring.mdx @@ -478,6 +478,166 @@ if (person1.TAG) { **Note:** Rescript versions < 9.0 had a `when` clause, not an `if` clause.  Rescript 9.0 changed `when` to `if`.  (`when` may still work, but is deprecated.) +### Match on subtype variants +You can refine a variant A to variant B using the [variant type spread syntax](variant.md#variant-type-spreads) in pattern matching. This is possible if variant B [is a subtype of](variant.md#coercion) variant A. + +Let's look at an example: + + + +```res +type pets = Cat | Dog +type fish = Cod | Salmon +type animals = | ...pets | ...fish + +let greetPet = (pet: pets) => { + switch pet { + | Cat => Console.log("Hello kitty!") + | Dog => Console.log("Woof woof doggie!") + } +} + +let greetFish = (fish: fish) => { + switch fish { + | Cod => Console.log("Blub blub..") + | Salmon => Console.log("Blub blub blub blub..") + } +} + +let greetAnimal = (animal: animals) => { + switch animal { + | ...pets as pet => greetPet(pet) + | ...fish as fish => greetFish(fish) + } +} +``` +```js +function greetPet(pet) { + if (pet === "Cat") { + console.log("Hello kitty!"); + return; + } + console.log("Woof woof doggie!"); +} + +function greetFish(fish) { + if (fish === "Cod") { + console.log("Blub blub.."); + return; + } + console.log("Blub blub blub blub.."); +} + +function greetAnimal(animal) { + switch (animal) { + case "Cat" : + case "Dog" : + return greetPet(animal); + case "Cod" : + case "Salmon" : + return greetFish(animal); + } +} +``` + + +Let's break down what we did: +* Defined two different variants for pets and for fish +* Wrote a dedicated function per animal type to greet that particular type of animal +* Combined `pets` and `fish` into a main variant for `animals` +* Wrote a function that can greet any animal by _spreading_ each sub variant on its own branch, aliasing that spread to a variable, and passing that variable to the dedicated greet function for that specific type + +Notice how we're able to match on parts of the main variant, as long as the variants are compatible. + +The example above aliases the variant type spread to a variable so we can use it in our branch. But, you can just as easily match without aliasing if you don't care about the value: + + +```res +let isPet = (animal: animals) => { + switch animal { + | ...pets => Console.log("A pet!") + | _ => Console.log("Not a pet...") + } +} + +``` +```js +function isPet(animal) { + switch (animal) { + case "Cat" : + case "Dog" : + console.log("A pet!"); + return; + case "Cod" : + case "Salmon" : + console.log("Not a pet..."); + return; + } +} +``` + + +Similarily, if you want to get advanced, you can even pull out a single variant constructor. This works with and without aliases. Example: + + + +```res +type dog = Dog +type pets = Cat | ...dog +type fish = Cod | Salmon +type animals = | ...pets | ...fish + +let isPet = (animal: animals) => { + switch animal { + | ...dog => Console.log("A dog!") + | _ => Console.log("Not a dog...") + } +} + +``` +```js +function isPet(animal) { + if (animal === "Dog") { + console.log("A dog!"); + return; + } + console.log("Not a dog..."); +} +``` + + +And, thanks to the rules of subtyping, the `Dog` constructor wouldn't _really_ need to be spread inside of the `pets` variant for this to work: + + + +```res +type pets = Cat | Dog +type fish = Cod | Salmon +type animals = | ...pets | ...fish + +// Notice `dog` isn't spread into the `pets` variant, +// but this still work due to subtyping. +type dog = Dog + +let isPet = (animal: animals) => { + switch animal { + | ...dog => Console.log("A dog!") + | _ => Console.log("Not a dog...") + } +} + +``` +```js +function isPet(animal) { + if (animal === "Dog") { + console.log("A dog!"); + return; + } + console.log("Not a dog..."); +} +``` + + ### Match on Exceptions If the function throws an exception (covered later), you can also match on _that_, in addition to the function's normally returned values.