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.
@@ -13,9 +13,28 @@ There have been several discussions about adding this feature to TypeScript via
13
13
  ```
14
14
  import {Opaque} from 'type-fest';
15
15
 
16
- type AccountNumber = Opaque<number>;
17
- type AccountBalance = Opaque<number>;
16
+ type AccountNumber = Opaque<number, 'AccountNumber'>;
17
+ type AccountBalance = Opaque<number, 'AccountBalance'>;
18
18
 
19
+ // The Token parameter allows the compiler to differentiate between types, whereas "unknown" will not. For example, consider the following structures:
20
+ type ThingOne = Opaque<string>;
21
+ type ThingTwo = Opaque<string>;
22
+
23
+ // To the compiler, these types are allowed to be cast to each other as they have the same underlying type. They are both `string & { __opaque__: unknown }`.
24
+ // To avoid this behaviour, you would instead pass the "Token" parameter, like so.
25
+ type NewThingOne = Opaque<string, 'ThingOne'>;
26
+ type NewThingTwo = Opaque<string, 'ThingTwo'>;
27
+
28
+ // Now they're completely separate types, so the following will fail to compile.
29
+ function createNewThingOne (): NewThingOne {
30
+ // As you can see, casting from a string is still allowed. However, you may not cast NewThingOne to NewThingTwo, and vice versa.
31
+ return 'new thing one' as NewThingOne;
32
+ }
33
+
34
+ // This will fail to compile, as they are fundamentally different types.
35
+ const thingTwo = createNewThingOne() as NewThingTwo;
36
+
37
+ // Here's another example of opaque typing.
19
38
  function createAccountNumber(): AccountNumber {
20
39
  return 2 as AccountNumber;
21
40
  }
@@ -33,8 +52,14 @@ getMoneyForAccount(2);
33
52
  // You can use opaque values like they aren't opaque too.
34
53
  const accountNumber = createAccountNumber();
35
54
 
36
- // This will compile successfully.
37
- accountNumber + 2;
55
+ // This will not compile successfully.
56
+ const newAccountNumber = accountNumber + 2;
57
+
58
+ // As a side note, you can (and should) use recursive types for your opaque types to make them stronger and hopefully easier to type.
59
+ type Person = {
60
+ id: Opaque<number, Person>;
61
+ name: string;
62
+ };
38
63
  ```
39
64
  */
40
- export type Opaque<Type> = Type & {readonly __opaque__: unique symbol};
65
+ export type Opaque<Type, Token = unknown> = Type & {readonly __opaque__: Token};
@@ -27,6 +27,8 @@ declare namespace PackageJson {
27
27
  };
28
28
 
29
29
  export interface DirectoryLocations {
30
+ [directoryType: string]: unknown;
31
+
30
32
  /**
31
33
  Location for executable scripts. Sugar to generate entries in the `bin` property by walking the folder.
32
34
  */
@@ -56,8 +58,6 @@ declare namespace PackageJson {
56
58
  Location for test files.
57
59
  */
58
60
  test?: string;
59
-
60
- [directoryType: string]: unknown;
61
61
  }
62
62
 
63
63
  export type Scripts = {
@@ -223,9 +223,9 @@ declare namespace PackageJson {
223
223
  esnext?:
224
224
  | string
225
225
  | {
226
+ [moduleName: string]: string | undefined;
226
227
  main?: string;
227
228
  browser?: string;
228
- [moduleName: string]: string | undefined;
229
229
  };
230
230
 
231
231
  /**
@@ -236,6 +236,13 @@ declare namespace PackageJson {
236
236
  | {
237
237
  [moduleName: string]: string | false;
238
238
  };
239
+
240
+ /**
241
+ Denote which files in your project are "pure" and therefore safe for Webpack to prune if unused.
242
+
243
+ [Read more.](https://webpack.js.org/guides/tree-shaking/)
244
+ */
245
+ sideEffects?: boolean | string[];
239
246
  }
240
247
 
241
248
  export interface TypeScriptConfiguration {
@@ -368,6 +375,13 @@ export type PackageJson = {
368
375
  | {
369
376
  type: string;
370
377
  url: string;
378
+
379
+ /**
380
+ Relative path to package.json if it is placed in non-root directory (for example if it is part of a monorepo).
381
+
382
+ [Read more.](https://github.com/npm/rfcs/blob/latest/implemented/0010-monorepo-subdirectory-declaration.md)
383
+ */
384
+ directory?: string;
371
385
  };
372
386
 
373
387
  /**
@@ -402,6 +416,15 @@ export type PackageJson = {
402
416
  */
403
417
  peerDependencies?: PackageJson.Dependency;
404
418
 
419
+ /**
420
+ Indicate peer dependencies that are optional.
421
+ */
422
+ peerDependenciesMeta?: {
423
+ [packageName: string]: {
424
+ optional: true;
425
+ };
426
+ };
427
+
405
428
  /**
406
429
  Package names that are bundled when the package is published.
407
430
  */
@@ -487,11 +510,35 @@ export type PackageJson = {
487
510
  private?: boolean;
488
511
 
489
512
  /**
490
- * A set of config values that will be used at publish-time. It's especially handy to set the tag, registry or access, to ensure that a given package is not tagged with 'latest', published to the global public registry or that a scoped module is private by default.
491
- */
513
+ A set of config values that will be used at publish-time. It's especially handy to set the tag, registry or access, to ensure that a given package is not tagged with 'latest', published to the global public registry or that a scoped module is private by default.
514
+ */
492
515
  publishConfig?: {
493
516
  [config: string]: unknown;
494
517
  };
518
+
519
+ /**
520
+ Describes and notifies consumers of a package's monetary support information.
521
+
522
+ [Read more.](https://github.com/npm/rfcs/blob/latest/accepted/0017-add-funding-support.md)
523
+ */
524
+ funding?: string | {
525
+ /**
526
+ The type of funding.
527
+ */
528
+ type?: LiteralUnion<
529
+ | 'github'
530
+ | 'opencollective'
531
+ | 'patreon'
532
+ | 'individual'
533
+ | 'foundation'
534
+ | 'corporation',
535
+ string
536
+ >;
537
+ /**
538
+ The URL to the funding page.
539
+ */
540
+ url: string;
541
+ };
495
542
  } &
496
543
  PackageJson.NonStandardEntryPoints &
497
544
  PackageJson.TypeScriptConfiguration &
@@ -0,0 +1,72 @@
1
+ import {Primitive} from './basic';
2
+
3
+ /**
4
+ Create a type from another type with all keys and nested keys set to optional.
5
+
6
+ Use-cases:
7
+ - Merging a default settings/config object with another object, the second object would be a deep partial of the default object.
8
+ - Mocking and testing complex entities, where populating an entire object with its keys would be redundant in terms of the mock or test.
9
+
10
+ @example
11
+ ```
12
+ import {PartialDeep} from 'type-fest';
13
+
14
+ const settings: Settings = {
15
+ textEditor: {
16
+ fontSize: 14;
17
+ fontColor: '#000000';
18
+ fontWeight: 400;
19
+ }
20
+ autocomplete: false;
21
+ autosave: true;
22
+ };
23
+
24
+ const applySavedSettings = (savedSettings: PartialDeep<Settings>) => {
25
+ return {...settings, ...savedSettings};
26
+ }
27
+
28
+ settings = applySavedSettings({textEditor: {fontWeight: 500}});
29
+ ```
30
+ */
31
+ export type PartialDeep<T> = T extends Primitive
32
+ ? Partial<T>
33
+ : T extends Map<infer KeyType, infer ValueType>
34
+ ? PartialMapDeep<KeyType, ValueType>
35
+ : T extends Set<infer ItemType>
36
+ ? PartialSetDeep<ItemType>
37
+ : T extends ReadonlyMap<infer KeyType, infer ValueType>
38
+ ? PartialReadonlyMapDeep<KeyType, ValueType>
39
+ : T extends ReadonlySet<infer ItemType>
40
+ ? PartialReadonlySetDeep<ItemType>
41
+ : T extends ((...arguments: any[]) => unknown)
42
+ ? T | undefined
43
+ : T extends object
44
+ ? PartialObjectDeep<T>
45
+ : unknown;
46
+
47
+ /**
48
+ Same as `PartialDeep`, but accepts only `Map`s and as inputs. Internal helper for `PartialDeep`.
49
+ */
50
+ interface PartialMapDeep<KeyType, ValueType> extends Map<PartialDeep<KeyType>, PartialDeep<ValueType>> {}
51
+
52
+ /**
53
+ Same as `PartialDeep`, but accepts only `Set`s as inputs. Internal helper for `PartialDeep`.
54
+ */
55
+ interface PartialSetDeep<T> extends Set<PartialDeep<T>> {}
56
+
57
+ /**
58
+ Same as `PartialDeep`, but accepts only `ReadonlyMap`s as inputs. Internal helper for `PartialDeep`.
59
+ */
60
+ interface PartialReadonlyMapDeep<KeyType, ValueType> extends ReadonlyMap<PartialDeep<KeyType>, PartialDeep<ValueType>> {}
61
+
62
+ /**
63
+ Same as `PartialDeep`, but accepts only `ReadonlySet`s as inputs. Internal helper for `PartialDeep`.
64
+ */
65
+ interface PartialReadonlySetDeep<T> extends ReadonlySet<PartialDeep<T>> {}
66
+
67
+ /**
68
+ Same as `PartialDeep`, but accepts only `object`s as inputs. Internal helper for `PartialDeep`.
69
+ */
70
+ type PartialObjectDeep<ObjectType extends object> = {
71
+ [KeyType in keyof ObjectType]?: PartialDeep<ObjectType[KeyType]>
72
+ };
@@ -1,7 +1,7 @@
1
1
  import {Primitive} from './basic';
2
2
 
3
3
  /**
4
- Convert `object`s, `Map`s, `Set`s, and `Array`s and all of their properties/elements into immutable structures recursively.
4
+ Convert `object`s, `Map`s, `Set`s, and `Array`s and all of their keys/elements into immutable structures recursively.
5
5
 
6
6
  This is useful when a deeply nested structure needs to be exposed as completely immutable, for example, an imported JSON module or when receiving an API response that is passed around.
7
7
 
@@ -55,5 +55,5 @@ interface ReadonlySetDeep<ItemType>
55
55
  Same as `ReadonlyDeep`, but accepts only `object`s as inputs. Internal helper for `ReadonlyDeep`.
56
56
  */
57
57
  type ReadonlyObjectDeep<ObjectType extends object> = {
58
- readonly [PropertyType in keyof ObjectType]: ReadonlyDeep<ObjectType[PropertyType]>
58
+ readonly [KeyType in keyof ObjectType]: ReadonlyDeep<ObjectType[KeyType]>
59
59
  };
@@ -1,7 +1,7 @@
1
1
  import {Except} from './except';
2
2
 
3
3
  /**
4
- Create a type that requires at least one of the given properties. The remaining properties are kept as is.
4
+ Create a type that requires at least one of the given keys. The remaining keys are kept as is.
5
5
 
6
6
  @example
7
7
  ```
@@ -28,5 +28,5 @@ export type RequireAtLeastOne<ObjectType, KeysType extends keyof ObjectType = ke
28
28
  Required<Pick<ObjectType, Key>>
29
29
  )
30
30
  }[KeysType]
31
- // …then, make intersection types by adding the remaining properties to each mapped type.
31
+ // …then, make intersection types by adding the remaining keys to each mapped type.
32
32
  & Except<ObjectType, KeysType>;
@@ -0,0 +1,36 @@
1
+ // TODO: Remove this when we target TypeScript >=3.5.
2
+ // eslint-disable-next-line @typescript-eslint/generic-type-naming
3
+ type _Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
4
+
5
+ /**
6
+ Create a type that requires exactly one of the given keys and disallows more. The remaining keys are kept as is.
7
+
8
+ Use-cases:
9
+ - Creating interfaces for components that only need one of the keys to display properly.
10
+ - Declaring generic keys in a single place for a single use-case that gets narrowed down via `RequireExactlyOne`.
11
+
12
+ The caveat with `RequireExactlyOne` is that TypeScript doesn't always know at compile time every key that will exist at runtime. Therefore `RequireExactlyOne` can't do anything to prevent extra keys it doesn't know about.
13
+
14
+ @example
15
+ ```
16
+ import {RequireExactlyOne} from 'type-fest';
17
+
18
+ type Responder = {
19
+ text: () => string;
20
+ json: () => string;
21
+ secure: boolean;
22
+ };
23
+
24
+ const responder: RequireExactlyOne<Responder, 'text' | 'json'> = {
25
+ // Adding a `text` key here would cause a compile error.
26
+
27
+ json: () => '{"message": "ok"}',
28
+ secure: true
29
+ };
30
+ ```
31
+ */
32
+ export type RequireExactlyOne<ObjectType, KeysType extends keyof ObjectType = keyof ObjectType> =
33
+ {[Key in KeysType]: (
34
+ Required<Pick<ObjectType, Key>> &
35
+ Partial<Record<Exclude<KeysType, Key>, never>>
36
+ )}[KeysType] & _Omit<ObjectType, KeysType>;
@@ -0,0 +1,32 @@
1
+ /**
2
+ Create a type that makes the given keys optional. The remaining keys are kept as is. The sister of the `SetRequired` type.
3
+
4
+ Use-case: You want to define a single model where the only thing that changes is whether or not some of the keys are optional.
5
+
6
+ @example
7
+ ```
8
+ import {SetOptional} from 'type-fest';
9
+
10
+ type Foo = {
11
+ a: number;
12
+ b?: string;
13
+ c: boolean;
14
+ }
15
+
16
+ type SomeOptional = SetOptional<Foo, 'b' | 'c'>;
17
+ // type SomeOptional = {
18
+ // a: number;
19
+ // b?: string; // Was already optional and still is.
20
+ // c?: boolean; // Is now optional.
21
+ // }
22
+ ```
23
+ */
24
+ export type SetOptional<BaseType, Keys extends keyof BaseType = keyof BaseType> =
25
+ // Pick just the keys that are not optional from the base type.
26
+ Pick<BaseType, Exclude<keyof BaseType, Keys>> &
27
+ // Pick the keys that should be optional from the base type and make them optional.
28
+ Partial<Pick<BaseType, Keys>> extends
29
+ // If `InferredType` extends the previous, then for each key, use the inferred type key.
30
+ infer InferredType
31
+ ? {[KeyType in keyof InferredType]: InferredType[KeyType]}
32
+ : never;
@@ -0,0 +1,32 @@
1
+ /**
2
+ Create a type that makes the given keys required. The remaining keys are kept as is. The sister of the `SetOptional` type.
3
+
4
+ Use-case: You want to define a single model where the only thing that changes is whether or not some of the keys are required.
5
+
6
+ @example
7
+ ```
8
+ import {SetRequired} from 'type-fest';
9
+
10
+ type Foo = {
11
+ a?: number;
12
+ b: string;
13
+ c?: boolean;
14
+ }
15
+
16
+ type SomeRequired = SetRequired<Foo, 'b' | 'c'>;
17
+ // type SomeRequired = {
18
+ // a?: number;
19
+ // b: string; // Was already required and still is.
20
+ // c: boolean; // Is now required.
21
+ // }
22
+ ```
23
+ */
24
+ export type SetRequired<BaseType, Keys extends keyof BaseType = keyof BaseType> =
25
+ // Pick just the keys that are not required from the base type.
26
+ Pick<BaseType, Exclude<keyof BaseType, Keys>> &
27
+ // Pick the keys that should be required from the base type and make them required.
28
+ Required<Pick<BaseType, Keys>> extends
29
+ // If `InferredType` extends the previous, then for each key, use the inferred type key.
30
+ infer InferredType
31
+ ? {[KeyType in keyof InferredType]: InferredType[KeyType]}
32
+ : never;