Wrong type with when guard and generics

Author: zoontekCreated Dec 14, 2021Updated May 16, 2025

Hi

As I try to create compatibility between this library and ts-belt, I noticed an issue with when guards when they use generics.

typescript
import { match, when } from "ts-pattern";

type Nullish = null | undefined;

const someGuard = <T>(option: T | Nullish): option is T => option != null;
const noneGuard = <T>(option: T | Nullish): option is Nullish => option == null;

const __Some = when(someGuard);
const __None = when(noneGuard);

const array = Array<string>(Math.floor(Math.random() * 10)).fill("foo");
const item = array[5];

if (someGuard(item)) {
  console.log(item); // type of item is string
}
if (noneGuard(item)) {
  console.log(item); // type of item is undefined
}

match(item)
  .with(__Some, item => { /* type of item is string | undefined, since ts-pattern struggles with generic type guards */ })
  .with(__None, item => { /* type of item is undefined */ })
  .exhaustive();

It works without generic:

typescript
import { match, when } from "ts-pattern";

type Nullish = null | undefined;

const someStringGuard = (option: string | Nullish): option is string => option != null;
const noneStringGuard = (option: string | Nullish): option is Nullish => option == null;

const __Some = when(someStringGuard);
const __None = when(noneStringGuard);

const array = Array<string>(Math.floor(Math.random() * 10)).fill("foo");
const item = array[5];

if (someGuard(item)) {
  console.log(item); // type of item is string
}
if (noneGuard(item)) {
  console.log(item); // type of item is undefined
}

match(item)
  .with(__Some, item => { /* type of item is string */})
  .with(__None, item => { /* type of item is undefined */ })
  .exhaustive();

Is there a way to achieve this (a generic guard pattern)?