Skip to content

Latest commit

 

History

History
393 lines (259 loc) · 6.64 KB

ts_style_guide.md

File metadata and controls

393 lines (259 loc) · 6.64 KB

TypeScript StyleGuide and Coding Conventions

Key Sections:

Variable and Function

  • Use camelCase for variable and function names

Reason: Conventional JavaScript

Bad

var FooVar;
function BarFunc() {}

Good

var fooVar;
function barFunc() {}

Class

  • Use PascalCase for class names.

Reason: This is actually fairly conventional in standard JavaScript.

Bad

class foo {}

Good

class Foo {}
  • Use camelCase of class members and methods

Reason: Naturally follows from variable and function naming convention.

Bad

class Foo {
  Bar: number;
  Baz() {}
}

Good

class Foo {
  bar: number;
  baz() {}
}

Component

  • Use PascalCase for component name, even if function component.

Reason: Follows React naming convention.

Bad

const component: React.FC = () => {
  return <subComponent />;
};

Good

const Component: React.FC = () => {
  return <SubComponent />;
};

Interface

  • Use PascalCase for name.

Reason: Similar to class

  • Use camelCase for members.

Reason: Similar to class

  • Don't prefix with I

Reason: Unconventional. lib.d.ts defines important interfaces without an I (e.g. Window, Document etc).

Bad

interface IFoo {}

Good

interface Foo {}

Type

  • Use PascalCase for name.

Reason: Similar to class

  • Use camelCase for members.

Reason: Similar to class

  • Use ALL_CAPS for action types.

Reason: Follows Redux naming convention

Namespace

  • Use PascalCase for names

Reason: Convention followed by the TypeScript team. Namespaces are effectively just a class with static members. Class names are PascalCase => Namespace names are PascalCase

Bad

namespace foo {}

Good

namespace Foo {}

Enum

  • Use PascalCase for enum names

Reason: Similar to Class. Is a Type.

Bad

enum color {}

Good

enum Color {}
  • Use PascalCase for enum member

Reason: Convention followed by TypeScript team i.e. the language creators e.g SyntaxKind.StringLiteral. Also helps with translation (code generation) of other languages into TypeScript.

Bad

enum Color {
  red,
}

Good

enum Color {
  Red,
}

Null vs. Undefined

  • Prefer not to use either for explicit unavailability

Reason: these values are commonly used to keep a consistent structure between values. In TypeScript you use types to denote the structure

Bad

let foo = { x: 123, y: undefined };

Good

let foo: { x: number; y?: number } = { x: 123 };
  • Use undefined in general (do consider returning an object like {valid:boolean,value?:Foo} instead)

Bad

return null;

Good

return undefined;
  • Use null where its a part of the API or conventional

Reason: It is conventional in Node.js e.g. error is null for NodeBack style callbacks.

Bad

cb(undefined);

Good

cb(null);
  • Use truthy check for objects being null or undefined

Bad

if (error === null)

Good

if (error)

Remark: Use === / !== to check for null / undefined on primitives that might be other falsy values (like '',0,false).

Formatting

Use Prettier to format TypeScript code as described in the README.

Reason: Reduce the cognitive overload on the team.

Quotes

  • Prefer double quotes (").

Reason: Follows Prettier naming convention.

Semicolons

  • Use semicolons.

Reasons: Explicit semicolons helps language formatting tools give consistent results. Missing ASI (automatic semicolon insertion) can trip new devs e.g. foo() \n (function(){}) will be a single statement (not two). TC39 warning on this as well. Example teams: airbnb, idiomatic, google/angular, facebook/react, Microsoft/TypeScript.

Array

  • Annotate arrays as foos:Foo[] instead of foos:Array<Foo>.

Reasons: Its easier to read. Its used by the TypeScript team. Makes easier to know something is an array as the mind is trained to detect [].

Filename

Name files with camelCase. E.g. accordion.tsx, myControl.tsx, utils.ts, map.ts etc.

Reason: Conventional across many JS teams.

type vs. interface

  • Use type when you might need a union or intersection:
type Foo = number | { someProperty: number }
  • Use interface when you want extends or implements e.g
interface Foo {
  foo: string;
}
interface FooBar extends Foo {
  bar: string;
}
class X implements FooBar {
  foo: string;
  bar: string;
}
  • Otherwise use whatever makes you happy that day.

One line if statements

Add braces to one-line if statements;

Good

if (isEmpty) {
  callFun();
}

Bad

if (isEmpty)
  callFun();

Reason: Avoiding braces can cause developers to miss bugs, such as Apple's infamous goto-fail bug

imports

Use absolute import statements everywhere for consistency.

Good

import { getAllProjects } from "backend";
import { Project } from "types/project";

Bad

import { getAllProjects } from "../../../../backend";
import { Project } from "../../../../types/project";

Reason: Provides consistency for imports across all files and shortens imports of commonly used top level modules. Developers don't have to count ../ to know where a module is, they can simply start from the root of src/.

KeyboardEvents

Use ts-key-enum when comparing to React.KeyboardEvents.

Good

import { Key } from "ts-key-enum";

if (event.key === Key.Enter) {
}

Bad

if (event.key === "Enter") {
}

Reason: Avoid typos and increase the number of mistakes that can be caught at compile time.