Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 15 additions & 8 deletions docs/typescript.md
Original file line number Diff line number Diff line change
Expand Up @@ -881,9 +881,16 @@ export class ComposableController<
const controllerMessenger = ControllerMessenger<any, any>;
```

### Type-Only Dependencies

If package `a` imports only types from `b`, should `b` be a dev or production dependency of `a`?
This depends on whether types from `b` are imported in the published `.d.ts` files of `a`.
This occurs if e.g. `a` exports a function that uses a type from `b` in its signature.
See the [TypeScript handbook](https://www.typescriptlang.org/docs/handbook/declaration-files/publishing.html#dependencies) on this topic for more details.

## Generic Types

#### Constrain generic types if necessary
### Constrain generic types if necessary

It may not be enough just to have a type or a function take another type — you might have to constrain it if it's not allowed to be anything (e.g. extends Json)

Expand All @@ -897,7 +904,7 @@ function createExampleMiddleware<
>(exampleParam);
```

#### Use `Omit` to reduce requirements
### Use `Omit` to reduce requirements

`Omit<T, K>` takes two generic types: `T` representing the original object type and `K` representing the property keys you want to remove. It returns a new type that has all the properties of T except for the ones specified in K. Here are some cases to use omit:

Expand Down Expand Up @@ -936,7 +943,7 @@ const cartPayload: singleItemPayload[] = [];

## Interfaces

#### Always prefer type aliases over the `interface` keyword
### Always prefer type aliases over the `interface` keyword

We enforce consistent and exclusive usage of type aliases over the `interface` keyword to declare types for several reasons:

Expand All @@ -946,7 +953,7 @@ We enforce consistent and exclusive usage of type aliases over the `interface` k
- Unlike interfaces, type aliases extend `Record` and have an index signature of `string` by default, which makes them compatible with our Json-serializable types (most notably `Record<string, Json>`).
- Type aliases can be freely merged using the intersection (`&`) operator, like interfaces which can implement multiple inheritance.

#### `implements` keyword
### `implements` keyword

The `implements` keyword enables us to define and enforce interfaces, i.e. strict contracts consisting of expected object and class properties and abstract method signatures.
Writing an interface to establish the specifications of a class that external code can interact while without being aware of internal implementation details is encouraged as sound OOP development practice.
Expand Down Expand Up @@ -974,7 +981,7 @@ The concept of the interface as discussed in this section is not to be confused

TypeScript offers several tools for crafting clear data definitions, with enumerations and unions standing as popular choices.

#### Consider using enums over union types for situations with a fixed set of known values.
### Consider using enums over union types for situations with a fixed set of known values.

Inevitably you will want to refer to the values of a union type somewhere (perhaps as the argument to a function). You can of course just use a literal which represents a member of that union — but if you have an enum, then all of the values are special, and any time you use a value then anyone can see where that value comes from.

Expand All @@ -994,7 +1001,7 @@ enum AccountType {
}
```

#### Don't use numeric enums
### Don't use numeric enums

Numeric enums are misleading because it creates a reverse mapping from value to property name, and when using `Object.values` to access member names, it will return the numerical values instead of the member names, potentially causing unexpected behavior.
🚫
Expand Down Expand Up @@ -1025,7 +1032,7 @@ const directions = Object.values(Direction); // ["Up", "Down", "Left", "Right"]

## Functions

#### For functions and methods, provide explicit return types
### For functions and methods, provide explicit return types

Although TypeScript is capable of inferring return types, adding them explicitly makes it much easier for the reader to see the API from the code alone and prevents unexpected changes to the API from emerging.

Expand Down Expand Up @@ -1065,7 +1072,7 @@ async function removeAccount(address: Hex): Promise<KeyringControllerState> {
}
```

#### For selector functions, define the input state argument with the narrowest type that preserves functionality
### For selector functions, define the input state argument with the narrowest type that preserves functionality

A selector function that directly queries state properties should define its input state argument as a subtype of root state that only contains the required queried properties.

Expand Down
Loading