type-fest 0.20.2 → 0.21.3
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/base.d.ts +1 -0
- package/package.json +6 -6
- package/readme.md +106 -4
- package/source/basic.d.ts +1 -17
- package/source/entry.d.ts +1 -1
- package/source/merge.d.ts +4 -1
- package/source/mutable.d.ts +24 -8
- package/source/set-optional.d.ts +8 -9
- package/source/set-required.d.ts +8 -9
- package/source/simplify.d.ts +4 -0
- package/source/typed-array.d.ts +15 -0
- package/source/utilities.d.ts +2 -0
- package/ts41/camel-case.d.ts +1 -9
- package/ts41/get.d.ts +131 -0
- package/ts41/index.d.ts +1 -0
- package/ts41/utilities.d.ts +8 -0
package/base.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "type-fest",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.21.3",
|
|
4
4
|
"description": "A collection of essential TypeScript types",
|
|
5
5
|
"license": "(MIT OR CC0-1.0)",
|
|
6
6
|
"repository": "sindresorhus/type-fest",
|
|
@@ -14,8 +14,7 @@
|
|
|
14
14
|
"node": ">=10"
|
|
15
15
|
},
|
|
16
16
|
"scripts": {
|
|
17
|
-
"
|
|
18
|
-
"test": "xo && tsc"
|
|
17
|
+
"test": "xo && tsd && tsc"
|
|
19
18
|
},
|
|
20
19
|
"files": [
|
|
21
20
|
"index.d.ts",
|
|
@@ -36,9 +35,10 @@
|
|
|
36
35
|
],
|
|
37
36
|
"devDependencies": {
|
|
38
37
|
"@sindresorhus/tsconfig": "~0.7.0",
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
"
|
|
38
|
+
"expect-type": "^0.11.0",
|
|
39
|
+
"tsd": "^0.14.0",
|
|
40
|
+
"typescript": "^4.1.3",
|
|
41
|
+
"xo": "^0.36.1"
|
|
42
42
|
},
|
|
43
43
|
"types": "./index.d.ts",
|
|
44
44
|
"typesVersions": {
|
package/readme.md
CHANGED
|
@@ -6,15 +6,32 @@
|
|
|
6
6
|
<br>
|
|
7
7
|
<b>A collection of essential TypeScript types</b>
|
|
8
8
|
<br>
|
|
9
|
+
<br>
|
|
10
|
+
<br>
|
|
11
|
+
<br>
|
|
12
|
+
<div align="center">
|
|
13
|
+
<p>
|
|
14
|
+
<p>
|
|
15
|
+
<sup>
|
|
16
|
+
<a href="https://github.com/sponsors/sindresorhus">Sindre Sorhus' open source work is supported by the community</a>
|
|
17
|
+
</sup>
|
|
18
|
+
</p>
|
|
19
|
+
<sup>Special thanks to:</sup>
|
|
20
|
+
<br>
|
|
21
|
+
<br>
|
|
22
|
+
<a href="https://standardresume.co/tech">
|
|
23
|
+
<img src="https://sindresorhus.com/assets/thanks/standard-resume-logo.svg" width="180"/>
|
|
24
|
+
</a>
|
|
25
|
+
</p>
|
|
26
|
+
</div>
|
|
27
|
+
<br>
|
|
9
28
|
<hr>
|
|
10
29
|
</div>
|
|
11
30
|
<br>
|
|
12
31
|
<br>
|
|
13
32
|
|
|
14
33
|
[](https://giphy.com/gifs/illustration-rainbow-unicorn-26AHG5KGFxSkUWw1i)
|
|
15
|
-
<!-- Commented out until they actually show anything
|
|
16
34
|
[](https://www.npmjs.com/package/type-fest?activeTab=dependents) [](https://www.npmjs.com/package/type-fest)
|
|
17
|
-
-->
|
|
18
35
|
|
|
19
36
|
Many of the types here should have been built-in. You can help by suggesting some of them to the [TypeScript project](https://github.com/Microsoft/TypeScript/blob/master/CONTRIBUTING.md).
|
|
20
37
|
|
|
@@ -52,7 +69,7 @@ Click the type names for complete docs.
|
|
|
52
69
|
|
|
53
70
|
- [`Primitive`](source/basic.d.ts) - Matches any [primitive value](https://developer.mozilla.org/en-US/docs/Glossary/Primitive).
|
|
54
71
|
- [`Class`](source/basic.d.ts) - Matches a [`class` constructor](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes).
|
|
55
|
-
- [`TypedArray`](source/
|
|
72
|
+
- [`TypedArray`](source/typed-array.d.ts) - Matches any [typed array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray), like `Uint8Array` or `Float64Array`.
|
|
56
73
|
- [`JsonObject`](source/basic.d.ts) - Matches a JSON object.
|
|
57
74
|
- [`JsonArray`](source/basic.d.ts) - Matches a JSON array.
|
|
58
75
|
- [`JsonValue`](source/basic.d.ts) - Matches any valid JSON value.
|
|
@@ -61,7 +78,7 @@ Click the type names for complete docs.
|
|
|
61
78
|
### Utilities
|
|
62
79
|
|
|
63
80
|
- [`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).
|
|
64
|
-
- [`Mutable`](source/mutable.d.ts) -
|
|
81
|
+
- [`Mutable`](source/mutable.d.ts) - Create a type that strips `readonly` from all or some of an object's keys. The inverse of `Readonly<T>`.
|
|
65
82
|
- [`Merge`](source/merge.d.ts) - Merge two types into a new type. Keys of the second type overrides keys of the first type.
|
|
66
83
|
- [`MergeExclusive`](source/merge-exclusive.d.ts) - Create a type that has mutually exclusive keys.
|
|
67
84
|
- [`RequireAtLeastOne`](source/require-at-least-one.d.ts) - Create a type that requires at least one of the given keys.
|
|
@@ -97,6 +114,7 @@ Click the type names for complete docs.
|
|
|
97
114
|
- [`PascalCase`](ts41/pascal-case.d.ts) – Converts a string literal to pascal-case (`FooBar`)
|
|
98
115
|
- [`SnakeCase`](ts41/snake-case.d.ts) – Convert a string literal to snake-case (`foo_bar`).
|
|
99
116
|
- [`DelimiterCase`](ts41/delimiter-case.d.ts) – Convert a string literal to a custom string delimiter casing.
|
|
117
|
+
- [`Get`](ts41/get.d.ts) - Get a deeply-nested property from an object using a key path, like [Lodash's `.get()`](https://lodash.com/docs/latest#get) function.
|
|
100
118
|
|
|
101
119
|
### Miscellaneous
|
|
102
120
|
|
|
@@ -632,6 +650,90 @@ There are many advanced types most users don't know about.
|
|
|
632
650
|
```
|
|
633
651
|
</details>
|
|
634
652
|
|
|
653
|
+
- [`Uppercase<S extends string>`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-1.html#template-literal-types) - Transforms every character in a string into uppercase.
|
|
654
|
+
<details>
|
|
655
|
+
<summary>
|
|
656
|
+
Example
|
|
657
|
+
</summary>
|
|
658
|
+
|
|
659
|
+
```ts
|
|
660
|
+
type T = Uppercase<'hello'>; // 'HELLO'
|
|
661
|
+
|
|
662
|
+
type T2 = Uppercase<'foo' | 'bar'>; // 'FOO' | 'BAR'
|
|
663
|
+
|
|
664
|
+
type T3<S extends string> = Uppercase<`aB${S}`>;
|
|
665
|
+
type T4 = T30<'xYz'>; // 'ABXYZ'
|
|
666
|
+
|
|
667
|
+
type T5 = Uppercase<string>; // string
|
|
668
|
+
type T6 = Uppercase<any>; // any
|
|
669
|
+
type T7 = Uppercase<never>; // never
|
|
670
|
+
type T8 = Uppercase<42>; // Error, type 'number' does not satisfy the constraint 'string'
|
|
671
|
+
```
|
|
672
|
+
</details>
|
|
673
|
+
|
|
674
|
+
- [`Lowercase<S extends string>`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-1.html#template-literal-types) - Transforms every character in a string into lowercase.
|
|
675
|
+
<details>
|
|
676
|
+
<summary>
|
|
677
|
+
Example
|
|
678
|
+
</summary>
|
|
679
|
+
|
|
680
|
+
```ts
|
|
681
|
+
type T = Lowercase<'HELLO'>; // 'hello'
|
|
682
|
+
|
|
683
|
+
type T2 = Lowercase<'FOO' | 'BAR'>; // 'foo' | 'bar'
|
|
684
|
+
|
|
685
|
+
type T3<S extends string> = Lowercase<`aB${S}`>;
|
|
686
|
+
type T4 = T32<'xYz'>; // 'abxyz'
|
|
687
|
+
|
|
688
|
+
type T5 = Lowercase<string>; // string
|
|
689
|
+
type T6 = Lowercase<any>; // any
|
|
690
|
+
type T7 = Lowercase<never>; // never
|
|
691
|
+
type T8 = Lowercase<42>; // Error, type 'number' does not satisfy the constraint 'string'
|
|
692
|
+
```
|
|
693
|
+
</details>
|
|
694
|
+
|
|
695
|
+
- [`Capitalize<S extends string>`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-1.html#template-literal-types) - Transforms the first character in a string into uppercase.
|
|
696
|
+
<details>
|
|
697
|
+
<summary>
|
|
698
|
+
Example
|
|
699
|
+
</summary>
|
|
700
|
+
|
|
701
|
+
```ts
|
|
702
|
+
type T = Capitalize<'hello'>; // 'Hello'
|
|
703
|
+
|
|
704
|
+
type T2 = Capitalize<'foo' | 'bar'>; // 'Foo' | 'Bar'
|
|
705
|
+
|
|
706
|
+
type T3<S extends string> = Capitalize<`aB${S}`>;
|
|
707
|
+
type T4 = T32<'xYz'>; // 'ABxYz'
|
|
708
|
+
|
|
709
|
+
type T5 = Capitalize<string>; // string
|
|
710
|
+
type T6 = Capitalize<any>; // any
|
|
711
|
+
type T7 = Capitalize<never>; // never
|
|
712
|
+
type T8 = Capitalize<42>; // Error, type 'number' does not satisfy the constraint 'string'
|
|
713
|
+
```
|
|
714
|
+
</details>
|
|
715
|
+
|
|
716
|
+
- [`Uncapitalize<S extends string>`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-1.html#template-literal-types) - Transforms the first character in a string into lowercase.
|
|
717
|
+
<details>
|
|
718
|
+
<summary>
|
|
719
|
+
Example
|
|
720
|
+
</summary>
|
|
721
|
+
|
|
722
|
+
```ts
|
|
723
|
+
type T = Uncapitalize<'Hello'>; // 'hello'
|
|
724
|
+
|
|
725
|
+
type T2 = Uncapitalize<'Foo' | 'Bar'>; // 'foo' | 'bar'
|
|
726
|
+
|
|
727
|
+
type T3<S extends string> = Uncapitalize<`AB${S}`>;
|
|
728
|
+
type T4 = T30<'xYz'>; // 'aBxYz'
|
|
729
|
+
|
|
730
|
+
type T5 = Uncapitalize<string>; // string
|
|
731
|
+
type T6 = Uncapitalize<any>; // any
|
|
732
|
+
type T7 = Uncapitalize<never>; // never
|
|
733
|
+
type T8 = Uncapitalize<42>; // Error, type 'number' does not satisfy the constraint 'string'
|
|
734
|
+
```
|
|
735
|
+
</details>
|
|
736
|
+
|
|
635
737
|
You can find some examples in the [TypeScript docs](https://www.typescriptlang.org/docs/handbook/advanced-types.html#predefined-conditional-types).
|
|
636
738
|
|
|
637
739
|
## Maintainers
|
package/source/basic.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/// <reference lib="
|
|
1
|
+
/// <reference lib="es2020.bigint"/>
|
|
2
2
|
|
|
3
3
|
// TODO: This can just be `export type Primitive = not object` when the `not` keyword is out.
|
|
4
4
|
/**
|
|
@@ -19,22 +19,6 @@ Matches a [`class` constructor](https://developer.mozilla.org/en-US/docs/Web/Jav
|
|
|
19
19
|
*/
|
|
20
20
|
export type Class<T = unknown, Arguments extends any[] = any[]> = new(...arguments_: Arguments) => T;
|
|
21
21
|
|
|
22
|
-
/**
|
|
23
|
-
Matches any [typed array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray), like `Uint8Array` or `Float64Array`.
|
|
24
|
-
*/
|
|
25
|
-
export type TypedArray =
|
|
26
|
-
| Int8Array
|
|
27
|
-
| Uint8Array
|
|
28
|
-
| Uint8ClampedArray
|
|
29
|
-
| Int16Array
|
|
30
|
-
| Uint16Array
|
|
31
|
-
| Int32Array
|
|
32
|
-
| Uint32Array
|
|
33
|
-
| Float32Array
|
|
34
|
-
| Float64Array
|
|
35
|
-
| BigInt64Array
|
|
36
|
-
| BigUint64Array;
|
|
37
|
-
|
|
38
22
|
/**
|
|
39
23
|
Matches a JSON object.
|
|
40
24
|
|
package/source/entry.d.ts
CHANGED
|
@@ -44,7 +44,7 @@ const arrayEntryNumber: Entry<typeof arrayExample> = [1, 1];
|
|
|
44
44
|
|
|
45
45
|
// Maps
|
|
46
46
|
const mapExample = new Map([['a', 1]]);
|
|
47
|
-
const mapEntry: Entry<typeof
|
|
47
|
+
const mapEntry: Entry<typeof mapExample> = ['a', 1];
|
|
48
48
|
|
|
49
49
|
// Sets
|
|
50
50
|
const setExample = new Set(['a', 1]);
|
package/source/merge.d.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import {Except} from './except';
|
|
2
|
+
import {Simplify} from './simplify';
|
|
3
|
+
|
|
4
|
+
type Merge_<FirstType, SecondType> = Except<FirstType, Extract<keyof FirstType, keyof SecondType>> & SecondType;
|
|
2
5
|
|
|
3
6
|
/**
|
|
4
7
|
Merge two types into a new type. Keys of the second type overrides keys of the first type.
|
|
@@ -19,4 +22,4 @@ type Bar = {
|
|
|
19
22
|
const ab: Merge<Foo, Bar> = {a: 1, b: 2};
|
|
20
23
|
```
|
|
21
24
|
*/
|
|
22
|
-
export type Merge<FirstType, SecondType> =
|
|
25
|
+
export type Merge<FirstType, SecondType> = Simplify<Merge_<FirstType, SecondType>>;
|
package/source/mutable.d.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
import {Except} from './except';
|
|
2
|
+
import {Simplify} from './simplify';
|
|
3
|
+
|
|
1
4
|
/**
|
|
2
|
-
|
|
5
|
+
Create a type that strips `readonly` from all or some of an object's keys. Inverse of `Readonly<T>`.
|
|
3
6
|
|
|
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),
|
|
7
|
+
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), [construct a `readonly` object within a function](https://github.com/Microsoft/TypeScript/issues/24509), or to define a single model where the only thing that changes is whether or not some of the keys are mutable.
|
|
5
8
|
|
|
6
9
|
@example
|
|
7
10
|
```
|
|
@@ -9,14 +12,27 @@ import {Mutable} from 'type-fest';
|
|
|
9
12
|
|
|
10
13
|
type Foo = {
|
|
11
14
|
readonly a: number;
|
|
12
|
-
readonly b: string;
|
|
15
|
+
readonly b: readonly string[]; // To show that only the mutability status of the properties, not their values, are affected.
|
|
16
|
+
readonly c: boolean;
|
|
13
17
|
};
|
|
14
18
|
|
|
15
|
-
const mutableFoo: Mutable<Foo> = {a: 1, b: '2'};
|
|
19
|
+
const mutableFoo: Mutable<Foo> = {a: 1, b: ['2']};
|
|
16
20
|
mutableFoo.a = 3;
|
|
21
|
+
mutableFoo.b[0] = 'new value'; // Will still fail as the value of property "b" is still a readonly type.
|
|
22
|
+
mutableFoo.b = ['something']; // Will work as the "b" property itself is no longer readonly.
|
|
23
|
+
|
|
24
|
+
type SomeMutable = Mutable<Foo, 'b' | 'c'>;
|
|
25
|
+
// type SomeMutable = {
|
|
26
|
+
// readonly a: number;
|
|
27
|
+
// b: readonly string[]; // It's now mutable. The type of the property remains unaffected.
|
|
28
|
+
// c: boolean; // It's now mutable.
|
|
29
|
+
// }
|
|
17
30
|
```
|
|
18
31
|
*/
|
|
19
|
-
export type Mutable<
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
32
|
+
export type Mutable<BaseType, Keys extends keyof BaseType = keyof BaseType> =
|
|
33
|
+
Simplify<
|
|
34
|
+
// Pick just the keys that are not mutable from the base type.
|
|
35
|
+
Except<BaseType, Keys> &
|
|
36
|
+
// Pick the keys that should be mutable from the base type and make them mutable by removing the `readonly` modifier from the key.
|
|
37
|
+
{-readonly [KeyType in keyof Pick<BaseType, Keys>]: Pick<BaseType, Keys>[KeyType]}
|
|
38
|
+
>;
|
package/source/set-optional.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {Except} from './except';
|
|
2
|
+
import {Simplify} from './simplify';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
Create a type that makes the given keys optional. The remaining keys are kept as is. The sister of the `SetRequired` type.
|
|
@@ -23,12 +24,10 @@ type SomeOptional = SetOptional<Foo, 'b' | 'c'>;
|
|
|
23
24
|
// }
|
|
24
25
|
```
|
|
25
26
|
*/
|
|
26
|
-
export type SetOptional<BaseType, Keys extends keyof BaseType
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
? {[KeyType in keyof InferredType]: InferredType[KeyType]}
|
|
34
|
-
: never;
|
|
27
|
+
export type SetOptional<BaseType, Keys extends keyof BaseType> =
|
|
28
|
+
Simplify<
|
|
29
|
+
// Pick just the keys that are readonly from the base type.
|
|
30
|
+
Except<BaseType, Keys> &
|
|
31
|
+
// Pick the keys that should be mutable from the base type and make them mutable.
|
|
32
|
+
Partial<Pick<BaseType, Keys>>
|
|
33
|
+
>;
|
package/source/set-required.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {Except} from './except';
|
|
2
|
+
import {Simplify} from './simplify';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
Create a type that makes the given keys required. The remaining keys are kept as is. The sister of the `SetOptional` type.
|
|
@@ -23,12 +24,10 @@ type SomeRequired = SetRequired<Foo, 'b' | 'c'>;
|
|
|
23
24
|
// }
|
|
24
25
|
```
|
|
25
26
|
*/
|
|
26
|
-
export type SetRequired<BaseType, Keys extends keyof BaseType
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
? {[KeyType in keyof InferredType]: InferredType[KeyType]}
|
|
34
|
-
: never;
|
|
27
|
+
export type SetRequired<BaseType, Keys extends keyof BaseType> =
|
|
28
|
+
Simplify<
|
|
29
|
+
// Pick just the keys that are optional from the base type.
|
|
30
|
+
Except<BaseType, Keys> &
|
|
31
|
+
// Pick the keys that should be required from the base type and make them required.
|
|
32
|
+
Required<Pick<BaseType, Keys>>
|
|
33
|
+
>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
Matches any [typed array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray), like `Uint8Array` or `Float64Array`.
|
|
3
|
+
*/
|
|
4
|
+
export type TypedArray =
|
|
5
|
+
| Int8Array
|
|
6
|
+
| Uint8Array
|
|
7
|
+
| Uint8ClampedArray
|
|
8
|
+
| Int16Array
|
|
9
|
+
| Uint16Array
|
|
10
|
+
| Int32Array
|
|
11
|
+
| Uint32Array
|
|
12
|
+
| Float32Array
|
|
13
|
+
| Float64Array
|
|
14
|
+
| BigInt64Array
|
|
15
|
+
| BigUint64Array;
|
package/source/utilities.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
export type UpperCaseCharacters = 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'J' | 'K' | 'L' | 'M' | 'N' | 'O' | 'P' | 'Q' | 'R' | 'S' | 'T' | 'U' | 'V' | 'W' | 'X' | 'Y' | 'Z';
|
|
2
2
|
|
|
3
3
|
export type WordSeparators = '-' | '_' | ' ';
|
|
4
|
+
|
|
5
|
+
export type StringDigit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9';
|
package/ts41/camel-case.d.ts
CHANGED
|
@@ -1,13 +1,5 @@
|
|
|
1
1
|
import {WordSeparators} from '../source/utilities';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
Recursively split a string literal into two parts on the first occurence of the given string, returning an array literal of all the separate parts.
|
|
5
|
-
*/
|
|
6
|
-
export type Split<S extends string, D extends string> =
|
|
7
|
-
string extends S ? string[] :
|
|
8
|
-
S extends '' ? [] :
|
|
9
|
-
S extends `${infer T}${D}${infer U}` ? [T, ...Split<U, D>] :
|
|
10
|
-
[S];
|
|
2
|
+
import {Split} from './utilities';
|
|
11
3
|
|
|
12
4
|
/**
|
|
13
5
|
Step by step takes the first item in an array literal, formats it and adds it to a string literal, and then recursively appends the remainder.
|
package/ts41/get.d.ts
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import {Split} from './utilities';
|
|
2
|
+
import {StringDigit} from '../source/utilities';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
Like the `Get` type but receives an array of strings as a path parameter.
|
|
6
|
+
*/
|
|
7
|
+
type GetWithPath<BaseType, Keys extends readonly string[]> =
|
|
8
|
+
Keys extends []
|
|
9
|
+
? BaseType
|
|
10
|
+
: Keys extends [infer Head, ...infer Tail]
|
|
11
|
+
? GetWithPath<PropertyOf<BaseType, Extract<Head, string>>, Extract<Tail, string[]>>
|
|
12
|
+
: never;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
Splits a dot-prop style path into a tuple comprised of the properties in the path. Handles square-bracket notation.
|
|
16
|
+
|
|
17
|
+
@example
|
|
18
|
+
```
|
|
19
|
+
ToPath<'foo.bar.baz'>
|
|
20
|
+
//=> ['foo', 'bar', 'baz']
|
|
21
|
+
|
|
22
|
+
ToPath<'foo[0].bar.baz'>
|
|
23
|
+
//=> ['foo', '0', 'bar', 'baz']
|
|
24
|
+
```
|
|
25
|
+
*/
|
|
26
|
+
type ToPath<S extends string> = Split<FixPathSquareBrackets<S>, '.'>;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
Replaces square-bracketed dot notation with dots, for example, `foo[0].bar` -> `foo.0.bar`.
|
|
30
|
+
*/
|
|
31
|
+
type FixPathSquareBrackets<Path extends string> =
|
|
32
|
+
Path extends `${infer Head}[${infer Middle}]${infer Tail}`
|
|
33
|
+
? `${Head}.${Middle}${FixPathSquareBrackets<Tail>}`
|
|
34
|
+
: Path;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
Returns true if `LongString` is made up out of `Substring` repeated 0 or more times.
|
|
38
|
+
|
|
39
|
+
@example
|
|
40
|
+
```
|
|
41
|
+
ConsistsOnlyOf<'aaa', 'a'> //=> true
|
|
42
|
+
ConsistsOnlyOf<'ababab', 'ab'> //=> true
|
|
43
|
+
ConsistsOnlyOf<'aBa', 'a'> //=> false
|
|
44
|
+
ConsistsOnlyOf<'', 'a'> //=> true
|
|
45
|
+
```
|
|
46
|
+
*/
|
|
47
|
+
type ConsistsOnlyOf<LongString extends string, Substring extends string> =
|
|
48
|
+
LongString extends ''
|
|
49
|
+
? true
|
|
50
|
+
: LongString extends `${Substring}${infer Tail}`
|
|
51
|
+
? ConsistsOnlyOf<Tail, Substring>
|
|
52
|
+
: false;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
Convert a type which may have number keys to one with string keys, making it possible to index using strings retrieved from template types.
|
|
56
|
+
|
|
57
|
+
@example
|
|
58
|
+
```
|
|
59
|
+
type WithNumbers = {foo: string; 0: boolean};
|
|
60
|
+
type WithStrings = WithStringKeys<WithNumbers>;
|
|
61
|
+
|
|
62
|
+
type WithNumbersKeys = keyof WithNumbers;
|
|
63
|
+
//=> 'foo' | 0
|
|
64
|
+
type WithStringsKeys = keyof WithStrings;
|
|
65
|
+
//=> 'foo' | '0'
|
|
66
|
+
```
|
|
67
|
+
*/
|
|
68
|
+
type WithStringKeys<BaseType extends Record<string | number, any>> = {
|
|
69
|
+
[Key in `${Extract<keyof BaseType, string | number>}`]: BaseType[Key]
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
Get a property of an object or array. Works when indexing arrays using number-literal-strings, for example, `PropertyOf<number[], '0'> = number`, and when indexing objects with number keys.
|
|
74
|
+
|
|
75
|
+
Note:
|
|
76
|
+
- Returns `unknown` if `Key` is not a property of `BaseType`, since TypeScript uses structural typing, and it cannot be guaranteed that extra properties unknown to the type system will exist at runtime.
|
|
77
|
+
- Returns `undefined` from nullish values, to match the behaviour of most deep-key libraries like `lodash`, `dot-prop`, etc.
|
|
78
|
+
*/
|
|
79
|
+
type PropertyOf<BaseType, Key extends string> =
|
|
80
|
+
BaseType extends null | undefined
|
|
81
|
+
? undefined
|
|
82
|
+
: Key extends keyof BaseType
|
|
83
|
+
? BaseType[Key]
|
|
84
|
+
: BaseType extends {
|
|
85
|
+
[n: number]: infer Item;
|
|
86
|
+
length: number; // Note: This is needed to avoid being too lax with records types using number keys like `{0: string; 1: boolean}`.
|
|
87
|
+
}
|
|
88
|
+
? (
|
|
89
|
+
ConsistsOnlyOf<Key, StringDigit> extends true
|
|
90
|
+
? Item
|
|
91
|
+
: unknown
|
|
92
|
+
)
|
|
93
|
+
: Key extends keyof WithStringKeys<BaseType>
|
|
94
|
+
? WithStringKeys<BaseType>[Key]
|
|
95
|
+
: unknown;
|
|
96
|
+
|
|
97
|
+
// This works by first splitting the path based on `.` and `[...]` characters into a tuple of string keys. Then it recursively uses the head key to get the next property of the current object, until there are no keys left. Number keys extract the item type from arrays, or are converted to strings to extract types from tuples and dictionaries with number keys.
|
|
98
|
+
/**
|
|
99
|
+
Get a deeply-nested property from an object using a key path, like Lodash's `.get()` function.
|
|
100
|
+
|
|
101
|
+
Use-case: Retrieve a property from deep inside an API response or some other complex object.
|
|
102
|
+
|
|
103
|
+
@example
|
|
104
|
+
```
|
|
105
|
+
import {Get} from 'type-fest';
|
|
106
|
+
import * as lodash from 'lodash';
|
|
107
|
+
|
|
108
|
+
const get = <BaseType, Path extends string>(object: BaseType, path: Path): Get<BaseType, Path> =>
|
|
109
|
+
lodash.get(object, path);
|
|
110
|
+
|
|
111
|
+
interface ApiResponse {
|
|
112
|
+
hits: {
|
|
113
|
+
hits: Array<{
|
|
114
|
+
_id: string
|
|
115
|
+
_source: {
|
|
116
|
+
name: Array<{
|
|
117
|
+
given: string[]
|
|
118
|
+
family: string
|
|
119
|
+
}>
|
|
120
|
+
birthDate: string
|
|
121
|
+
}
|
|
122
|
+
}>
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const getName = (apiResponse: ApiResponse) =>
|
|
127
|
+
get(apiResponse, 'hits.hits[0]._source.name');
|
|
128
|
+
//=> Array<{given: string[]; family: string}>
|
|
129
|
+
```
|
|
130
|
+
*/
|
|
131
|
+
export type Get<BaseType, Path extends string> = GetWithPath<BaseType, ToPath<Path>>;
|
package/ts41/index.d.ts
CHANGED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
Recursively split a string literal into two parts on the first occurence of the given string, returning an array literal of all the separate parts.
|
|
3
|
+
*/
|
|
4
|
+
export type Split<S extends string, D extends string> =
|
|
5
|
+
string extends S ? string[] :
|
|
6
|
+
S extends '' ? [] :
|
|
7
|
+
S extends `${infer T}${D}${infer U}` ? [T, ...Split<U, D>] :
|
|
8
|
+
[S];
|