forked from MetaMask/utils
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathmisc.test-d.ts
166 lines (123 loc) · 5.43 KB
/
misc.test-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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
import { expectAssignable, expectNotAssignable, expectType } from 'tsd';
import type { RuntimeObject } from './misc';
import { isObject, hasProperty, getKnownPropertyNames } from './misc';
//=============================================================================
// isObject
//=============================================================================
// eslint-disable-next-line @typescript-eslint/ban-types
const unknownValue = {} as unknown;
expectNotAssignable<RuntimeObject>(unknownValue);
if (isObject(unknownValue)) {
expectAssignable<RuntimeObject>(unknownValue);
}
// Does not interfere with satisfaction of static type
const constObjectType = { foo: 'foo' } as const;
if (hasProperty(constObjectType, 'foo')) {
expectAssignable<{ foo: 'foo' }>(constObjectType);
}
//=============================================================================
// hasProperty
//=============================================================================
// eslint-disable-next-line @typescript-eslint/ban-types
const unknownObject = {} as Object;
// Establish that `Object` is not accepted when a specific property is needed.
expectNotAssignable<Record<'foo', unknown>>(unknownObject);
// Establish that `RuntimeObject` is not accepted when a specific property is needed.
if (isObject(unknownObject)) {
expectNotAssignable<Record<'foo', unknown>>(unknownObject);
}
// An object is accepted after `hasProperty` is used to prove that it has the required property.
if (isObject(unknownObject) && hasProperty(unknownObject, 'foo')) {
expectAssignable<Record<'foo', unknown>>(unknownObject);
}
// An object is accepted after `hasProperty` is used to prove that it has all required properties.
if (
isObject(unknownObject) &&
hasProperty(unknownObject, 'foo') &&
hasProperty(unknownObject, 'bar')
) {
expectAssignable<Record<'foo' | 'bar', unknown>>(unknownObject);
}
// An object is not accepted after `hasProperty` has only been used to establish that some required properties exist.
if (isObject(unknownObject) && hasProperty(unknownObject, 'foo')) {
expectNotAssignable<Record<'foo' | 'bar', unknown>>(unknownObject);
}
// Does not interfere with satisfaction of non-overlapping types
const overlappingTypesExample = { foo: 'foo', baz: 'baz' };
if (hasProperty(overlappingTypesExample, 'foo')) {
expectAssignable<Record<'baz', unknown>>(overlappingTypesExample);
}
const exampleErrorWithCode = new Error('test');
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
exampleErrorWithCode.code = 999;
// Establish that trying to check for a custom property on an error results in failure
expectNotAssignable<{ code: any }>(exampleErrorWithCode);
// Using custom Error property is allowed after checking with `hasProperty`
if (hasProperty(exampleErrorWithCode, 'code')) {
expectType<unknown>(exampleErrorWithCode.code);
}
// `hasProperty` is compatible with interfaces
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
interface HasPropertyInterfaceExample {
a: number;
}
const hasPropertyInterfaceExample: HasPropertyInterfaceExample = { a: 0 };
hasProperty(hasPropertyInterfaceExample, 'a');
// `hasProperty` is compatible with classes
class HasPropertyClassExample {
a!: number;
}
const hasPropertyClassExample = new HasPropertyClassExample();
hasProperty(hasPropertyClassExample, 'a');
type HasPropertyTypeExample = {
a?: number;
};
// It keeps the original type when defined.
const hasPropertyTypeExample: HasPropertyTypeExample = {};
if (hasProperty(hasPropertyTypeExample, 'a')) {
expectType<number | undefined>(hasPropertyTypeExample.a);
}
//=============================================================================
// getKnownPropertyNames
//=============================================================================
enum GetKnownPropertyNamesEnumExample {
Foo = 'bar',
Baz = 'qux',
}
expectType<('Foo' | 'Baz')[]>(
getKnownPropertyNames(GetKnownPropertyNamesEnumExample),
);
//=============================================================================
// RuntimeObject
//=============================================================================
// Valid runtime objects:
expectAssignable<RuntimeObject>({});
expectAssignable<RuntimeObject>({ foo: 'foo' });
// eslint-disable-next-line @typescript-eslint/naming-convention
expectAssignable<RuntimeObject>({ 0: 'foo' });
expectAssignable<RuntimeObject>({ [Symbol('foo')]: 'foo' });
// Invalid runtime objects:
expectNotAssignable<RuntimeObject>(null);
expectNotAssignable<RuntimeObject>(undefined);
expectNotAssignable<RuntimeObject>('foo');
expectNotAssignable<RuntimeObject>(0);
expectNotAssignable<RuntimeObject>([]);
expectNotAssignable<RuntimeObject>(new Date());
expectNotAssignable<RuntimeObject>(() => 0);
expectNotAssignable<RuntimeObject>(new Set());
expectNotAssignable<RuntimeObject>(new Map());
expectNotAssignable<RuntimeObject>(Symbol('test'));
// The RuntimeObject type gets confused by interfaces. This interface is a valid object,
// but it's incompatible with the RuntimeObject type.
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
interface RuntimeObjectInterfaceExample {
a: number;
}
const runtimeObjectInterfaceExample: RuntimeObjectInterfaceExample = { a: 0 };
expectNotAssignable<RuntimeObject>(runtimeObjectInterfaceExample);
class RuntimeObjectClassExample {
a!: number;
}
const runtimeObjectClassExample = new RuntimeObjectClassExample();
expectNotAssignable<RuntimeObject>(runtimeObjectClassExample);