UNPKG

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