TypeScript Style Guide
Rules and best practices for writing TypeScript. Each section links to a detailed rule file with full code examples.
When to Use This Skill
- Writing new TypeScript code
- Reviewing TypeScript pull requests
- Refactoring existing TypeScript code
- Setting up a new TypeScript project
Syntax
Identifiers
| Style | Category |
|---|---|
UpperCamelCase |
class / interface / type / enum / decorator / type parameters |
lowerCamelCase |
variable / parameter / function / method / property / module alias |
CONSTANT_CASE |
global constant values, including enum values |
Key rules:
- Treat abbreviations as whole words:
loadHttpUrl, notloadHTTPURL - Do not use
_as a prefix or suffix - Do not use
#privatefields; use TypeScript'sprivatekeyword - React components must be
UpperCamelCase - Do not decorate names with type info (no
IMyInterface, noopt_prefix) - Names must be descriptive and clear to new readers
Comments & Documentation
- Use
/** JSDoc */for documentation (user-facing) - Use
// line commentsfor implementation notes - Document all top-level exports
- Omit comments redundant with TypeScript types (no
@paramtypes, no@implements) - Do not use
@override - Place JSDoc before decorators, not between decorator and declaration
- Make comments add information; don't just restate parameter names
- Use UTF-8 encoding; use actual Unicode characters for non-ASCII
Language Rules
Classes
- Limit symbol visibility as much as possible
- Never use the
publicmodifier except for non-readonly public parameter properties - Always use parentheses in constructor calls:
new Foo(), notnew Foo - Don't write empty constructors or constructors that just call
super() - Use
readonlyfor properties never reassigned outside the constructor - Use parameter properties instead of manual assignment
- Initialize fields where they're declared when possible
- Use semicolons (not commas) in interface/class member declarations
Functions
- Use
function foo() {}declarations for named functions - Use arrow functions in expressions (callbacks, etc.)
- Only use expression body (
=>without braces) when the return value is used - Do not use
thisin regular functions; use arrow functions or explicit params - Prefer wrapping instance method calls in arrow functions over arrow function properties
Variables & Primitives
- Always use
constorlet, nevervar - Use
constby default;letonly when reassignment is needed - Always use
new Error()(not bareError()) for exceptions - Do not instantiate wrapper classes (
new String(),new Boolean(),new Number()) - Do not use
Array()constructor; use bracket notation orArray.from() - Use
Number()for parsing; always check forNaN - Do not use unary
+orparseInt/parseFloat(except for non-base-10) - Do not rely on Automatic Semicolon Insertion; always use semicolons
- Always use
enum, notconst enum - No
debuggerstatements in production code - Do not define new decorators; only use framework-provided ones
Control Flow
- Multi-line control flow must use blocks
{ } - All
switchstatements must have adefaultcase - Always use
===and!==(exception:== nullto check both null/undefined) - Use
for...oforObject.keys()/Object.entries()instead offor...in - Do not use
.forEach(); usefor...ofloops - Only spread matching types (objects into objects, iterables into arrays)
Type Safety
- Do not use
@ts-ignore - Prefer runtime checks (
instanceof, truthiness) over type assertions - When assertions are necessary, use
assyntax (not angle brackets) - Use type annotations (
: Foo) on object literals, not assertions (as Foo) - Do not mix quoted and dotted property access
Source Organization
Modules & Imports
- Use relative imports (
./foo) within the same project - Do not use
namespace; use ES6 modules - Do not use
require(); use ES6import - Use
import type/export typefor type-only imports/exports
| Import type | Example | Use for |
|---|---|---|
| module | import * as foo from '...' |
Large APIs where namespacing improves readability |
| destructuring | import { Foo } from '...' |
Commonly used symbols |
| default | import Foo from '...' |
Only for external code that requires it |
| side-effect | import '...' |
Libraries loaded for side effects only |
Exports
- Use named exports; do not use default exports
- Minimize the exported API surface
- Do not use
export let(mutable exports) - Do not create container classes with only static members; export functions/constants directly
- Organize packages by feature, not by type
Type System
Type System Rules
- Rely on inference for trivially inferred types (
string,number,boolean,newexpressions) - Add annotations when they improve readability or catch refactoring bugs
- Return type annotations are optional but can improve documentation
- Use optional fields/params (
?) rather than| undefined - Do not include
| nullor| undefinedin type aliases - Use
interfacefor object shapes;typefor unions, tuples, primitives - Use
T[]for simple types;Array<T>for complex types (unions, objects) - Avoid
any; prefer specific types,unknown, or documented suppression - Use
Record<K, V>orMap/Setover plain objects as associative arrays - Never use wrapper types (
String,Boolean,Number,Object) - Avoid return-type-only generics
- Prefer simple types over complex mapped/conditional types when possible
Consistency
For any style question not covered here, follow the conventions already in the file, then the directory, then the project.