type-fest 0.7.1 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.d.ts CHANGED
@@ -7,10 +7,15 @@ export {Mutable} from './source/mutable';
7
7
  export {Merge} from './source/merge';
8
8
  export {MergeExclusive} from './source/merge-exclusive';
9
9
  export {RequireAtLeastOne} from './source/require-at-least-one';
10
+ export {RequireExactlyOne} from './source/require-exactly-one';
11
+ export {PartialDeep} from './source/partial-deep';
10
12
  export {ReadonlyDeep} from './source/readonly-deep';
11
13
  export {LiteralUnion} from './source/literal-union';
12
14
  export {Promisable} from './source/promisable';
13
15
  export {Opaque} from './source/opaque';
16
+ export {SetOptional} from './source/set-optional';
17
+ export {SetRequired} from './source/set-required';
14
18
 
15
19
  // Miscellaneous
16
20
  export {PackageJson} from './source/package-json';
21
+ export {TsConfigJson} from './source/tsconfig-json';
package/package.json CHANGED
@@ -1,9 +1,10 @@
1
1
  {
2
2
  "name": "type-fest",
3
- "version": "0.7.1",
3
+ "version": "0.10.0",
4
4
  "description": "A collection of essential TypeScript types",
5
5
  "license": "(MIT OR CC0-1.0)",
6
6
  "repository": "sindresorhus/type-fest",
7
+ "funding": "https://github.com/sponsors/sindresorhus",
7
8
  "author": {
8
9
  "name": "Sindre Sorhus",
9
10
  "email": "sindresorhus@gmail.com",
@@ -31,12 +32,13 @@
31
32
  "json"
32
33
  ],
33
34
  "devDependencies": {
34
- "@sindresorhus/tsconfig": "^0.4.0",
35
- "@typescript-eslint/eslint-plugin": "^1.9.0",
36
- "@typescript-eslint/parser": "^1.10.2",
37
- "eslint-config-xo-typescript": "^0.14.0",
35
+ "@sindresorhus/tsconfig": "^0.7.0",
36
+ "@typescript-eslint/eslint-plugin": "2.17.0",
37
+ "@typescript-eslint/parser": "2.17.0",
38
+ "eslint-config-xo-typescript": "^0.24.1",
38
39
  "tsd": "^0.7.3",
39
- "xo": "^0.24.0"
40
+ "typescript": "3.7.5",
41
+ "xo": "^0.25.3"
40
42
  },
41
43
  "xo": {
42
44
  "extends": "xo-typescript",
package/readme.md CHANGED
@@ -23,7 +23,6 @@ Either add this package as a dependency or copy-paste the needed types. No credi
23
23
 
24
24
  PR welcome for additional commonly needed types and docs improvements. Read the [contributing guidelines](.github/contributing.md) first.
25
25
 
26
-
27
26
  ## Install
28
27
 
29
28
  ```
@@ -32,7 +31,6 @@ $ npm install type-fest
32
31
 
33
32
  *Requires TypeScript >=3.2*
34
33
 
35
-
36
34
  ## Usage
37
35
 
38
36
  ```ts
@@ -47,7 +45,6 @@ type FooWithoutRainbow = Except<Foo, 'rainbow'>;
47
45
  //=> {unicorn: string}
48
46
  ```
49
47
 
50
-
51
48
  ## API
52
49
 
53
50
  Click the type names for complete docs.
@@ -65,26 +62,30 @@ Click the type names for complete docs.
65
62
  ### Utilities
66
63
 
67
64
  - [`Except`](source/except.d.ts) - Create a type from an object type without certain keys. This is a stricter version of [`Omit`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-5.html#the-omit-helper-type).
68
- - [`Mutable`](source/mutable.d.ts) - Convert an object with `readonly` properties into a mutable object. Inverse of `Readonly<T>`.
65
+ - [`Mutable`](source/mutable.d.ts) - Convert an object with `readonly` keys into a mutable object. The inverse of `Readonly<T>`.
69
66
  - [`Merge`](source/merge.d.ts) - Merge two types into a new type. Keys of the second type overrides keys of the first type.
70
- - [`MergeExclusive`](source/merge-exclusive.d.ts) - Create a type that has mutually exclusive properties.
71
- - [`RequireAtLeastOne`](source/require-at-least-one.d.ts) - Create a type that requires at least one of the given properties.
72
- - [`ReadonlyDeep`](source/readonly-deep.d.ts) - Create a deeply immutable version of a `object`/`Map`/`Set`/`Array` type.
67
+ - [`MergeExclusive`](source/merge-exclusive.d.ts) - Create a type that has mutually exclusive keys.
68
+ - [`RequireAtLeastOne`](source/require-at-least-one.d.ts) - Create a type that requires at least one of the given keys.
69
+ - [`RequireExactlyOne`](source/require-exactly-one.d.ts) - Create a type that requires exactly a single key of the given keys and disallows more.
70
+ - [`PartialDeep`](source/partial-deep.d.ts) - Create a deeply optional version of another type. Use [`Partial<T>`](https://github.com/Microsoft/TypeScript/blob/2961bc3fc0ea1117d4e53bc8e97fa76119bc33e3/src/lib/es5.d.ts#L1401-L1406) if you only need one level deep.
71
+ - [`ReadonlyDeep`](source/readonly-deep.d.ts) - Create a deeply immutable version of an `object`/`Map`/`Set`/`Array` type. Use [`Readonly<T>`](https://github.com/Microsoft/TypeScript/blob/2961bc3fc0ea1117d4e53bc8e97fa76119bc33e3/src/lib/es5.d.ts#L1415-L1420) if you only need one level deep.
73
72
  - [`LiteralUnion`](source/literal-union.d.ts) - Create a union type by combining primitive types and literal types without sacrificing auto-completion in IDEs for the literal type part of the union. Workaround for [Microsoft/TypeScript#29729](https://github.com/Microsoft/TypeScript/issues/29729).
74
73
  - [`Promisable`](source/promisable.d.ts) - Create a type that represents either the value or the value wrapped in `PromiseLike`.
75
74
  - [`Opaque`](source/opaque.d.ts) - Create an [opaque type](https://codemix.com/opaque-types-in-javascript/).
75
+ - [`SetOptional`](source/set-optional.d.ts) - Create a type that makes the given keys optional.
76
+ - [`SetRequired`](source/set-required.d.ts) - Create a type that makes the given keys required.
76
77
 
77
78
  ### Miscellaneous
78
79
 
79
80
  - [`PackageJson`](source/package-json.d.ts) - Type for [npm's `package.json` file](https://docs.npmjs.com/creating-a-package-json-file).
80
-
81
+ - [`TsConfigJson`](source/tsconfig-json.d.ts) - Type for [TypeScript's `tsconfig.json` file](https://www.typescriptlang.org/docs/handbook/tsconfig-json.html) (TypeScript 3.7).
81
82
 
82
83
  ## Declined types
83
84
 
84
85
  *If we decline a type addition, we will make sure to document the better solution here.*
85
86
 
86
87
  - [`Diff` and `Spread`](https://github.com/sindresorhus/type-fest/pull/7) - The PR author didn't provide any real-world use-cases and the PR went stale. If you think this type is useful, provide some real-world use-cases and we might reconsider.
87
-
88
+ - [`Dictionary`](https://github.com/sindresorhus/type-fest/issues/33) - You only save a few characters (`Dictionary<number>` vs `Record<string, number>`) from [`Record`](https://github.com/Microsoft/TypeScript/blob/2961bc3fc0ea1117d4e53bc8e97fa76119bc33e3/src/lib/es5.d.ts#L1429-L1434), which is more flexible and well-known. Also, you shouldn't use an object as a dictionary. We have `Map` in JavaScript now.
88
89
 
89
90
  ## Tips
90
91
 
@@ -93,28 +94,539 @@ Click the type names for complete docs.
93
94
  There are many advanced types most users don't know about.
94
95
 
95
96
  - [`Partial<T>`](https://github.com/Microsoft/TypeScript/blob/2961bc3fc0ea1117d4e53bc8e97fa76119bc33e3/src/lib/es5.d.ts#L1401-L1406) - Make all properties in `T` optional.
97
+ <details>
98
+ <summary>
99
+ Example
100
+ </summary>
101
+
102
+ [Playground](https://www.typescriptlang.org/play/#code/JYOwLgpgTgZghgYwgAgHIHsAmEDC6QzADmyA3gLABQyycADnanALYQBcyAzmFKEQNxUaddFDAcQAV2YAjaIMoBfKlQQAbOJ05osEAIIMAQpOBrsUMkOR1eANziRkCfISKSoD4Pg4ZseAsTIALyW1DS0DEysHADkvvoMMQA0VsKi4sgAzAAMuVaKClY2wPaOknSYDrguADwA0sgQAB6QIJjaANYQAJ7oMDp+LsQAfAAUXd0cdUnI9mo+uv6uANp1ALoAlKHhyGAAFsCcAHTOAW4eYF4gyxNrwbNwago0ypRWp66jH8QcAApwYmAjxq8SWIy2FDCNDA3ToKFBQyIdR69wmfQG1TOhShyBgomQX3w3GQE2Q6IA8jIAFYQBBgI4TTiEs5bTQYsFInrLTbbHZOIlgZDlSqQABqj0kKBC3yINx6a2xfOQwH6o2FVXFaklwSCIUkbQghBAEEwENSfNOlykEGefNe5uhB2O6sgS3GPRmLogmslG1tLxUOKgEDA7hAuydtteryAA)
103
+
104
+ ```ts
105
+ interface NodeConfig {
106
+ appName: string;
107
+ port: number;
108
+ }
109
+
110
+ class NodeAppBuilder {
111
+ private configuration: NodeConfig = {
112
+ appName: 'NodeApp',
113
+ port: 3000
114
+ };
115
+
116
+ private updateConfig<Key extends keyof NodeConfig>(key: Key, value: NodeConfig[Key]) {
117
+ this.configuration[key] = value;
118
+ }
119
+
120
+ config(config: Partial<NodeConfig>) {
121
+ type NodeConfigKey = keyof NodeConfig;
122
+
123
+ for (const key of Object.keys(config) as NodeConfigKey[]) {
124
+ const updateValue = config[key];
125
+
126
+ if (updateValue === undefined) {
127
+ continue;
128
+ }
129
+
130
+ this.updateConfig(key, updateValue);
131
+ }
132
+
133
+ return this;
134
+ }
135
+ }
136
+
137
+ // `Partial<NodeConfig>`` allows us to provide only a part of the
138
+ // NodeConfig interface.
139
+ new NodeAppBuilder().config({appName: 'ToDoApp'});
140
+ ```
141
+ </details>
142
+
96
143
  - [`Required<T>`](https://github.com/Microsoft/TypeScript/blob/2961bc3fc0ea1117d4e53bc8e97fa76119bc33e3/src/lib/es5.d.ts#L1408-L1413) - Make all properties in `T` required.
144
+ <details>
145
+ <summary>
146
+ Example
147
+ </summary>
148
+
149
+ [Playground](https://typescript-play.js.org/?target=6#code/AQ4SwOwFwUwJwGYEMDGNgGED21VQGJZwC2wA3gFCjXAzFJgA2A-AFzADOUckA5gNxUaIYjA4ckvGG07c+g6gF8KQkAgCuEFFDA5O6gEbEwUbLm2ESwABQIixACJIoSdgCUYAR3Vg4MACYAPGYuFvYAfACU5Ko0APRxwADKMBD+wFAAFuh2Vv7OSBlYGdmc8ABu8LHKsRyGxqY4oQT21pTCIHQMjOwA5DAAHgACxAAOjDAAdChYxL0ANLHUouKSMH0AEmAAhJhY6ozpAJ77GTCMjMCiV0ToSAb7UJPPC9WRgrEJwAAqR6MwSRQPFGUFocDgRHYxnEfGAowh-zgUCOwF6KwkUl6tXqJhCeEsxDaS1AXSYfUGI3GUxmc0WSneQA)
150
+
151
+ ```ts
152
+ interface ContactForm {
153
+ email?: string;
154
+ message?: string;
155
+ }
156
+
157
+ function submitContactForm(formData: Required<ContactForm>) {
158
+ // Send the form data to the server.
159
+ }
160
+
161
+ submitContactForm({
162
+ email: 'ex@mple.com',
163
+ message: 'Hi! Could you tell me more about…',
164
+ });
165
+
166
+ // TypeScript error: missing property 'message'
167
+ submitContactForm({
168
+ email: 'ex@mple.com',
169
+ });
170
+ ```
171
+ </details>
172
+
97
173
  - [`Readonly<T>`](https://github.com/Microsoft/TypeScript/blob/2961bc3fc0ea1117d4e53bc8e97fa76119bc33e3/src/lib/es5.d.ts#L1415-L1420) - Make all properties in `T` readonly.
174
+ <details>
175
+ <summary>
176
+ Example
177
+ </summary>
178
+
179
+ [Playground](https://typescript-play.js.org/?target=6#code/AQ4UwOwVwW2AZA9gc3mAbmANsA3gKFCOAHkAzMgGkOJABEwAjKZa2kAUQCcvEu32AMQCGAF2FYBIAL4BufDRABLCKLBcywgMZgEKZOoDCiCGSXI8i4hGEwwALmABnUVxXJ57YFgzZHSVF8sT1BpBSItLGEnJz1kAy5LLy0TM2RHACUwYQATEywATwAeAITjU3MAPnkrCJMXLigtUT4AClxgGztKbyDgaX99I1TzAEokr1BRAAslJwA6FIqLAF48TtswHp9MHDla9hJGACswZvmyLjAwAC8wVpm5xZHkUZDaMKIwqyWXYCW0oN4sNlsA1h0ug5gAByACyBQAggAHJHQ7ZBIFoXbzBjMCz7OoQP5YIaJNYQMAAdziCVaALGNSIAHomcAACoFJFgADKWjcSNEwG4vC4ji0wggEEQguiTnMEGALWAV1yAFp8gVgEjeFyuKICvMrCTgVxnst5jtsGC4ljsPNhXxGaAWcAAOq6YRXYDCRg+RWIcA5JSC+kWdCepQ+v3RYCU3RInzRMCGwlpC19NYBW1Ye08R1AA)
180
+
181
+ ```ts
182
+ enum LogLevel {
183
+ Off,
184
+ Debug,
185
+ Error,
186
+ Fatal
187
+ };
188
+
189
+ interface LoggerConfig {
190
+ name: string;
191
+ level: LogLevel;
192
+ }
193
+
194
+ class Logger {
195
+ config: Readonly<LoggerConfig>;
196
+
197
+ constructor({name, level}: LoggerConfig) {
198
+ this.config = {name, level};
199
+ Object.freeze(this.config);
200
+ }
201
+ }
202
+
203
+ const config: LoggerConfig = {
204
+ name: 'MyApp',
205
+ level: LogLevel.Debug
206
+ };
207
+
208
+ const logger = new Logger(config);
209
+
210
+ // TypeScript Error: cannot assign to read-only property.
211
+ logger.config.level = LogLevel.Error;
212
+
213
+ // We are able to edit config variable as we please.
214
+ config.level = LogLevel.Error;
215
+ ```
216
+ </details>
217
+
98
218
  - [`Pick<T, K>`](https://github.com/Microsoft/TypeScript/blob/2961bc3fc0ea1117d4e53bc8e97fa76119bc33e3/src/lib/es5.d.ts#L1422-L1427) - From `T`, pick a set of properties whose keys are in the union `K`.
219
+ <details>
220
+ <summary>
221
+ Example
222
+ </summary>
223
+
224
+ [Playground](https://typescript-play.js.org/?target=6#code/AQ4SwOwFwUwJwGYEMDGNgEE5TCgNugN4BQoZwOUBAXMAM5RyQDmA3KeSFABYCuAtgCMISMHloMmENh04oA9tBjQJjFuzIBfYrOAB6PcADCcGElh1gEGAHcKATwAO6ebyjB5CTNlwFwSxFR0BX5HeToYABNgBDh5fm8cfBg6AHIKG3ldA2BHOOcfFNpUygJ0pAhokr4hETFUgDpswywkggAFUwA3MFtgAF5gQgowKhhVKTYKGuFRcXo1aVZgbTIoJ3RW3xhOmB6+wfbcAGsAHi3kgBpgEtGy4AAfG54BWfqAPnZm4AAlZUj4MAkMA8GAGB4vEgfMlLLw6CwPBA8PYRmMgZVgAC6CgmI4cIommQELwICh8RBgKZKvALh1ur0bHQABR5PYMui0Wk7em2ADaAF0AJS0AASABUALIAGQAogR+Mp3CROCAFBBwVC2ikBpj5CgBIqGjizLA5TAFdAmalImAuqlBRoVQh5HBgEy1eDWfs7J5cjzGYKhroVfpDEhHM4MV6GRR5NN0JrtnRg6BVirTFBeHAKYmYY6QNpdB73LmCJZBlSAXAubtvczeSmQMNSuMbmKNgBlHFgPEUNwusBIPAAQlS1xetTmxT0SDoESgdD0C4aACtHMwxytLrohawgA)
225
+
226
+ ```ts
227
+ interface Article {
228
+ title: string;
229
+ thumbnail: string;
230
+ content: string;
231
+ }
232
+
233
+ // Creates new type out of the `Article` interface composed
234
+ // from the Articles' two properties: `title` and `thumbnail`.
235
+ // `ArticlePreview = {title: string; thumbnail: string}`
236
+ type ArticlePreview = Pick<Article, 'title' | 'thumbnail'>;
237
+
238
+ // Render a list of articles using only title and description.
239
+ function renderArticlePreviews(previews: ArticlePreview[]): HTMLElement {
240
+ const articles = document.createElement('div');
241
+
242
+ for (const preview of previews) {
243
+ // Append preview to the articles.
244
+ }
245
+
246
+ return articles;
247
+ }
248
+
249
+ const articles = renderArticlePreviews([
250
+ {
251
+ title: 'TypeScript tutorial!',
252
+ thumbnail: '/assets/ts.jpg'
253
+ }
254
+ ]);
255
+ ```
256
+ </details>
257
+
99
258
  - [`Record<K, T>`](https://github.com/Microsoft/TypeScript/blob/2961bc3fc0ea1117d4e53bc8e97fa76119bc33e3/src/lib/es5.d.ts#L1429-L1434) - Construct a type with a set of properties `K` of type `T`.
259
+ <details>
260
+ <summary>
261
+ Example
262
+ </summary>
263
+
264
+ [Playground](https://typescript-play.js.org/?target=6#code/AQ4ejYAUHsGcCWAXBMB2dgwGbAKYC2ADgDYwCeeemCaWArgE7ADGMxAhmuQHQBQoYEnJE8wALKEARnkaxEKdMAC8wAOS0kstGuAAfdQBM8ANzxlRjXQbVaWACwC0JPB0NqA3HwGgIwAJJoWozYHCxixnAsjAhStADmwESMMJYo1Fi4HMCIaPEu+MRklHj8gpqyoeHAAKJFFFTAAN4+giDYCIxwSAByHAR4AFw5SDF5Xm2gJBzdfQPD3WPxE5PAlBxdAPLYNQAelgh4aOHDaPQEMowrIAC+3oJ+AMKMrlrAXFhSAFZ4LEhC9g4-0BmA4JBISXgiCkBQABpILrJ5MhUGhYcATGD6Bk4Hh-jNgABrPDkOBlXyQAAq9ngYmJpOAAHcEOCRjAXqwYODfoo6DhakUSph+Uh7GI4P0xER4Cj0OSQGwMP8tP1hgAlX7swwAHgRl2RvIANALSA08ABtAC6AD4VM1Wm0Kow0MMrYaHYJjGYLLJXZb3at1HYnC43Go-QHQDcvA6-JsmEJXARgCDgMYWAhjIYhDAU+YiMAAFIwex0ZmilMITCGF79TLAGRsAgJYAAZRwSEZGzEABFTOZUrJ5Yn+jwnWgeER6HB7AAKJrADpdXqS4ZqYultTG6azVfqHswPBbtauLY7fayQ7HIbAAAMwBuAEoYw9IBq2Ixs9h2eFMOQYPQObALQKJgggABeYhghCIpikkKRpOQRIknAsZUiIeCttECBEP8NSMCkjDDAARMGziuIYxHwYOjDCMBmDNnAuTxA6irdCOBB1Lh5Dqpqn66tISIykawBnOCtqqC0gbjqc9DgpGkxegOliyfJDrRkAA)
265
+
266
+ ```ts
267
+ // Positions of employees in our company.
268
+ type MemberPosition = 'intern' | 'developer' | 'tech-lead';
269
+
270
+ // Interface describing properties of a single employee.
271
+ interface Employee {
272
+ firstName: string;
273
+ lastName: string;
274
+ yearsOfExperience: number;
275
+ }
276
+
277
+ // Create an object that has all possible `MemberPosition` values set as keys.
278
+ // Those keys will store a collection of Employees of the same position.
279
+ const team: Record<MemberPosition, Employee[]> = {
280
+ intern: [],
281
+ developer: [],
282
+ 'tech-lead': [],
283
+ };
284
+
285
+ // Our team has decided to help John with his dream of becoming Software Developer.
286
+ team.intern.push({
287
+ firstName: 'John',
288
+ lastName: 'Doe',
289
+ yearsOfExperience: 0
290
+ });
291
+
292
+ // `Record` forces you to initialize all of the property keys.
293
+ // TypeScript Error: "tech-lead" property is missing
294
+ const teamEmpty: Record<MemberPosition, null> = {
295
+ intern: null,
296
+ developer: null,
297
+ };
298
+ ```
299
+ </details>
300
+
100
301
  - [`Exclude<T, U>`](https://github.com/Microsoft/TypeScript/blob/2961bc3fc0ea1117d4e53bc8e97fa76119bc33e3/src/lib/es5.d.ts#L1436-L1439) - Exclude from `T` those types that are assignable to `U`.
302
+ <details>
303
+ <summary>
304
+ Example
305
+ </summary>
306
+
307
+ [Playground](https://typescript-play.js.org/?target=6#code/JYOwLgpgTgZghgYwgAgMrQG7QMIHsQzADmyA3gFDLIAOuUYAXMiAK4A2byAPsgM5hRQJHqwC2AI2gBucgF9y5MAE9qKAEoQAjiwj8AEnBAATNtGQBeZAAooWphu26wAGmS3e93bRC8IASgsAPmRDJRlyAHoI5ABRAA8ENhYjFFYOZGVVZBgoXFFkAAM0zh5+QRBhZhYJaAKAOkjogEkQZAQ4X2QAdwALCFbaemRgXmQtFjhOMFwq9K6ULuB0lk6U+HYwZAxJnQaYFhAEMGB8ZCIIMAAFOjAANR2IK0HGWISklIAedCgsKDwCYgAbQA5M9gQBdVzFQJ+JhiSRQMiUYYwayZCC4VHPCzmSzAspCYEBWxgFhQAZwKC+FpgJ43VwARgADH4ZFQSWSBjcZPJyPtDsdTvxKWBvr8rD1DCZoJ5HPopaYoK4EPhCEQmGKcKriLCtrhgEYkVQVT5Nr4fmZLLZtMBbFZgT0wGBqES6ghbHBIJqoBKFdBWQpjfh+DQbhY2tqiHVsbjLMVkAB+ZAAZiZaeQTHOVxu9ySjxNaujNwDVHNvzqbBGkBAdPoAfkQA)
308
+
309
+ ```ts
310
+ interface ServerConfig {
311
+ port: null | string | number;
312
+ }
313
+
314
+ type RequestHandler = (request: Request, response: Response) => void;
315
+
316
+ // Exclude `null` type from `null | string | number`.
317
+ // In case the port is equal to `null`, we will use default value.
318
+ function getPortValue(port: Exclude<ServerConfig['port'], null>): number {
319
+ if (typeof port === 'string') {
320
+ return parseInt(port, 10);
321
+ }
322
+
323
+ return port;
324
+ }
325
+
326
+ function startServer(handler: RequestHandler, config: ServerConfig): void {
327
+ const server = require('http').createServer(handler);
328
+
329
+ const port = config.port === null ? 3000 : getPortValue(config.port);
330
+ server.listen(port);
331
+ }
332
+ ```
333
+ </details>
334
+
101
335
  - [`Extract<T, U>`](https://github.com/Microsoft/TypeScript/blob/2961bc3fc0ea1117d4e53bc8e97fa76119bc33e3/src/lib/es5.d.ts#L1441-L1444) - Extract from `T` those types that are assignable to `U`.
336
+ <details>
337
+ <summary>
338
+ Example
339
+ </summary>
340
+
341
+ [Playground](https://typescript-play.js.org/?target=6#code/CYUwxgNghgTiAEAzArgOzAFwJYHtXzSwEdkQBJYACgEoAueVZAWwCMQYBuAKDDwGcM8MgBF4AXngBlAJ6scESgHIRi6ty5ZUGdoihgEABXZ888AN5d48ANoiAuvUat23K6ihMQ9ATE0BzV3goPy8GZjZOLgBfLi4Aejj4AEEICBwAdz54MAALKFQQ+BxEeAAHY1NgKAwoIKy0grr4DByEUpgccpgMaXgAaxBerCzi+B9-ZulygDouFHRsU1z8kKMYE1RhaqgAHkt4AHkWACt4EAAPbVRgLLWNgBp9gGlBs8uQa6yAUUuYPQwdgNpKM7nh7mMML4CgA+R5WABqUAgpDeVxuhxO1he0jsXGh8EoOBO9COx3BQPo2PBADckaR6IjkSA6PBqTgsMBzPsicdrEC7OJWXSQNwYvFEgAVTS9JLXODpeDpKBZFg4GCoWa8VACIJykAKiQWKy2YQOAioYikCg0OEMDyhRSy4DyxS24KhAAMjyi6gS8AAwjh5OD0iBFHAkJoEOksC1mnkMJq8gUQKDNttKPlnfrwYp3J5XfBHXqoKpfYkAOI4ansTxaeDADmoRSCCBYAbxhC6TDx6rwYHIRX5bScjA4bLJwoDmDwDkfbA9JMrVMVdM1TN69LgkTgwgkchUahqIA)
342
+
343
+ ```ts
344
+ declare function uniqueId(): number;
345
+
346
+ const ID = Symbol('ID');
347
+
348
+ interface Person {
349
+ [ID]: number;
350
+ name: string;
351
+ age: number;
352
+ }
353
+
354
+ // Allows changing the person data as long as the property key is of string type.
355
+ function changePersonData<
356
+ Obj extends Person,
357
+ Key extends Extract<keyof Person, string>,
358
+ Value extends Obj[Key]
359
+ > (obj: Obj, key: Key, value: Value): void {
360
+ obj[key] = value;
361
+ }
362
+
363
+ // Tiny Andrew was born.
364
+ const andrew = {
365
+ [ID]: uniqueId(),
366
+ name: 'Andrew',
367
+ age: 0,
368
+ };
369
+
370
+ // Cool, we're fine with that.
371
+ changePersonData(andrew, 'name', 'Pony');
372
+
373
+ // Goverment didn't like the fact that you wanted to change your identity.
374
+ changePersonData(andrew, ID, uniqueId());
375
+ ```
376
+ </details>
377
+
102
378
  - [`NonNullable<T>`](https://github.com/Microsoft/TypeScript/blob/2961bc3fc0ea1117d4e53bc8e97fa76119bc33e3/src/lib/es5.d.ts#L1446-L1449) - Exclude `null` and `undefined` from `T`.
379
+ <details>
380
+ <summary>
381
+ Example
382
+ </summary>
383
+ Works with <code>strictNullChecks</code> set to <code>true</code>. (Read more <a href="https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-0.html">here</a>)
384
+
385
+ [Playground](https://typescript-play.js.org/?target=6#code/C4TwDgpgBACg9gJ2AOQK4FsBGEFQLxQDOwCAlgHYDmUAPlORtrnQwDasDcAUFwPQBU-WAEMkUOADMowqAGNWwwoSgATCBIqlgpOOSjAAFsOBRSy1IQgr9cKJlSlW1mZYQA3HFH68u8xcoBlHA8EACEHJ08Aby4oKDBUTFZSWXjEFEYcAEIALihkXTR2YSSIAB54JDQsHAA+blj4xOTUsHSACkMzPKD3HHDHNQQAGjSkPMqMmoQASh7g-oihqBi4uNIpdraxPAI2VhmVxrX9AzMAOm2ppnwoAA4ABifuE4BfKAhWSyOTuK7CS7pao3AhXF5rV48E4ICDAVAIPT-cGQyG+XTEIgLMJLTx7CAAdygvRCA0iCHaMwarhJOIQjUBSHaACJHk8mYdeLwxtdcVAAOSsh58+lXdr7Dlcq7A3n3J4PEUdADMcspUE53OluAIUGVTx46oAKuAIAFZGQwCYAKIIBCILjUxaDHAMnla+iodjcIA)
386
+
387
+ ```ts
388
+ type PortNumber = string | number | null;
389
+
390
+ /** Part of a class definition that is used to build a server */
391
+ class ServerBuilder {
392
+ portNumber!: NonNullable<PortNumber>;
393
+
394
+ port(this: ServerBuilder, port: PortNumber): ServerBuilder {
395
+ if (port == null) {
396
+ this.portNumber = 8000;
397
+ } else {
398
+ this.portNumber = port;
399
+ }
400
+
401
+ return this;
402
+ }
403
+ }
404
+
405
+ const serverBuilder = new ServerBuilder();
406
+
407
+ serverBuilder
408
+ .port('8000') // portNumber = '8000'
409
+ .port(null) // portNumber = 8000
410
+ .port(3000); // portNumber = 3000
411
+
412
+ // TypeScript error
413
+ serverBuilder.portNumber = null;
414
+ ```
415
+ </details>
416
+
103
417
  - [`Parameters<T>`](https://github.com/Microsoft/TypeScript/blob/2961bc3fc0ea1117d4e53bc8e97fa76119bc33e3/src/lib/es5.d.ts#L1451-L1454) - Obtain the parameters of a function type in a tuple.
418
+ <details>
419
+ <summary>
420
+ Example
421
+ </summary>
422
+
423
+ [Playground](https://typescript-play.js.org/?target=6#code/GYVwdgxgLglg9mABAZwBYmMANgUwBQxgAOIUAXIgIZgCeA2gLoCUFAbnDACaIDeAUIkQB6IYgCypSlBxUATrMo1ECsJzgBbLEoipqAc0J7EMKMgDkiHLnU4wp46pwAPHMgB0fAL58+oSLARECEosLAA5ABUYG2QAHgAxJGdpVWREPDdMylk9ZApqemZEAF4APipacrw-CApEgBogkKwAYThwckQwEHUAIxxZJl4BYVEImiIZKF0oZRwiWVdbeygJmThgOYgcGFYcbhqApCJsyhtpWXcR1cnEePBoeDAABVPzgbTixFeFd8uEsClADcIxGiygIFkSEOT3SmTc2VydQeRx+ZxwF2QQ34gkEwDgsnSuFmMBKiAADEDjIhYk1Qm0OlSYABqZnYka4xA1DJZHJYkGc7yCbyeRA+CAIZCzNAYbA4CIAdxg2zJwVCkWirjwMswuEaACYmCCgA)
424
+
425
+ ```ts
426
+ function shuffle(input: any[]): void {
427
+ // Mutate array randomly changing its' elements indexes.
428
+ }
429
+
430
+ function callNTimes<Fn extends (...args: any[]) => any> (func: Fn, callCount: number) {
431
+ // Type that represents the type of the received function parameters.
432
+ type FunctionParameters = Parameters<Fn>;
433
+
434
+ return function (...args: FunctionParameters) {
435
+ for (let i = 0; i < callCount; i++) {
436
+ func(...args);
437
+ }
438
+ }
439
+ }
440
+
441
+ const shuffleTwice = callNTimes(shuffle, 2);
442
+ ```
443
+ </details>
444
+
104
445
  - [`ConstructorParameters<T>`](https://github.com/Microsoft/TypeScript/blob/2961bc3fc0ea1117d4e53bc8e97fa76119bc33e3/src/lib/es5.d.ts#L1456-L1459) - Obtain the parameters of a constructor function type in a tuple.
446
+ <details>
447
+ <summary>
448
+ Example
449
+ </summary>
450
+
451
+ [Playground](https://typescript-play.js.org/?target=6#code/MYGwhgzhAECCBOAXAlqApgWQPYBM0mgG8AoaaFRENALmgkXmQDsBzAblOmCycTV4D8teo1YdO3JiICuwRFngAKClWENmLAJRFOZRAAtkEAHQq00ALzlklNBzIBfYk+KhIMAJJTEYJsDQAwmDA+mgAPAAq0GgAHnxMODCKTGgA7tCKxllg8CwQtL4AngDaALraFgB80EWa1SRkAA6MAG5gfNAB4FABPDJyCrQR9tDNyG0dwMGhtBhgjWEiGgA00F70vv4RhY3hEZXVVinpc42KmuJkkv3y8Bly8EPaDWTkhiZd7r3e8LK3llwGCMXGQWGhEOsfH5zJlsrl8p0+gw-goAAo5MAAW3BaHgEEilU0tEhmzQ212BJ0ry4SOg+kg+gBBiMximIGA0nAfAQLGk2N4EAAEgzYcYcnkLsRdDTvNEYkYUKwSdCme9WdM0MYwYhFPSIPpJdTkAAzDKxBUaZX+aAAQgsVmkCTQxuYaBw2ng4Ok8CYcotSu8pMur09iG9vuObxZnx6SN+AyUWTF8MN0CcZE4Ywm5jZHK5aB5fP4iCFIqT4oRRTKRLo6lYVNeAHpG50wOzOe1zHr9NLQ+HoABybsD4HOKXXRA1JCoKhBELmI5pNaB6Fz0KKBAodDYPAgSUTmqYsAALx4m5nC6nW9nGq14KtaEUA9gR9PvuNCjQ9BgACNvcwNBtAcLiAA)
452
+
453
+ ```ts
454
+ class ArticleModel {
455
+ title: string;
456
+ content?: string;
457
+
458
+ constructor(title: string) {
459
+ this.title = title;
460
+ }
461
+ }
462
+
463
+ class InstanceCache<T extends (new (...args: any[]) => any)> {
464
+ private ClassConstructor: T;
465
+ private cache: Map<string, InstanceType<T>> = new Map();
466
+
467
+ constructor (ctr: T) {
468
+ this.ClassConstructor = ctr;
469
+ }
470
+
471
+ getInstance (...args: ConstructorParameters<T>): InstanceType<T> {
472
+ const hash = this.calculateArgumentsHash(...args);
473
+
474
+ const existingInstance = this.cache.get(hash);
475
+ if (existingInstance !== undefined) {
476
+ return existingInstance;
477
+ }
478
+
479
+ return new this.ClassConstructor(...args);
480
+ }
481
+
482
+ private calculateArgumentsHash(...args: any[]): string {
483
+ // Calculate hash.
484
+ return 'hash';
485
+ }
486
+ }
487
+
488
+ const articleCache = new InstanceCache(ArticleModel);
489
+ const amazonArticle = articleCache.getInstance('Amazon forests burining!');
490
+ ```
491
+ </details>
492
+
105
493
  - [`ReturnType<T>`](https://github.com/Microsoft/TypeScript/blob/2961bc3fc0ea1117d4e53bc8e97fa76119bc33e3/src/lib/es5.d.ts#L1461-L1464) – Obtain the return type of a function type.
494
+ <details>
495
+ <summary>
496
+ Example
497
+ </summary>
498
+
499
+ [Playground](https://typescript-play.js.org/?target=6#code/MYGwhgzhAECSAmICmBlJAnAbgS2E6A3gFDTTwD2AcuQC4AW2AdgOYAUAlAFzSbnbyEAvkWFFQkGJSQB3GMVI1sNZNwg10TZgG4S0YOUY0kh1es07d+xmvQBXYDXLpWi5UlMaWAGj0GjJ6BtNdkJdBQYIADpXZGgAXmgYpB1ScOwoq38aeN9DYxoU6GFRKzVoJjUwRjwAYXJbPPRuAFkwAAcAHgAxBodsAx9GWwBbACMMAD4cxhloVraOCyYjdAAzMDxoOut1e0d0UNIZ6WhWSPOwdGYIbiqATwBtAF0uaHudUQB6ACpv6ABpJBINqJdAbADW0Do5BOw3u5R2VTwMHIq2gAANtjZ0bkbHsnFCwJh8ONjHp0EgwEZ4JFoN9PkRVr1FAZoMwkDRYIjqkgOrosepoEgAB7+eAwAV2BxOLy6ACCVxgIrFEoMeOl6AACpcwMMORgIB1JRMiBNWKVdhruJKfOdIpdrtwFddXlzKjyACp3Nq842HaDIbL6BrZBIVGhIpB1EMYSLsmjmtWW-YhAA+qegAAYLKQLQj3ZsEsdccmnGcLor2Dn8xGedHGpEIBzEzspfsfMHDNAANTQACMVaIljV5GQkRA5DYmIpVKQAgAJARO9le33BDXIyi0YuLW2nJFGLqkOvxFB0YPdBSaLZ0IwNzyPkO8-xkGgsLh8Al427a3hWAhXwwHA8EHT5PmgAB1bAQBAANJ24adKWpft72RaBUTgRBUCAj89HAM8xCTaBjggABRQx0DuHJv25P9dCkWRZVIAAiBjoFImpmjlFBgA0NpsjadByDacgIDAEAIAAQmYpjoGYgAZSBsmGPw6DtZiiFA8CoJguDmAQmoZ2QvtUKQLdoAYmBTwgdEiCAA)
500
+
501
+ ```ts
502
+ /** Provides every element of the iterable `iter` into the `callback` function and stores the results in an array. */
503
+ function mapIter<
504
+ Elem,
505
+ Func extends (elem: Elem) => any,
506
+ Ret extends ReturnType<Func>
507
+ >(iter: Iterable<Elem>, callback: Func): Ret[] {
508
+ const mapped: Ret[] = [];
509
+
510
+ for (const elem of iter) {
511
+ mapped.push(callback(elem));
512
+ }
513
+
514
+ return mapped;
515
+ }
516
+
517
+ const setObject: Set<string> = new Set();
518
+ const mapObject: Map<number, string> = new Map();
519
+
520
+ mapIter(setObject, (value: string) => value.indexOf('Foo')); // number[]
521
+
522
+ mapIter(mapObject, ([key, value]: [number, string]) => {
523
+ return key % 2 === 0 ? value : 'Odd';
524
+ }); // string[]
525
+ ```
526
+ </details>
527
+
106
528
  - [`InstanceType<T>`](https://github.com/Microsoft/TypeScript/blob/2961bc3fc0ea1117d4e53bc8e97fa76119bc33e3/src/lib/es5.d.ts#L1466-L1469) – Obtain the instance type of a constructor function type.
529
+ <details>
530
+ <summary>
531
+ Example
532
+ </summary>
533
+
534
+ [Playground](https://typescript-play.js.org/?target=6#code/MYGwhgzhAECSAmICmBlJAnAbgS2E6A3gFDTTwD2AcuQC4AW2AdgOYAUAlAFzSbnbyEAvkWFFQkGJSQB3GMVI1sNZNwg10TZgG4S0YOUY0kh1es07d+xmvQBXYDXLpWi5UlMaWAGj0GjJ6BtNdkJdBQYIADpXZGgAXmgYpB1ScOwoq38aeN9DYxoU6GFRKzVoJjUwRjwAYXJbPPRuAFkwAAcAHgAxBodsAx9GWwBbACMMAD4cxhloVraOCyYjdAAzMDxoOut1e0d0UNIZ6WhWSPOwdGYIbiqATwBtAF0uaHudUQB6ACpv6ABpJBINqJdAbADW0Do5BOw3u5R2VTwMHIq2gAANtjZ0bkbHsnFCwJh8ONjHp0EgwEZ4JFoN9PkRVr1FAZoMwkDRYIjqkgOrosepoEgAB7+eAwAV2BxOLy6ACCVxgIrFEoMeOl6AACpcwMMORgIB1JRMiBNWKVdhruJKfOdIpdrtwFddXlzKjyACp3Nq842HaDIbL6BrZBIVGhIpB1EMYSLsmjmtWW-YhAA+qegAAYLKQLQj3ZsEsdccmnGcLor2Dn8xGedHGpEIBzEzspfsfMHDNAANTQACMVaIljV5GQkRA5DYmIpVKQAgAJARO9le33BDXIyi0YuLW2nJFGLqkOvxFB0YPdBSaLZ0IwNzyPkO8-xkGgsLh8Al427a3hWAhXwwHA8EHT5PmgAB1bAQBAANJ24adKWpft72RaBUTgRBUCAj89HAM8xCTaBjggABRQx0DuHJv25P9dCkWRZVIAAiBjoFImpmjlFBgA0NpsjadByDacgIDAEAIAAQmYpjoGYgAZSBsmGPw6DtZiiFA8CoJguDmAQmoZ2QvtUKQLdoAYmBTwgdEiCAA)
535
+
536
+ ```ts
537
+ class IdleService {
538
+ doNothing (): void {}
539
+ }
540
+
541
+ class News {
542
+ title: string;
543
+ content: string;
544
+
545
+ constructor(title: string, content: string) {
546
+ this.title = title;
547
+ this.content = content;
548
+ }
549
+ }
550
+
551
+ const instanceCounter: Map<Function, number> = new Map();
552
+
553
+ interface Constructor {
554
+ new(...args: any[]): any;
555
+ }
556
+
557
+ // Keep track how many instances of `Constr` constructor have been created.
558
+ function getInstance<
559
+ Constr extends Constructor,
560
+ Args extends ConstructorParameters<Constr>
561
+ >(constructor: Constr, ...args: Args): InstanceType<Constr> {
562
+ let count = instanceCounter.get(constructor) || 0;
563
+
564
+ const instance = new constructor(...args);
565
+
566
+ instanceCounter.set(constructor, count + 1);
567
+
568
+ console.log(`Created ${count + 1} instances of ${Constr.name} class`);
569
+
570
+ return instance;
571
+ }
572
+
573
+
574
+ const idleService = getInstance(IdleService);
575
+ // Will log: `Created 1 instances of IdleService class`
576
+ const newsEntry = getInstance(News, 'New ECMAScript proposals!', 'Last month...');
577
+ // Will log: `Created 1 instances of News class`
578
+ ```
579
+ </details>
580
+
581
+ - [`Omit<T, K>`](https://github.com/microsoft/TypeScript/blob/71af02f7459dc812e85ac31365bfe23daf14b4e4/src/lib/es5.d.ts#L1446) – Constructs a type by picking all properties from T and then removing K.
582
+ <details>
583
+ <summary>
584
+ Example
585
+ </summary>
586
+
587
+ [Playground](https://typescript-play.js.org/?target=6#code/JYOwLgpgTgZghgYwgAgIImAWzgG2QbwChlks4BzCAVShwC5kBnMKUcgbmKYAcIFgIjBs1YgOXMpSFMWbANoBdTiW5woFddwAW0kfKWEAvoUIB6U8gDCUCHEiNkICAHdkYAJ69kz4GC3JcPG4oAHteKDABBxCYNAxsPFBIWEQUCAAPJG4wZABySUFcgJAAEzMLXNV1ck0dIuCw6EjBADpy5AB1FAQ4EGQAV0YUP2AHDy8wEOQbUugmBLwtEIA3OcmQnEjuZBgQqE7gAGtgZAhwKHdkHFGwNvGUdDIcAGUliIBJEF3kAF5kAHlML4ADyPBIAGjyBUYRQAPnkqho4NoYQA+TiEGD9EAISIhPozErQMG4AASK2gn2+AApek9pCSXm8wFSQooAJQMUkAFQAsgAZACiOAgmDOOSIJAQ+OYyGl4DgoDmf2QJRCCH6YvALQQNjsEGFovF1NyJWAy1y7OUyHMyE+yRAuFImG4Iq1YDswHxbRINjA-SgfXlHqVUE4xiAA)
588
+
589
+ ```ts
590
+ interface Animal {
591
+ imageUrl: string;
592
+ species: string;
593
+ images: string[];
594
+ paragraphs: string[];
595
+ }
596
+
597
+ // Creates new type with all properties of the `Animal` interface
598
+ // except 'images' and 'paragraphs' properties. We can use this
599
+ // type to render small hover tooltip for a wiki entry list.
600
+ type AnimalShortInfo = Omit<Animal, 'images' | 'paragraphs'>;
601
+
602
+ function renderAnimalHoverInfo (animals: AnimalShortInfo[]): HTMLElement {
603
+ const container = document.createElement('div');
604
+ // Internal implementation.
605
+ return container;
606
+ }
607
+ ```
608
+ </details>
107
609
 
108
610
  You can find some examples in the [TypeScript docs](https://www.typescriptlang.org/docs/handbook/advanced-types.html#predefined-conditional-types).
109
611
 
110
-
111
612
  ## Maintainers
112
613
 
113
614
  - [Sindre Sorhus](https://github.com/sindresorhus)
114
615
  - [Jarek Radosz](https://github.com/CvX)
115
616
  - [Dimitri Benin](https://github.com/BendingBender)
116
617
 
117
-
118
618
  ## License
119
619
 
120
620
  (MIT OR CC0-1.0)
621
+
622
+ ---
623
+
624
+ <div align="center">
625
+ <b>
626
+ <a href="https://tidelift.com/subscription/pkg/npm-type-fest?utm_source=npm-type-fest&utm_medium=referral&utm_campaign=readme">Get professional support for this package with a Tidelift subscription</a>
627
+ </b>
628
+ <br>
629
+ <sub>
630
+ Tidelift helps make open source sustainable for maintainers while giving companies<br>assurances about security, maintenance, and licensing for their dependencies.
631
+ </sub>
632
+ </div>
@@ -2,7 +2,7 @@
2
2
  type Without<FirstType, SecondType> = {[KeyType in Exclude<keyof FirstType, keyof SecondType>]?: never};
3
3
 
4
4
  /**
5
- Create a type that has mutually exclusive properties.
5
+ Create a type that has mutually exclusive keys.
6
6
 
7
7
  This type was inspired by [this comment](https://github.com/Microsoft/TypeScript/issues/14094#issuecomment-373782604).
8
8
 
@@ -1,5 +1,5 @@
1
1
  /**
2
- Convert an object with `readonly` properties into a mutable object. Inverse of `Readonly<T>`.
2
+ Convert an object with `readonly` keys into a mutable object. Inverse of `Readonly<T>`.
3
3
 
4
4
  This can be used to [store and mutate options within a class](https://github.com/sindresorhus/pageres/blob/4a5d05fca19a5fbd2f53842cbf3eb7b1b63bddd2/source/index.ts#L72), [edit `readonly` objects within tests](https://stackoverflow.com/questions/50703834), and [construct a `readonly` object within a function](https://github.com/Microsoft/TypeScript/issues/24509).
5
5
 
@@ -17,6 +17,6 @@ mutableFoo.a = 3;
17
17
  ```
18
18
  */
19
19
  export type Mutable<ObjectType> = {
20
- // For each `Key` in the keys of `ObjectType`, make a mapped type by removing the `readonly` modifier from the property.
20
+ // For each `Key` in the keys of `ObjectType`, make a mapped type by removing the `readonly` modifier from the key.
21
21
  -readonly [KeyType in keyof ObjectType]: ObjectType[KeyType];
22
22
  };