forked from sindresorhus/type-fest
-
Notifications
You must be signed in to change notification settings - Fork 0
/
pick-index-signature.d.ts
102 lines (86 loc) · 2.67 KB
/
pick-index-signature.d.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
/**
Pick only index signatures from the given object type, leaving out all explicitly defined properties.
This is the counterpart of `OmitIndexSignature`.
When you use a type that will iterate through an object that has indexed keys and explicitly defined keys you end up with a type where only the indexed keys are kept. This is because `keyof` of an indexed type always returns `string | number | symbol`, because every key is possible in that object. With this type, you can save the indexed keys and reinject them later, like in the second example below.
@example
```
import type {PickIndexSignature} from 'type-fest';
declare const symbolKey: unique symbol;
type Example = {
// These index signatures will remain.
[x: string]: unknown;
[x: number]: unknown;
[x: symbol]: unknown;
[x: `head-${string}`]: string;
[x: `${string}-tail`]: string;
[x: `head-${string}-tail`]: string;
[x: `${bigint}`]: string;
[x: `embedded-${number}`]: string;
// These explicitly defined keys will be removed.
['snake-case-key']: string;
[symbolKey]: string;
foo: 'bar';
qux?: 'baz';
};
type ExampleIndexSignature = PickIndexSignature<Example>;
// {
// [x: string]: unknown;
// [x: number]: unknown;
// [x: symbol]: unknown;
// [x: `head-${string}`]: string;
// [x: `${string}-tail`]: string;
// [x: `head-${string}-tail`]: string;
// [x: `${bigint}`]: string;
// [x: `embedded-${number}`]: string;
// }
```
@example
```
import type {OmitIndexSignature, PickIndexSignature, Simplify} from 'type-fest';
type Foo = {
[x: string]: string;
foo: string;
bar: number;
};
// Imagine that you want a new type `Bar` that comes from `Foo`.
// => {
// [x: string]: string;
// bar: number;
// };
type Bar = Omit<Foo, 'foo'>;
// This is not working because `Omit` returns only indexed keys.
// => {
// [x: string]: string;
// [x: number]: string;
// }
// One solution is to save the indexed signatures to new type.
type FooIndexSignature = PickIndexSignature<Foo>;
// => {
// [x: string]: string;
// }
// Get a new type without index signatures.
type FooWithoutIndexSignature = OmitIndexSignature<Foo>;
// => {
// foo: string;
// bar: number;
// }
// At this point we can use Omit to get our new type.
type BarWithoutIndexSignature = Omit<FooWithoutIndexSignature, 'foo'>;
// => {
// bar: number;
// }
// And finally we can merge back the indexed signatures.
type BarWithIndexSignature = Simplify<BarWithoutIndexSignature & FooIndexSignature>;
// => {
// [x: string]: string;
// bar: number;
// }
```
@see OmitIndexSignature
@category Object
*/
export type PickIndexSignature<ObjectType> = {
[KeyType in keyof ObjectType as {} extends Record<KeyType, unknown>
? KeyType
: never]: ObjectType[KeyType];
};