Skip to content

Coding Guidelines

Lean towards kebab case for most file names. If you see an exception such as the ‘gg_native’ folder its because the react native init system doesn’t except kebab case.

Most coding conventions are applied by the Biome linter and formatter. You can find the ‘biome.json’ config file in the root of the repo.

  • Directory.github/
  • Directory.vscode/
  • Directorymono/
  • Directorynative/
  • .gitignore
  • biome.json

Functions

Explicit functions should be ‘named’, not arrow functions

// Valid
function myFunction() {
// ...
}
// Not valid
const myFunction = () => {
// ...
}

Arrow functions are great when needed in-line

myArray.map((item) => {
return item + 1;
});

Imports

When importing functions from the project (not NPM) use file extensions. This means the monorepo tools don’t need to do extra work trying a range of extensions on hundreds of files. The project is set up so you can rely on autocomplete for imports and it will add the extension for you.

WARNING!!! Don’t use the file extension on an import for files that have platform specific alternatives e.g. ‘myComponent.tsx’ because it will fail to load ‘myComponent.android.tsx’ or ‘myComponent.web.tsx’. Here you should just import ‘myComponent’ and let the bundler work out the correct file.

Imports are grouped with 3rd party npm packages first, then local files.

// Valid
import { myFunction } from './my-file.ts';
// Not valid
import { myFunction } from './my-file';

Props

Props are declared in the following style. As a type called ‘Props’, and then a destructured object with the properties. This means a bit less typing i.e. no ‘props.foo’ and also the linter can detect unused properties in the prop.

// Valid
type Props = {
readonly route: RouteProp<RootStackParamList, "Details">;
readonly navigation: NavigationProp<ReactNavigation.RootParamList>;
};
export default function StatBars({ route, navigation }: Props) {
// Not valid
type Props = {
readonly stats: ItemStats;
readonly destinyItem: DestinyItem;
};
export default function StatBars(props: Props) {
// Also not valid
function DetailsView({
route,
navigation,
}: {
readonly route: RouteProp<RootStackParamList, "Details">;
readonly navigation: NavigationProp<ReactNavigation.RootParamList>;
}) {

Exports

A common problem is the use of ‘barrel files’ which export everything from a folder. This can cause performance issues, especially in a monorepo. You need just one function from a file, but behind the scenes the whole file is being imported and parsed.

Instead, export each function directly from the file and rely on autocomplete to help you find the right file.

// Valid
export function myFunction() {
// ...
}
// Not valid
export * from './my-file';

The Biome linter enforces this rule.

TypeScript

Strict mode is enabled in the project. The hot reloading system does not care about strict mode so while editing code it’s possible to use ‘any’ while working things out. It’s also the case that many other type errors that show up during refactoring won’t break the hot reloading so long as the code is still valid typescript/javascript.

But the CI will reject any PR that doesn’t pass the strict mode check.

// Valid
const myArray: any[] = [];
// Not valid
const myArray: Array<T> = [];

Branded Types

Branded types can be used to narrow down certain types for example characterId, bucketHash, itemHash and itemInstanceId. There is a helper to create them as per https://egghead.io/blog/using-branded-types-in-typescript

As of May 2024 some minor refactoring to tidy the use of branded types might be required. But the main use case is to stop the hard to spot mistakes of using ‘itemHash’ instead of ‘itemInstanceId’ which is easily done and not helped by some questionable end point naming that is outside this apps control.

Semantic Commit Messages

See how a minor change to your commit message style can make you a better programmer.

Format: <type>(<scope>): <subject>

<scope> is optional

Example

feat: add hat wobble
^--^ ^------------^
| |
| +-> Summary in present tense.
|
+-------> Type: chore, docs, feat, fix, refactor, style, or test.

More Examples:

  • feat: (new feature for the user, not a new feature for build script)
  • fix: (bug fix for the user, not a fix to a build script)
  • docs: (changes to the documentation)
  • style: (formatting, missing semi colons, etc; no production code change)
  • refactor: (refactoring production code, eg. renaming a variable)
  • test: (adding missing tests, refactoring tests; no production code change)
  • chore: (updating grunt tasks etc; no production code change)
  • ux: (user experience changes)

References: