You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: pages/docs/manual/v12.0.0/pattern-matching-destructuring.mdx
+160
Original file line number
Diff line number
Diff line change
@@ -478,6 +478,166 @@ if (person1.TAG) {
478
478
479
479
**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.)
480
480
481
+
### Match on subtype variants
482
+
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.
483
+
484
+
Let's look at an example:
485
+
486
+
<CodeTablabels={["ReScript", "JS Output"]}>
487
+
488
+
```res
489
+
type pets = Cat | Dog
490
+
type fish = Cod | Salmon
491
+
type animals = | ...pets | ...fish
492
+
493
+
let greetPet = (pet: pets) => {
494
+
switch pet {
495
+
| Cat => Console.log("Hello kitty!")
496
+
| Dog => Console.log("Woof woof doggie!")
497
+
}
498
+
}
499
+
500
+
let greetFish = (fish: fish) => {
501
+
switch fish {
502
+
| Cod => Console.log("Blub blub..")
503
+
| Salmon => Console.log("Blub blub blub blub..")
504
+
}
505
+
}
506
+
507
+
let greetAnimal = (animal: animals) => {
508
+
switch animal {
509
+
| ...pets as pet => greetPet(pet)
510
+
| ...fish as fish => greetFish(fish)
511
+
}
512
+
}
513
+
```
514
+
```js
515
+
functiongreetPet(pet) {
516
+
if (pet ==="Cat") {
517
+
console.log("Hello kitty!");
518
+
return;
519
+
}
520
+
console.log("Woof woof doggie!");
521
+
}
522
+
523
+
functiongreetFish(fish) {
524
+
if (fish ==="Cod") {
525
+
console.log("Blub blub..");
526
+
return;
527
+
}
528
+
console.log("Blub blub blub blub..");
529
+
}
530
+
531
+
functiongreetAnimal(animal) {
532
+
switch (animal) {
533
+
case"Cat" :
534
+
case"Dog" :
535
+
returngreetPet(animal);
536
+
case"Cod" :
537
+
case"Salmon" :
538
+
returngreetFish(animal);
539
+
}
540
+
}
541
+
```
542
+
</CodeTab>
543
+
544
+
Let's break down what we did:
545
+
* Defined two different variants for pets and for fish
546
+
* Wrote a dedicated function per animal type to greet that particular type of animal
547
+
* Combined `pets` and `fish` into a main variant for `animals`
548
+
* 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
549
+
550
+
Notice how we're able to match on parts of the main variant, as long as the variants are compatible.
551
+
552
+
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:
553
+
<CodeTablabels={["ReScript", "JS Output"]}>
554
+
555
+
```res
556
+
let isPet = (animal: animals) => {
557
+
switch animal {
558
+
| ...pets => Console.log("A pet!")
559
+
| _ => Console.log("Not a pet...")
560
+
}
561
+
}
562
+
563
+
```
564
+
```js
565
+
functionisPet(animal) {
566
+
switch (animal) {
567
+
case"Cat" :
568
+
case"Dog" :
569
+
console.log("A pet!");
570
+
return;
571
+
case"Cod" :
572
+
case"Salmon" :
573
+
console.log("Not a pet...");
574
+
return;
575
+
}
576
+
}
577
+
```
578
+
</CodeTab>
579
+
580
+
Similarily, if you want to get advanced, you can even pull out a single variant constructor. This works with and without aliases. Example:
581
+
582
+
<CodeTablabels={["ReScript", "JS Output"]}>
583
+
584
+
```res
585
+
type dog = Dog
586
+
type pets = Cat | ...dog
587
+
type fish = Cod | Salmon
588
+
type animals = | ...pets | ...fish
589
+
590
+
let isPet = (animal: animals) => {
591
+
switch animal {
592
+
| ...dog => Console.log("A dog!")
593
+
| _ => Console.log("Not a dog...")
594
+
}
595
+
}
596
+
597
+
```
598
+
```js
599
+
functionisPet(animal) {
600
+
if (animal ==="Dog") {
601
+
console.log("A dog!");
602
+
return;
603
+
}
604
+
console.log("Not a dog...");
605
+
}
606
+
```
607
+
</CodeTab>
608
+
609
+
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:
610
+
611
+
<CodeTablabels={["ReScript", "JS Output"]}>
612
+
613
+
```res
614
+
type pets = Cat | Dog
615
+
type fish = Cod | Salmon
616
+
type animals = | ...pets | ...fish
617
+
618
+
// Notice `dog` isn't spread into the `pets` variant,
619
+
// but this still work due to subtyping.
620
+
type dog = Dog
621
+
622
+
let isPet = (animal: animals) => {
623
+
switch animal {
624
+
| ...dog => Console.log("A dog!")
625
+
| _ => Console.log("Not a dog...")
626
+
}
627
+
}
628
+
629
+
```
630
+
```js
631
+
functionisPet(animal) {
632
+
if (animal ==="Dog") {
633
+
console.log("A dog!");
634
+
return;
635
+
}
636
+
console.log("Not a dog...");
637
+
}
638
+
```
639
+
</CodeTab>
640
+
481
641
### Match on Exceptions
482
642
483
643
If the function throws an exception (covered later), you can also match on _that_, in addition to the function's normally returned values.
0 commit comments