NodeJS
TypeScript Best Practices: Writing Production-Ready Code
2024-03-01•11 min read•By Abdul Basit
On this page
On this page
Writing production-ready TypeScript code requires more than just adding types. This guide covers advanced TypeScript patterns, best practices, and techniques to build scalable, maintainable applications.
Enable Strict Mode
Always enable strict mode in your tsconfig.json for better type safety:
tsconfig.json strict settings:
{
"compilerOptions": {
"strict": true, // Enables all strict checks
// Or enable individually:
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"strictBindCallApply": true,
"strictPropertyInitialization": true,
"noImplicitThis": true,
"alwaysStrict": true
}
}Utility Types
TypeScript provides powerful utility types for common type transformations:
Common utility types:
interface User {
name: string;
age: number;
email: string;
active: boolean;
}
// Partial - makes all properties optional
type PartialUser = Partial<User>;
// { name?: string; age?: number; email?: string; active?: boolean; }
// Required - makes all properties required
type RequiredUser = Required<PartialUser>;
// Readonly - makes all properties readonly
type ReadonlyUser = Readonly<User>;
// Pick - select specific properties
type UserName = Pick<User, "name" | "email">;
// { name: string; email: string; }
// Omit - exclude specific properties
type UserWithoutEmail = Omit<User, "email">;
// { name: string; age: number; active: boolean; }
// Record - create object type with specific keys
type UserRoles = Record<string, boolean>;
// { [key: string]: boolean; }
// Exclude - exclude types from union
type NonNullable<T> = Exclude<T, null | undefined>;
// Extract - extract types from union
type StringOrNumber = Extract<string | number | boolean, string | number>;
// ReturnType - get return type of function
type AddResult = ReturnType<typeof add>; // number
// Parameters - get parameter types
type AddParams = Parameters<typeof add>; // [number, number]Type Guards
Type guards help TypeScript narrow types in conditional blocks:
Type guard functions:
// Type predicate
function isString(value: unknown): value is string {
return typeof value === "string";
}
function processValue(value: unknown) {
if (isString(value)) {
// TypeScript knows value is string here
console.log(value.toUpperCase());
}
}
// instanceof type guard
class Dog {
bark() {
console.log("Woof!");
}
}
class Cat {
meow() {
console.log("Meow!");
}
}
function makeSound(animal: Dog | Cat) {
if (animal instanceof Dog) {
animal.bark();
} else {
animal.meow();
}
}
// Discriminated unions
type Success = {
status: "success";
data: string;
};
type Error = {
status: "error";
message: string;
};
type Result = Success | Error;
function handleResult(result: Result) {
if (result.status === "success") {
console.log(result.data); // TypeScript knows it's Success
} else {
console.error(result.message); // TypeScript knows it's Error
}
}Avoid Using 'any'
Better alternatives to any:
// Bad: Using any
function processData(data: any) {
return data.value;
}
// Good: Use unknown and type guards
function processData(data: unknown) {
if (typeof data === "object" && data !== null && "value" in data) {
return (data as { value: string }).value;
}
throw new Error("Invalid data");
}
// Better: Define proper types
interface Data {
value: string;
}
function processData(data: Data) {
return data.value;
}
// Use generics for flexible types
function getValue<T>(obj: { value: T }): T {
return obj.value;
}
const stringValue = getValue<string>({ value: "hello" });
const numberValue = getValue<number>({ value: 42 });Learning Resources
Continue mastering TypeScript:
- TypeScript Deep Dive: Comprehensive TypeScript guide
- TypeScript Handbook: Official TypeScript documentation
- FreeCodeCamp TypeScript: TypeScript tutorials
Share Your Feedback
Your thoughts help me improve my content.