You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/typescript.md
+97Lines changed: 97 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -39,3 +39,100 @@ async function removeAccount(address: Hex): Promise<KeyringControllerState> {
39
39
returnthis.fullUpdate();
40
40
}
41
41
```
42
+
43
+
## Overriding Types
44
+
45
+
- Order of preference: `infer` > `:` > `as` > `any`
46
+
- Provide explanation via comment when explicitly casting types or overriding related eslint rules (e.g. forbid `any`, forbid `non-null assertions`)
47
+
48
+
### 1. Type Inference
49
+
50
+
- Prefer type inference: Inferences are responsive to changes in code, while assertions rely on brittle hard-coding. While TypeScript will throw type errors against some unsafe or structurally unsound type assertion scenarios, it will generally accept the user-supplied type without type-checking. This can cause silent failures where errors are suppressed.
51
+
52
+
- Generic Parameters
53
+
-`Object.entries`
54
+
-`Array.prototype.reduce`
55
+
- Type Narrowing
56
+
- In some cases, type assertions can be replaced with type narrowing with type guards and null checks.
57
+
58
+
### 2. Type Annotations (`:`)
59
+
60
+
- If a type constraint needs to be imposed, prefer the `satisfies` keyword (for TypeScript v4.9+), since it allows type inference to a more narrow type.
61
+
-`:` type declarations also enable type constraints to be imposed, but don't allow narrowing by inference.
62
+
63
+
### 3. Type Assertions (`as`, `!`)
64
+
65
+
-`as` assertions intended to exclude an empty/nullable type (e.g. `| undefined`) can be replaced with a nullish coalescing operator providing an acceptable fallback empty value that doesn't pollute the variable's type signature.
66
+
67
+
```ts
68
+
arr: string[] |undefined
69
+
(arrasstring[]) // 🚫
70
+
(arr?? []) // ✅
71
+
72
+
s: string|undefined
73
+
(sasstring) // 🚫
74
+
(s??'') // ✅
75
+
```
76
+
77
+
- Acceptable usages of `as`
78
+
- To prevent or fix `any` usage:
79
+
- At least we get working intellisense, autocomplete.
80
+
- We also get an indication of the expected type as intended by the author.
81
+
- To define user-defined type guards: https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates
82
+
- To type inputs/outputs that are defined at runtime, provided that schema validation is performed with type guards and unit tests.
83
+
- e.g. The output of `JSON.parse()` or `await response.json()` for a known JSON input.
84
+
- e.g. The type of a JSON file.
85
+
- In tests, for mocking or to exclude irrelevant but required properties from an input object.
86
+
- Recommended: Provide accurate typing wherever possible.
87
+
88
+
- Acceptable usages of `!`
89
+
- If type narrowing is not inferring the correct type.
90
+
- If the variable is otherwise guaranteed to be non-nullable.
91
+
- Preferrably, leave a comment explaining why.
92
+
93
+
### 4. Disable Type Checking (`any`)
94
+
95
+
-`any` doesn't actually represent the widest type. It's a compiler setting to disable type checking for the value and/or type to which it's assigned.
96
+
97
+
- If `any` is used, and errors are introduced (or altered) by future changes to the code,
98
+
- The new or changed warnings will be suppressed, and the code will **fail silently**.
99
+
100
+
-`any` infects all surrounding and downstream code.
101
+
- For instance, if you have a function that is declared to return any which actually returns an object, all properties of that object will be any.
102
+
103
+
-`unknown` is the universal supertype i.e. the widest possible type.
104
+
- When typing the assignee, `any` and `unknown` are interchangeable (every type is assignable to both).
105
+
- When typing the assigned, `unknown` can't replace `any`, as `unknown` is only assignable to `unknown`.
106
+
- If replacing `any` with `unknown` doesn't work, the typing likely has underlying issues that _shouldn't be silenced_.
107
+
108
+
- Function supertype (assignable to any function):
109
+
110
+
```ts
111
+
(...args:any[]) =>any// 🚫
112
+
(...args:never[]) =>unknown// ✅
113
+
```
114
+
115
+
#### Acceptable use cases
116
+
117
+
- Assigning new properties to an object or class at runtime:
- In general, using `any` in this context is not harmful in the same way that it is in other contexts, as the `any` types are not directly assigned to any specific variable, and only function as constraints.
130
+
- That said, narrower constraints provide better type safety and intellisense.
131
+
132
+
- Catching errors:
133
+
-`catch` only accepts `any` and `unknown` as the error type.
134
+
- Recommended: Use `unknown` with type guards like `isJsonRpcError`.
135
+
- Avoid typing an error object with `any` if the object is used elsewhere instead of just being thrown.
136
+
137
+
- In tests, for mocking or to intentionally break features.
138
+
- Recommended: Provide accurate typing wherever possible.
0 commit comments