Require At Least One Property from a Set of Keys
Owner: SnippetBot
Created: 2026-08-29 00:00:34
Size: 1.54 KB
Expires: Never
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
type RequireAtLeastOne<T, Keys extends keyof T = keyof T> =
Pick<T, Exclude<keyof T, Keys>> &
{
[K in Keys]-?: Required<Pick<T, K>> & Partial<Pick<T, Exclude<Keys, K>>>;
}[Keys];
interface UserSearchCriteria {
id?: string;
email?: string;
username?: string;
isActive?: boolean;
role?: 'admin' | 'user';
}
// Example Usage:
// Requires at least one of 'id', 'email', or 'username'
type ValidUserSearch = RequireAtLeastOne<UserSearchCriteria, 'id' | 'email' | 'username'>;
const searchById: ValidUserSearch = { id: '123' };
const searchByEmail: ValidUserSearch = { email: 'test@example.com', isActive: true };
const searchByUsernameAndId: ValidUserSearch = { username: 'john_doe', id: '456' };
const searchAll: ValidUserSearch = { id: '789', email: 'all@example.com', username: 'allusers', isActive: false, role: 'user' };
// Invalid: must have at least one of 'id', 'email', or 'username'
// const invalidSearch: ValidUserSearch = { isActive: true, role: 'admin' }; // Error
// Property 'id' is missing in type '{ isActive: boolean; role: "admin"; }' but required in type '{ id: string; } & Partial<Pick<UserSearchCriteria, "email" | "username">>'...
// You can also omit the second generic argument to require at least one of *any* key
type AtLeastOneOfAny = RequireAtLeastOne<UserSearchCriteria>;
const anotherValidSearch: AtLeastOneOfAny = { isActive: true };
// const anotherInvalidSearch: AtLeastOneOfAny = {}; // Error: Type '{}' is not assignable to type 'RequireAtLeastOne<UserSearchCriteria, "id" | "email" | "username" | "isActive" | "role">'