Last Updated: 3/18/2026
P.not() - Negation Patterns
P.not() creates a pattern that matches everything except the specified value or pattern. It’s useful for excluding specific cases.
Basic Usage
import { match, P } from 'ts-pattern';
type Input = string | number | boolean;
const toNumber = (input: Input) =>
match(input)
.with(P.not(P.boolean), (n) => n) // n: string | number
.with(true, () => 1)
.with(false, () => 0)
.exhaustive();Signature
P.not<P extends Pattern>(pattern: P): PatternExamples
Negating Primitives
// Match anything except 'loading'
match(status)
.with(P.not('loading'), (status) => {
// status: Exclude<Status, 'loading'>
console.log('Not loading:', status);
})
.with('loading', () => 'Loading...')
.exhaustive();Negating Types
type Input = string | number | null;
match(input)
.with(P.not(P.nullish), (value) => {
// value: string | number
console.log('Has value:', value);
})
.with(P.nullish, () => 'No value')
.exhaustive();Negating Object Patterns
type State =
| { status: 'idle' }
| { status: 'loading' }
| { status: 'success'; data: string }
| { status: 'error'; error: Error };
match(state)
.with(
{ status: P.not('loading') },
(state) => {
// state: { status: 'idle' } | { status: 'success' | 'error', ... }
console.log('Not loading');
}
)
.otherwise(() => 'Loading');Excluding Multiple Values
Use P.union inside P.not to exclude multiple values:
match(status)
.with(
P.not(P.union('idle', 'loading')),
(status) => {
// status: Exclude<Status, 'idle' | 'loading'>
console.log('Active status:', status);
}
)
.otherwise(() => 'Inactive');Real-World Examples
State Machine Transitions
type State =
| { status: 'idle' }
| { status: 'loading'; startTime: number }
| { status: 'success'; data: string }
| { status: 'error'; error: Error };
type Event = { type: 'fetch' } | { type: 'cancel' };
const reducer = (state: State, event: Event) =>
match([state, event])
.with(
[{ status: P.not('loading') }, { type: 'fetch' }],
() => ({
status: 'loading' as const,
startTime: Date.now()
})
)
.with(
[{ status: 'loading' }, { type: 'cancel' }],
() => ({ status: 'idle' as const })
)
.otherwise(() => state);Form Validation
type FormField =
| { type: 'text'; value: string }
| { type: 'number'; value: number }
| { type: 'checkbox'; value: boolean }
| { type: 'file'; value: File };
const validateRequired = (field: FormField) =>
match(field)
.with(
{ type: P.not('checkbox'), value: '' },
() => 'This field is required'
)
.with(
{ type: P.not('checkbox'), value: P.not('') },
() => null // Valid
)
.with(
{ type: 'checkbox' },
(field) => null // Checkboxes have different validation
)
.exhaustive();Permission Checks
type User = {
role: 'admin' | 'editor' | 'viewer';
verified: boolean;
};
const canEdit = (user: User) =>
match(user)
.with(
{ role: P.not('viewer'), verified: true },
() => true
)
.otherwise(() => false);
const canDelete = (user: User) =>
match(user)
.with(
{ role: P.not(P.union('viewer', 'editor')), verified: true },
() => true
)
.otherwise(() => false);Combining with Other Patterns
P.not with P.when
match(user)
.with(
{
age: P.not(P.when((age) => age < 18)),
verified: true
},
(user) => 'Adult verified user'
)
.otherwise(() => 'Minor or unverified');P.not with P.select
match(response)
.with(
{ status: P.not('loading'), data: P.select() },
(data) => {
// status is not 'loading', data is selected
return processData(data);
}
)
.otherwise(() => null);Nested P.not
match(obj)
.with(
{
status: P.not('error'),
config: { mode: P.not('debug') }
},
() => 'Production mode'
)
.otherwise(() => 'Error or debug mode');Type Safety
TypeScript accurately narrows types when using P.not:
type Status = 'idle' | 'loading' | 'success' | 'error';
declare const status: Status;
match(status)
.with(P.not('loading'), (s) => {
// ✅ s: 'idle' | 'success' | 'error'
console.log(s);
})
.exhaustive();Common Pitfalls
Double Negation
Avoid using P.not(P.not(...)) as it’s confusing. Just use the positive pattern:
// ❌ Don't do this
.with(P.not(P.not('loading')), ...)
// ✅ Do this instead
.with('loading', ...)P.not with Arrays
P.not works with array patterns but be careful with type inference:
// Matches arrays that don't start with 'error'
match(arr)
.with([P.not('error'), ...P.array()], ...)
.otherwise(...);