TypeScript Best Practices
Applies TypeScript conventions that keep code strict, readable, and easy to refactor.
Project conventions override these defaults when they are already established. When editing React TSX, also apply React best practices.
Review Workflow
- Check strictness first: avoid
any, unsafe indexing, and loose optional properties.
- Prefer inference for local implementation details.
- Add explicit boundaries for exported functions, public APIs, and complex return types.
- Choose
interface for object shapes and type for unions, primitives, and intersections.
- Replace enums with const objects unless project conventions require enums.
- Check naming, unused variables, and file naming against local project conventions.
Do Not Use For
- Plain JavaScript unless the task involves adding types, migrating to TypeScript, or editing JSDoc types.
- Generated TypeScript files unless the generator or schema is being changed.
Strictness
- Follow TypeScript strict mode with
exactOptionalPropertyTypes and noUncheckedIndexedAccess
- Avoid using the
any type unless absolutely necessary; prefer unknown for unknown types
- Narrow
unknown before use
- Do not use
var declarations; use let or const instead
function getErrorMessage(error: unknown): string {
if (error instanceof Error) return error.message;
return String(error);
}
Types vs Interfaces
- Use
interface for object definitions, especially for React component props and object inheritance
- Use
type for primitives, unions, and intersections
Enums
Avoid using enum due to runtime cost and potential type safety issues. Prefer const objects with as const:
// Bad
enum Status {
Active = "active",
Inactive = "inactive",
}
// Good
const Status = {
Active: "active",
Inactive: "inactive",
} as const;
type Status = (typeof Status)[keyof typeof Status];
Type Declaration
- Prefer implicit return types when TypeScript can infer them for local implementation details
- Use explicit return types for exported functions, public APIs, and complex return values
- Prefer array brackets (
Type[]) over the Array<Type> generic for array types
- Avoid explicit type annotations when TypeScript can infer the type (e.g., in
.map() callbacks, variable assignments)
Functions
- Use
function instead of const for top-level functions
- Use
const for callback functions inside React components
Variables
- Prefix unused variables with an underscore (
_var)
- Use descriptive names with auxiliary verbs (e.g.,
isLoading, hasError)
Naming Conventions
- camelCase for variables and functions
- PascalCase for components and types
- Prefer kebab-case for filenames unless the project already uses another convention
1---2name: typescript-best-practices3description: Guides writing, reviewing, and refactoring TypeScript strictness, inference, unknown handling, interfaces, enums, functions, variables, and naming. Use when working on TypeScript code, TSX, type definitions, or type-safe refactors.4---56# TypeScript Best Practices78Applies TypeScript conventions that keep code strict, readable, and easy to refactor.910Project conventions override these defaults when they are already established. When editing React TSX, also apply React best practices.1112## Review Workflow13141. Check strictness first: avoid `any`, unsafe indexing, and loose optional properties.152. Prefer inference for local implementation details.163. Add explicit boundaries for exported functions, public APIs, and complex return types.174. Choose `interface` for object shapes and `type` for unions, primitives, and intersections.185. Replace enums with const objects unless project conventions require enums.196. Check naming, unused variables, and file naming against local project conventions.2021## Do Not Use For2223- Plain JavaScript unless the task involves adding types, migrating to TypeScript, or editing JSDoc types.24- Generated TypeScript files unless the generator or schema is being changed.2526## Strictness2728- Follow TypeScript strict mode with `exactOptionalPropertyTypes` and `noUncheckedIndexedAccess`29- Avoid using the `any` type unless absolutely necessary; prefer `unknown` for unknown types30- Narrow `unknown` before use31- Do not use `var` declarations; use `let` or `const` instead3233```typescript34function getErrorMessage(error: unknown): string {35 if (error instanceof Error) return error.message;36 return String(error);37}38```3940## Types vs Interfaces4142- Use `interface` for object definitions, especially for React component props and object inheritance43- Use `type` for primitives, unions, and intersections4445## Enums4647Avoid using `enum` due to runtime cost and potential type safety issues. Prefer const objects with `as const`:4849```typescript50// Bad51enum Status {52 Active = "active",53 Inactive = "inactive",54}5556// Good57const Status = {58 Active: "active",59 Inactive: "inactive",60} as const;6162type Status = (typeof Status)[keyof typeof Status];63```6465## Type Declaration6667- Prefer implicit return types when TypeScript can infer them for local implementation details68- Use explicit return types for exported functions, public APIs, and complex return values69- Prefer array brackets (`Type[]`) over the `Array<Type>` generic for array types70- Avoid explicit type annotations when TypeScript can infer the type (e.g., in `.map()` callbacks, variable assignments)7172## Functions7374- Use `function` instead of `const` for top-level functions75- Use `const` for callback functions inside React components7677## Variables7879- Prefix unused variables with an underscore (`_var`)80- Use descriptive names with auxiliary verbs (e.g., `isLoading`, `hasError`)8182## Naming Conventions8384- camelCase for variables and functions85- PascalCase for components and types86- Prefer kebab-case for filenames unless the project already uses another convention