This style guide extends existing JavaScript style guide and defines rules for TypeScript specific features.
tsc has some options
to make type checks stricter:
{
"compilerOptions": {
"strict": true,
"noEmitOnError": true
}
}It's recommended to turn them on as early as possible in development (and migration from JS).
If you want TypeScript to check for unused variables and parameters instead tslint, you can
add the following options:
{
"compilerOptions": {
"noUnusedLocals": true,
"noUnusedParameters": true
}
}-
InterfaceLikeThis. -
TypeAliasLikeThis. -
In generics:
KandVare reserved for key-value generic data structures,Kfor key types andVfor value types;TandUare reserved for generic data types;- other generic parameters should have meaningful names:
Good:
function foo<Attribute, State>(attributes: Attribute[], state: State): void { // ... }
Bad:
function foo<A, S>(attributes: A[], state: S): void { // ... }
-
Prefer interfaces to in place structure definitions:
Explanation: In place structure definitions make it unnecessary difficult to reuse a type. Also meaningful type names help to document code.
Good:
interface Person { name: string; age: number; } let person: Person;
Bad:
let person: {name: string, age: number};
-
Prefer interfaces to type aliases.
Explanation: From handbook:
...interfaces create a new name that is used everywhere... [whereas] ...type aliases don’t create a new name — for instance, error messages won’t use the alias name.
...type aliases cannot be extended or implemented from.
-
Don't use
voidfor functions returningundefined:Explanation:
voidmeans that a function doesn't return a value;voidisn't assignable toundefined.
Good:
function find(): object | undefined { // ... return; // or `return undefined;` for the sake of being explicit. }
Bad:
function find(): object | void { // ... }
-
There should be one whitespace before and after the type operator:
Good:
let foo: string | number;
Bad:
let foo: string|number;
-
Use
as Typefor type assertions:Explanation: Use one style for
JSXand not.Good:
(someValue as string).length;
Bad:
(<string>someValue).length;
-
For array declaration use
T[]notation:Good:
let pool: (LockableConnection | null)[];
Bad:
let pool: Array<LockableConnection | null>;
-
Don't use
publicmodifier for public class members:Explanation: In TypeScript, each member is public by default (like in JavaScript). Explicit public modifier is redundant.
Good:
class Foo { publicProp: number; publicMethod(): void {} }
Bad:
class Foo { public publicProp: number; public publicMethod(): void {} }
-
Prefix
privateandprotectedfields with_:Explanation:
- Underscore specifies visual difference from public fields. So, you don't need to read the field's declaration to determine its visibility.
- Minimizes name conflicts with public fields: after adding public field with the same name as private field, you don't need perform renaming.
- Simplifies migration from JavaScript, where
_often means that the field is "internal". - Improves autocompletion by dictionary: when you type
_the autocomplete popup shows non-public fields.
Good:
class Foo { private _prop: number; protected _method(): void {} }
Bad:
class Foo { private prop: number; protected method(): void {} }
-
Prefer using const enums.
Explanation: const enums are completely removed during compilation. Const enum members are inlined at places of use.
If you need real objects in generated code, use non-const enums. E.g.:
- enum contains computed members;
- enum should be printed (generated object stores both forward (
name -> value) and reverse (value -> name) mappings); - enum should be available from JavaScript.
-
For enum values use
UPPER_CASEstyle.Good:
enum Foo { BAR, BAZ } enum Bar { FOO = 'foo', BAZ = 'baz' }
Bad:
enum Foo { Bar, Baz }