-
Notifications
You must be signed in to change notification settings - Fork 0
Coding Standards
Coding standards help keep code bases looking and feeling similar across all repositories. It is important that when someone looks at one section of code, they feel like it was written using the same standards as another portion of the code base.
In both of the main repositories, we use ESLint and Prettier to maintain most of our coding standards, but this document will serve as an outline to walk any new developer through both the items that are covered by our linters and those that are not.
These are the standards that everything in TypeScript, JavaScript, React, and Nest.js have in common
Prefer single quotation marks over double quotation marks. This is the most common preference of JavaScript/TypeScript developers.
Usage
❌ Incorrect usage:
const str = "hello world!"
const heSaid = "He said 'hi!'"
✔️ Correct usage:
const str = 'hello world!'
const heSaid = 'He said "hi!"'
const backTicks = `He said ${str}`
Arrays/lists/object properties split over separate lines will have a comma on every line (including the last line). This allows any later edits done to arrays, lists, and object properties to be done without looking for a missing comma.
Usage
❌ Incorrect Usage:
const func = (
param1,
param2
) {...}const arr = [
item1,
item2
];const obj = {
prop1,
prop2
};✔️ Correct Usage:
const func = (
param1,
param2,
) {...}const arr = [
item1,
item2,
];const obj = {
prop1,
prop2,
};Always prefer using semi colons wherever possible. Removing colons can sometimes have unintended and extremely difficult to debug errors/issues.
Usage
❌ Incorrect Usage:
const obj = { name: 'Name' }
const func = () => { console.log('hi!') }
✔️ Correct Usage:
const obj = { name: 'Name' };
const func = () => { console.log('hi!'); };
Usage
Prefer using arrow parentheses, even when unnecessary. This keeps all arrow parentheses looking the same across the board.
❌ Incorrect Usage:
const func = (res => { console.log(res) }; );
✔️ Correct Usage:
const func = ((res) => { console.log(res) }; );
Tab width in all projects is 2 spaces. This keeps nested code blocks closer to the left, which makes code easier to read on smaller screens.
Usage
❌ Incorrect Usage:
const func = () => {
console.log('hi!');
};✔️ Correct Usage:
const func = () => {
console.log('hi!');
};Curly braces need space! This is for readability and common practice. The one exception is HTML and React component properties. See usage for more details.
Usage
❌ Incorrect Usage:
import {Button} from 'reactstrap';const HelloWorld = ({className}) => (
<p className={className}>Hello World!</p>
)const obj = {name='Name'};✔️ Correct Usage:
import { Button } from 'reactstrap';const HelloWorld = ({ className }) => ( // notice that the property here has space
<p className={className}> // ✔️ this is the one exception - HTML and React property assignments do not require breathing space.
Hello World!
</p>
)const obj = { name='Name' };Prefer const and let over var. This follows most recent standards of both JavaScritp and TypeScript (ES6+).
Usage
❌ Incorrect Usage:
var func = () => {
console.log('hi!');
};✔️ Correct Usage:
const func = () => {
console.log('hi!');
};let str = 'Hello';
str + `${str} world!`;Use brackets for code blocks except HTML only react components or single line function returns. This helps with readability and, if a future editor has to come back to add lines to your code block, the brackets are already there.
Usage
❌ Incorrect Usage:
if (true) console.log('true');if (true)
console.log('true');✔️ Correct Usage:
if (true) {
console.log('true');
// now it's easier to add lines to this in the future.
}Curly braces should always open on the same line as preceding code. See usage for more.
Usage
❌ Incorrect Usage:
if (true)
{
console.log('true');
}✔️ Correct Usage:
if (true) {
console.log('true');
}catch, finally, else, and else if statements should always be on the same line as the previous closing brace. See usage for more information.
Usage
❌ Incorrect Usage:
if (true) {
console.log('true');
} else {
console.log('false');
}if (true && str.length > 1) {
console.log('true');
} else if (true && str.length === 1) {
console.log('false');
}try {
const response = await axios.get('/?id=example');
...
} catch {
console.log('failed');
}try {
const response = await axios.get('/?id=example');
...
} finally {
console.log('finally');
}✔️ Correct Usage:
```javascript
if (true) {
console.log('true');
} else {
console.log('false');
}if (true && str.length > 1) {
console.log('true');
} else if (true && str.length === 1) {
console.log('false');
}try {
const response = await axios.get('/?id=example');
...
} catch {
console.log('failed');
}try {
const response = await axios.get('/?id=example');
...
} finally {
console.log('finally');
}Console statements should be removed before creating a pull request. They can be useful for debugging, but console statements lower SEO and can give 3rd parties information that could be harmful to our product.
eval() statements must be removed before creating a pull request. Eval statements allow bad actors to pass any JavaScript statements with the privileges of the caller. See Mozilla's documentation for more information.
Do not use dangerouslySetInnerHTML(). Depending on the usage, this can allow bad actors to run JavaScript statements in the client or even run code in the server.
Always import react in any file that uses a react component. This import should also be the very first line in the file. This allows other developers to immediately know that they are looking at a react component by looking at a file that contains at least one react component.
Usage
❌ Incorrect Usage:
// missing import
const HelloWorld = () => (
<p>Hello world!</p>
)// no react component
import React from 'react';
const add = (a, b) => { return a + b; };import cn from 'classnames';
// not first import
import React from 'react';
const HelloWorld = ({className}) => (
<p className={cn('bold', className)}>
Hello world!
</p>
)✔️ Correct Usage:
// import on first line
import React from 'react';
import cn from 'classnames';
const HelloWorld = ({className}) => (
<p className={cn('bold', className)}>
Hello world!
</p>
)// no react component = no import
const add = (a, b) => { return a + b; };Imports should follow the following order:
- imports from react
- imports from any other react-created library in alphabetical order by library name
- imports from 3rd party libraries in alphabetical order by library name
- imports from internal project in alphabetical order by folder name, then file name
This allows for developers to easily find any library or file import quickly and easily.
Usage
❌ Incorrect Usage:
import cn from 'classnames'; // should import react first
import React from 'react';
...import React from 'react';
import { HelloWorld } from '../HelloWorld'; // 3rd party classnames should come before internal folder HelloWorld
import cn from 'classnames';
...import React from 'react';
import cn from 'classnames';
import { Router } from 'react-router-dom'; // this should come before classnames import
...import React from 'react';
import cn from 'classnames';
import * from 'alphabetical'; // this should come before classnames => alphabetical order
...import React from 'react';
import { AddFunction } from '../lib/Add';
import HelloWorld from '../components/HelloWorld'; // components folder comes before lib alphabetically
...import React from 'react';
import HelloWorld from '../HelloWorld';
import AddComponent from '../Add'; // Add component comes before HelloWorld alphabetically
...✔️ Correct Usage:
import React from 'react';
import { Router } from 'react-router-dom';
import cn from 'classnames';
import { Button } from 'reactstrap'; // reactstrap is not made by react teams.
import { AddFunction } from '../lib/Add';
import AddComponent from '../components/Add';
import HelloWorld from '../components/HelloWorld';
...React component file names should be in PascalCase, be named after the component, and have a file extension of .jsx.
Usage
❌ Incorrect Usage:
├── src
│ ├── components
│ │ ├── HelloWorld.js // must be jsx extension
│ │ ├── index.js
├── src
│ ├── components
│ │ ├── helloWorld.jsx // must be Pascal Case
│ │ ├── index.js
✔️ Correct Usage:
├── src
│ ├── components
│ │ ├── HelloWorld.jsx
│ │ ├── index.js
Component names should be in PascalCase and be the same as the file name without the extension.
Usage
❌ Incorrect Usage:
const helloWorld = () => (
<p>Hello world!</p>
)// file name = helloWorld.jsx <= file name should be pascal
const HelloWorld = () => (
<p>Hello world!</p>
)✔️ Correct Usage:
// file name is also HellWorld.jsx
import React from 'react';
const HelloWorld = () => (
<p>Hello world!</p>
)React components should always be arrow function components. This is follows most recent JSX standards.
Usage
❌ Incorrect Usage:
import React from 'react';
class HelloWorld extends React.Component {
render() {
return <p>Hello world!</p>;
}
}import React from 'react';
function HelloWorld () (
<p>Hello world!</p>
)✔️ Correct Usage:
import React from 'react';
const HelloWorld = () => (
<p>Hello world!</p>
)The following standards are specific to Nest.js applications.
Interfaces should not start with the commonly used interface abbreviation "I". See usage below.
Usage
❌ Incorrect Usage:
export interface IUser {
id: string;
...
}✔️ Correct Usage:
export interface User {
id: string;
...
}You are highly encouraged to avoid using the any type whenever possible. any removes intellisense and can make it more difficult to catch errors in the compiler. Often, type issues aren't caught until runtime.
Usage
❌ Incorrect Usage:
add = (a: any, b: any) => a + b;✔️ Correct Usage:
add = (a: number, b: number) => a + b;You are required to use return types in the service layer. This is only being used here as a learning mechanism to gain familiarity with TypeScript. You are not required to use return types in the controller layer, as the only interaction you should have with those functions directly is in the tests.
Usage
❌ Incorrect Usage:
@Injectable()
export class CalculatorService {
add = (a: number, b: number) => a + b;
}✔️ Correct Usage:
@Injectable()
export class CalculatorService {
add = (a: number, b: number): number => a + b;
}Always use !! to check for not null checks in a conditional statement (if, else if, while, etc.). This is to avoid other truthy values, such as 1, true, etc.
Usage
❌ Incorrect Usage:
let user: any;
user = 1;
if (user) {
...
}✔️ Correct Usage:
let user: any;
user = 1;
if (!!user) {
...
}Imports should follow the following order:
- imports from any nest-created library in alphabetical order by library name
- imports from 3rd party libraries in alphabetical order by library name
- imports from internal project in alphabetical order by folder name, then file name
This allows for developers to easily find any library or file import quickly and easily.
Usage
❌ Incorrect Usage:
import { PrismaClient } from '@prisma/client'; // should import from nest first
import { Injectable } from '@nestjs/common';
...import { NestFactory } from '@nestjs/core'; // '@nestjs/common' comes before '@nestjs/core' alphabetically
import { Injectable } from '@nestjs/common';
...import { Injectable } from '@nestjs/common';
import { SupabaseClient } from '@supabase/supabase-js';
import { PrismaClient } from '@prisma/client'; // this should come before supabase => alphabetical order
...import { Injectable } from '@nestjs/common';
import { SetAdminDto, UserProfileListItemDto } from './dtos'; // this should come after all 3rd party library imports
import { PrismaClient } from '@prisma/client';
import { SupabaseClient } from '@supabase/supabase-js';
...import { UserProfileListItemDto, SetAdminDto} from './dtos'; // imports are in incorrect orderimport { Injectable } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';
import { SupabaseClient } from '@supabase/supabase-js';
import { SetAdminDto, UserProfileListItemDto } from './dtos';
import { CurrentUser } from './decorators'; // this should come before dtos => alphabetical ordering
...✔️ Correct Usage:
import { Injectable } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';
import { SupabaseClient } from '@supabase/supabase-js';
import { CurrentUser } from './decorators'; // this should come before dtos => alphabetical ordering
import { SetAdminDto, UserProfileListItemDto } from './dtos';
...