0
# Key Types
1
2
Extract and work with object property keys based on their characteristics (optional, required, readonly, writable). These types help you work with the structure and metadata of object types.
3
4
## Capabilities
5
6
### OptionalKeys
7
8
Constructs a union type by picking all optional properties of object type `Type`.
9
10
```typescript { .api }
11
type OptionalKeys<Type> = {
12
[K in keyof Type]-?: {} extends Pick<Type, K> ? K : never;
13
}[keyof Type];
14
```
15
16
**Usage Example:**
17
18
```typescript
19
import type { OptionalKeys } from "ts-essentials";
20
21
type User = {
22
id: number;
23
name: string;
24
email?: string;
25
avatar?: string;
26
bio?: string;
27
};
28
29
type UserOptionalKeys = OptionalKeys<User>;
30
// Result: "email" | "avatar" | "bio"
31
32
// Use with Pick to get all optional properties
33
type OptionalUserProps = Pick<User, OptionalKeys<User>>;
34
// Result: { email?: string; avatar?: string; bio?: string; }
35
```
36
37
### PickKeys
38
39
Constructs a union type by picking all properties of object type `Type` which values are assignable to type `Value`.
40
41
```typescript { .api }
42
type PickKeys<Type, Value> = {
43
[K in keyof Type]: Type[K] extends Value ? K : never;
44
}[keyof Type];
45
```
46
47
**Usage Example:**
48
49
```typescript
50
import type { PickKeys } from "ts-essentials";
51
52
type User = {
53
id: number;
54
name: string;
55
email: string;
56
age: number;
57
isActive: boolean;
58
isAdmin: boolean;
59
};
60
61
type StringKeys = PickKeys<User, string>;
62
// Result: "name" | "email"
63
64
type BooleanKeys = PickKeys<User, boolean>;
65
// Result: "isActive" | "isAdmin"
66
67
type NumberKeys = PickKeys<User, number>;
68
// Result: "id" | "age"
69
70
// Use with Pick to extract properties by type
71
type UserStrings = Pick<User, PickKeys<User, string>>;
72
// Result: { name: string; email: string; }
73
```
74
75
### ReadonlyKeys
76
77
Constructs a union type by picking all `readonly` properties of object type `Type`.
78
79
```typescript { .api }
80
type ReadonlyKeys<Type> = {
81
[K in keyof Type]-?: ReadonlyEquivalent<
82
{ [Q in K]: Type[K] },
83
{ -readonly [Q in K]: Type[K] }
84
> extends true
85
? never
86
: K;
87
}[keyof Type];
88
```
89
90
**Usage Example:**
91
92
```typescript
93
import type { ReadonlyKeys } from "ts-essentials";
94
95
type User = {
96
readonly id: number;
97
name: string;
98
readonly createdAt: Date;
99
email: string;
100
readonly version: number;
101
};
102
103
type UserReadonlyKeys = ReadonlyKeys<User>;
104
// Result: "id" | "createdAt" | "version"
105
106
// Use with Pick to get all readonly properties
107
type ReadonlyUserProps = Pick<User, ReadonlyKeys<User>>;
108
// Result: { readonly id: number; readonly createdAt: Date; readonly version: number; }
109
```
110
111
### RequiredKeys
112
113
Constructs a union type by picking all required properties of object type `Type`.
114
115
```typescript { .api }
116
type RequiredKeys<Type> = {
117
[K in keyof Type]-?: {} extends Pick<Type, K> ? never : K;
118
}[keyof Type];
119
```
120
121
**Usage Example:**
122
123
```typescript
124
import type { RequiredKeys } from "ts-essentials";
125
126
type User = {
127
id: number;
128
name: string;
129
email?: string;
130
avatar?: string;
131
createdAt: Date;
132
};
133
134
type UserRequiredKeys = RequiredKeys<User>;
135
// Result: "id" | "name" | "createdAt"
136
137
// Use with Pick to get all required properties
138
type RequiredUserProps = Pick<User, RequiredKeys<User>>;
139
// Result: { id: number; name: string; createdAt: Date; }
140
141
// Useful for validation schemas
142
function validateRequiredFields<T>(
143
obj: T,
144
requiredKeys: RequiredKeys<T>[]
145
): boolean {
146
return requiredKeys.every(key => obj[key] !== undefined);
147
}
148
```
149
150
### WritableKeys
151
152
Constructs a union type by picking all writable properties of object type `Type`, meaning their values can be reassigned.
153
154
```typescript { .api }
155
type WritableKeys<Type> = {
156
[K in keyof Type]-?: ReadonlyEquivalent<
157
{ [Q in K]: Type[K] },
158
{ -readonly [Q in K]: Type[K] }
159
> extends true
160
? K
161
: never;
162
}[keyof Type];
163
```
164
165
**Usage Example:**
166
167
```typescript
168
import type { WritableKeys } from "ts-essentials";
169
170
type User = {
171
readonly id: number;
172
name: string;
173
email: string;
174
readonly createdAt: Date;
175
isActive: boolean;
176
};
177
178
type UserWritableKeys = WritableKeys<User>;
179
// Result: "name" | "email" | "isActive"
180
181
// Use with Pick to get all writable properties
182
type WritableUserProps = Pick<User, WritableKeys<User>>;
183
// Result: { name: string; email: string; isActive: boolean; }
184
185
// Useful for update operations
186
function updateUser<T>(
187
user: T,
188
updates: Partial<Pick<T, WritableKeys<T>>>
189
): T {
190
return { ...user, ...updates };
191
}
192
```
193
194
## Advanced Usage
195
196
Combine multiple key type utilities for complex type operations:
197
198
```typescript
199
import type { RequiredKeys, OptionalKeys, WritableKeys, ReadonlyKeys, PickKeys } from "ts-essentials";
200
201
type User = {
202
readonly id: number;
203
name: string;
204
email?: string;
205
readonly createdAt: Date;
206
isActive: boolean;
207
avatar?: string;
208
};
209
210
// Get required writable properties
211
type RequiredWritableKeys = RequiredKeys<User> & WritableKeys<User>;
212
// Result: "name" | "isActive"
213
214
// Get optional readonly properties
215
type OptionalReadonlyKeys = OptionalKeys<User> & ReadonlyKeys<User>;
216
// Result: never (no properties are both optional and readonly in this example)
217
218
// Get all string properties that are writable
219
type WritableStringKeys = WritableKeys<User> & PickKeys<User, string>;
220
// Result: "name"
221
222
// Create update type with only writable properties
223
type UserUpdate = Partial<Pick<User, WritableKeys<User>>>;
224
// Result: { name?: string; email?: string; isActive?: boolean; avatar?: string; }
225
```
226
227
## Types
228
229
```typescript { .api }
230
type ReadonlyEquivalent<X, Y> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2
231
? true
232
: false;
233
```