-
Notifications
You must be signed in to change notification settings - Fork 1
/
types.ts
76 lines (64 loc) · 2.54 KB
/
types.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
import type { AttributeValue } from '@aws-sdk/client-dynamodb';
// Common
export type AttributeValues = Record<string, AttributeValue>;
export type AttributeNames = Record<string, string>;
export type GenericObject = Record<string, unknown>;
// Flatten entity
export type FlattenObject<TValue> = CollapseEntries<CreateObjectEntries<TValue, TValue>>;
type Entry = { key: string; value: unknown };
type EmptyEntry<TValue> = { key: ''; value: TValue };
type ExcludedTypes = Date | Set<unknown> | Map<unknown, unknown>;
type ArrayEncoder = `[${bigint}]`;
type EscapeArrayKey<TKey extends string> = TKey extends `${infer TKeyBefore}.${ArrayEncoder}${infer TKeyAfter}`
? EscapeArrayKey<`${TKeyBefore}${ArrayEncoder}${TKeyAfter}`>
: TKey;
// Transforms entries to one flattened type
type CollapseEntries<TEntry extends Entry> = {
[E in TEntry as EscapeArrayKey<E['key']>]: E['value'];
};
// Transforms array type to object
type CreateArrayEntry<TValue, TValueInitial> = OmitItself<
TValue extends unknown[] ? { [k: ArrayEncoder]: TValue[number] } : TValue,
TValueInitial
>;
// Omit the type that references itself
type OmitItself<TValue, TValueInitial> = TValue extends TValueInitial
? EmptyEntry<TValue>
: OmitExcludedTypes<TValue, TValueInitial>;
// Omit the type that is listed in ExcludedTypes union
type OmitExcludedTypes<TValue, TValueInitial> = TValue extends ExcludedTypes
? EmptyEntry<TValue>
: CreateObjectEntries<TValue, TValueInitial>;
type CreateObjectEntries<TValue, TValueInitial> = TValue extends object
? {
// Checks that Key is of type string
[TKey in keyof TValue]-?: TKey extends string
? // Nested key can be an object, run recursively to the bottom
CreateArrayEntry<TValue[TKey], TValueInitial> extends infer TNestedValue
? TNestedValue extends Entry
? TNestedValue['key'] extends ''
? {
key: TKey;
value: TNestedValue['value'];
}
:
| {
key: `${TKey}.${TNestedValue['key']}`;
value: TNestedValue['value'];
}
| {
key: TKey;
value: TValue[TKey];
}
: never
: never
: never;
}[keyof TValue] // Builds entry for each key
: EmptyEntry<TValue>;
// Narrow utility
type Narrowable = string | number | bigint | boolean;
export type Narrow<T> =
| (T extends Narrowable ? T : never)
| {
[K in keyof T]: Narrow<T[K]>;
};