mirror of
https://github.com/trezor/trezor-suite.git
synced 2026-03-05 06:55:13 +01:00
92 lines
1.9 KiB
Markdown
92 lines
1.9 KiB
Markdown
# Defensive Programming
|
|
|
|
## Do not fall back to default
|
|
|
|
Whenever possible, cover all cases. If a new case is added in the future, TypeScript should force the developer to set behavior for it.
|
|
|
|
### Force explicit return types
|
|
|
|
Makes sure all cases are covered in a function.
|
|
|
|
```ts
|
|
// TS Error: Function lacks ending return statement and return type does not include 'undefined'
|
|
export const isEnabled = (status: 'a' | 'b' | 'c'): boolean => {
|
|
if (status === 'a') {
|
|
return true;
|
|
}
|
|
|
|
if (status === 'b') {
|
|
return false;
|
|
}
|
|
};
|
|
```
|
|
|
|
### Use `exhaustive` switch
|
|
|
|
Makes sure all cases are covered in a switch statement.
|
|
|
|
```ts
|
|
// TS Error: Argument of type '"c"' is not assignable to parameter of type 'never'
|
|
export const isEnabled = (status: 'a' | 'b' | 'c') => {
|
|
switch (status) {
|
|
case 'a':
|
|
return true;
|
|
case 'b':
|
|
return false;
|
|
default:
|
|
return exhaustive(status);
|
|
}
|
|
};
|
|
```
|
|
|
|
### Use type-mapping technique
|
|
|
|
Alternative to an exhaustive switch statement.
|
|
|
|
```ts
|
|
type Schema = {
|
|
a: number;
|
|
b: number;
|
|
};
|
|
|
|
// TS Error: Property 'b' is missing in type '{ a: () => string; }' but required in type '{ a: () => void; b: () => void; }'.
|
|
const result: { [K in keyof Schema]: () => void } = {
|
|
a: () => console.log('This is A'),
|
|
};
|
|
```
|
|
|
|
## Do not use exceptions
|
|
|
|
Unless failures are unpredictable, pass errors via `return` and do not `throw`. Throwing exceptions is not type-safe. There is a `Result` type that shall be used.
|
|
|
|
Bad:
|
|
|
|
```ts
|
|
try {
|
|
const result = await action();
|
|
} catch (error) {
|
|
// Possible errors cannot be typed
|
|
// ...
|
|
}
|
|
```
|
|
|
|
Good:
|
|
|
|
```ts
|
|
const result = await action();
|
|
|
|
if (result.error) {
|
|
const { type } = result.error;
|
|
|
|
switch (type) {
|
|
case 'ErrorA':
|
|
// ... do stuff
|
|
case 'ErrorB':
|
|
// ... do different stuff
|
|
|
|
default:
|
|
return exhaustive(type);
|
|
}
|
|
}
|
|
```
|