Back to Blog
★ TypeScript ★
TypeScript Best Practices in 2025
Jun 8, 2025 6 min read By Ahmad Zaini Nijar
Improve your TypeScript code with these modern patterns — from strict types to utility types and type guards.
Enable Strict Mode
Always enable strict mode in your tsconfig.json:
{
"compilerOptions": {
"strict": true
}
}
This enables a suite of type-checking rules that catch many common bugs.
Use Utility Types
TypeScript has powerful built-in utility types:
interface User {
id: number;
name: string;
email: string;
password: string;
}
// Pick only what you need
type PublicUser = Omit<User, 'password'>;
// Make all fields optional
type PartialUser = Partial<User>;
// Make all fields required
type RequiredUser = Required<User>;
// Read-only version
type ReadonlyUser = Readonly<User>;
Type Guards
Use type guards to narrow types safely:
function isString(value: unknown): value is string {
return typeof value === 'string';
}
function isUser(value: unknown): value is User {
return (
typeof value === 'object' &&
value !== null &&
'id' in value &&
'name' in value
);
}
Discriminated Unions
Great for modelling states:
type ApiState<T> =
| { status: 'idle' }
| { status: 'loading' }
| { status: 'success'; data: T }
| { status: 'error'; message: string };
function render(state: ApiState<User>) {
switch (state.status) {
case 'loading': return 'Loading...';
case 'success': return state.data.name; // fully typed!
case 'error': return state.message;
default: return 'Idle';
}
}
const Assertions
Use as const to infer literal types:
const ROLES = ['admin', 'user', 'guest'] as const;
type Role = typeof ROLES[number]; // 'admin' | 'user' | 'guest'
Conclusion
TypeScript's type system is incredibly powerful. Investing time in strong types pays dividends in the form of fewer bugs, better editor support, and more confident refactoring.