Skip to content

Commit 2cf4a41

Browse files
rekmarksmcmire
andauthored
docs: Add section on type-only dependencies (#156)
Adds a section explaining when you should list a type-only dependency as a dev vs. prod dependency. Also opportunistically fixes header hierarchy in TypeScript docs. Co-authored-by: Elliot Winkler <[email protected]>
1 parent 2612368 commit 2cf4a41

File tree

1 file changed

+15
-8
lines changed

1 file changed

+15
-8
lines changed

docs/typescript.md

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -881,9 +881,16 @@ export class ComposableController<
881881
const controllerMessenger = ControllerMessenger<any, any>;
882882
```
883883
884+
### Type-Only Dependencies
885+
886+
If package `a` imports only types from `b`, should `b` be a dev or production dependency of `a`?
887+
This depends on whether types from `b` are imported in the published `.d.ts` files of `a`.
888+
This occurs if e.g. `a` exports a function that uses a type from `b` in its signature.
889+
See the [TypeScript handbook](https://www.typescriptlang.org/docs/handbook/declaration-files/publishing.html#dependencies) on this topic for more details.
890+
884891
## Generic Types
885892
886-
#### Constrain generic types if necessary
893+
### Constrain generic types if necessary
887894
888895
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)
889896
@@ -897,7 +904,7 @@ function createExampleMiddleware<
897904
>(exampleParam);
898905
```
899906
900-
#### Use `Omit` to reduce requirements
907+
### Use `Omit` to reduce requirements
901908
902909
`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:
903910
@@ -936,7 +943,7 @@ const cartPayload: singleItemPayload[] = [];
936943
937944
## Interfaces
938945
939-
#### Always prefer type aliases over the `interface` keyword
946+
### Always prefer type aliases over the `interface` keyword
940947
941948
We enforce consistent and exclusive usage of type aliases over the `interface` keyword to declare types for several reasons:
942949
@@ -946,7 +953,7 @@ We enforce consistent and exclusive usage of type aliases over the `interface` k
946953
- 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>`).
947954
- Type aliases can be freely merged using the intersection (`&`) operator, like interfaces which can implement multiple inheritance.
948955
949-
#### `implements` keyword
956+
### `implements` keyword
950957
951958
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.
952959
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.
@@ -974,7 +981,7 @@ The concept of the interface as discussed in this section is not to be confused
974981
975982
TypeScript offers several tools for crafting clear data definitions, with enumerations and unions standing as popular choices.
976983
977-
#### Consider using enums over union types for situations with a fixed set of known values.
984+
### Consider using enums over union types for situations with a fixed set of known values.
978985
979986
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.
980987
@@ -994,7 +1001,7 @@ enum AccountType {
9941001
}
9951002
```
9961003
997-
#### Don't use numeric enums
1004+
### Don't use numeric enums
9981005
9991006
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.
10001007
🚫
@@ -1025,7 +1032,7 @@ const directions = Object.values(Direction); // ["Up", "Down", "Left", "Right"]
10251032
10261033
## Functions
10271034
1028-
#### For functions and methods, provide explicit return types
1035+
### For functions and methods, provide explicit return types
10291036
10301037
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.
10311038
@@ -1065,7 +1072,7 @@ async function removeAccount(address: Hex): Promise<KeyringControllerState> {
10651072
}
10661073
```
10671074
1068-
#### For selector functions, define the input state argument with the narrowest type that preserves functionality
1075+
### For selector functions, define the input state argument with the narrowest type that preserves functionality
10691076
10701077
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.
10711078

0 commit comments

Comments
 (0)