This repository has been archived by the owner on Feb 26, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 17
/
index.d.ts
95 lines (86 loc) · 2.76 KB
/
index.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
/**
* Copyright (C) 2019-present, Rimeto, LLC.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* A generic type that cannot be `undefined`.
*/
type Defined<T> = Exclude<T, undefined>;
/**
* Data accessor interface to dereference the value of the `TSOCType`.
*/
interface TSOCDataAccessor<T> {
/**
* Data accessor without a default value. If no data exists,
* `undefined` is returned.
*/
(noDefaultValue?: undefined): Defined<T> | undefined;
/**
* Data accessor with default value.
*/
(defaultValue: NonNullable<T>): NonNullable<T>;
(nullDefaultValue: T extends null ? null : never): Defined<T>; // Null case
}
/**
* `TSOCObjectWrapper` gives TypeScript visibility into the properties of
* an `TSOCType` object at compile-time.
*/
type TSOCObjectWrapper<T> = { [K in keyof T]-?: TSOCType<T[K]> };
/**
* `TSOCArrayWrapper` gives TypeScript visibility into the `TSOCType` values of an array
* without exposing Array methods (it is problematic to attempt to invoke methods during
* the course of an optional chain traversal).
*/
interface TSOCArrayWrapper<T> {
length: TSOCType<number>;
[K: number]: TSOCType<T>;
}
/**
* Data accessor interface to dereference the value of an `any` type.
* @extends TSOCDataAccessor<any>
*/
interface TSOCAny extends TSOCDataAccessor<any> {
[K: string]: TSOCAny; // Enable deep traversal of arbitrary props
}
/**
* `TSOCDataWrapper` selects between `TSOCArrayWrapper`, `TSOCObjectWrapper`, and `TSOCDataAccessor`
* to wrap Arrays, Objects and all other types respectively.
*/
type TSOCDataWrapper<T> =
0 extends (1 & T) // Is T any? (https://stackoverflow.com/questions/49927523/disallow-call-with-any/49928360#49928360)
? TSOCAny
: T extends any[] // Is T array-like?
? TSOCArrayWrapper<T[number]>
: T extends object // Is T object-like?
? TSOCObjectWrapper<T>
: TSOCDataAccessor<T>;
/**
* An object that supports optional chaining
*/
type TSOCType<T> = TSOCDataAccessor<T> & TSOCDataWrapper<NonNullable<T>>;
/**
* Optional chaining with default values. To inspect a property value in
* a tree-like structure, invoke it as a function, optionally passing a default value.
*
* @example
* // Given:
* const x = oc<T>({
* a: 'hello',
* b: { d: 'world' },
* c: [-100, 200, -300],
* });
*
* // Then:
* x.a() === 'hello'
* x.b.d() === 'world'
* x.c[0]() === -100
* x.c[100]() === undefined
* x.c[100](1234) === 1234
* x.c.map((e) => e()) === [-100, 200, -300]
* x.d.e() === undefined
* x.d.e('optional default value') === 'optional default value'
* (x as any).y.z.a.b.c.d.e.f.g.h.i.j.k() === undefined
*/
export declare function oc<T>(data?: T): TSOCType<T>;