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 +5 -0
- package/package.json +8 -6
- package/readme.md +523 -11
- package/source/merge-exclusive.d.ts +1 -1
- package/source/mutable.d.ts +2 -2
- package/source/opaque.d.ts +30 -5
- package/source/package-json.d.ts +52 -5
- package/source/partial-deep.d.ts +72 -0
- package/source/readonly-deep.d.ts +2 -2
- package/source/require-at-least-one.d.ts +2 -2
- package/source/require-exactly-one.d.ts +36 -0
- package/source/set-optional.d.ts +32 -0
- package/source/set-required.d.ts +32 -0
- package/source/tsconfig-json.d.ts +872 -0
package/source/opaque.d.ts
CHANGED
|
@@ -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__:
|
|
65
|
+
export type Opaque<Type, Token = unknown> = Type & {readonly __opaque__: Token};
|
package/source/package-json.d.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
|
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 [
|
|
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
|
|
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
|
|
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;
|