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 CHANGED
@@ -3,6 +3,7 @@
3
3
 
4
4
  // Basic
5
5
  export * from './source/basic';
6
+ export * from './source/typed-array';
6
7
 
7
8
  // Utilities
8
9
  export {Except} from './source/except';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "type-fest",
3
- "version": "0.20.2",
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
- "//test": "xo && tsd && tsc",
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
- "tsd": "^0.13.1",
40
- "typescript": "^4.1.2",
41
- "xo": "^0.35.0"
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://img.shields.io/badge/unicorn-approved-ff69b4.svg)](https://giphy.com/gifs/illustration-rainbow-unicorn-26AHG5KGFxSkUWw1i)
15
- <!-- Commented out until they actually show anything
16
34
  [![npm dependents](https://badgen.net/npm/dependents/type-fest)](https://www.npmjs.com/package/type-fest?activeTab=dependents) [![npm downloads](https://badgen.net/npm/dt/type-fest)](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/basic.d.ts) - Matches any [typed array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray), like `Uint8Array` or `Float64Array`.
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) - Convert an object with `readonly` keys into a mutable object. The inverse of `Readonly<T>`.
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="esnext"/>
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 map> = ['a', 1];
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> = Except<FirstType, Extract<keyof FirstType, keyof SecondType>> & SecondType;
25
+ export type Merge<FirstType, SecondType> = Simplify<Merge_<FirstType, SecondType>>;
@@ -1,7 +1,10 @@
1
+ import {Except} from './except';
2
+ import {Simplify} from './simplify';
3
+
1
4
  /**
2
- Convert an object with `readonly` keys into a mutable object. Inverse of `Readonly<T>`.
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), and [construct a `readonly` object within a function](https://github.com/Microsoft/TypeScript/issues/24509).
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<ObjectType> = {
20
- // For each `Key` in the keys of `ObjectType`, make a mapped type by removing the `readonly` modifier from the key.
21
- -readonly [KeyType in keyof ObjectType]: ObjectType[KeyType];
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
+ >;
@@ -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 = keyof BaseType> =
27
- // Pick just the keys that are not optional from the base type.
28
- Except<BaseType, Keys> &
29
- // Pick the keys that should be optional from the base type and make them optional.
30
- Partial<Pick<BaseType, Keys>> extends
31
- // If `InferredType` extends the previous, then for each key, use the inferred type key.
32
- infer InferredType
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
+ >;
@@ -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 = keyof BaseType> =
27
- // Pick just the keys that are not required from the base type.
28
- Except<BaseType, Keys> &
29
- // Pick the keys that should be required from the base type and make them required.
30
- Required<Pick<BaseType, Keys>> extends
31
- // If `InferredType` extends the previous, then for each key, use the inferred type key.
32
- infer InferredType
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,4 @@
1
+ /**
2
+ Flatten the type output to improve type hints shown in editors.
3
+ */
4
+ export type Simplify<T> = {[KeyType in keyof T]: T[KeyType]};
@@ -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;
@@ -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';
@@ -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
@@ -7,3 +7,4 @@ export {KebabCase} from './kebab-case';
7
7
  export {PascalCase} from './pascal-case';
8
8
  export {SnakeCase} from './snake-case';
9
9
  export {DelimiterCase} from './delimiter-case';
10
+ export {Get} from './get';
@@ -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];