Best Practices in TypeScript
Level: Beginner to Intermediate
- What Best Practices in TypeScript means in React + TypeScript
- How type safety improves React components
- How to model School Management System data with interfaces and types
- Common TypeScript mistakes to avoid
- How to explain this topic in interviews
Why This Matters
Best Practices in TypeScript helps you build React screens with fewer runtime bugs. In real .NET Web API projects, TypeScript makes API DTOs, component props, form state, and shared data contracts easier to understand and safer to change.
Write maintainable, type-safe React applications with patterns that prevent bugs.
Prerequisite: Read React JS article 16 first.
The Problem
React JavaScript can fail at runtime when props, API responses, or form values have the wrong shape. This lesson shows how Best Practices in TypeScript uses TypeScript to catch many of those mistakes while you write code, before the student dashboard reaches users.
Enable Strict Mode
{
"compilerOptions": {
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true
}
}
Avoid any and unknown
// ❌ Any defeats TypeScript
function process(data: any): any {
return data.value;
}
// ✓ Generic better
function process<T extends { value: string }>(data: T): string {
return data.value;
}
// ✓ Unknown safer
function process(data: unknown): string {
if (typeof data === 'object' && data !== null && 'value' in data) {
return (data as { value: string }).value;
}
throw new Error('Invalid data');
}
Const Assertions for Type Safety
const STUDENT_STATUSES = ['Active', 'Inactive', 'Graduated'] as const;
type StudentStatus = typeof STUDENT_STATUSES[number];
// StudentStatus = 'Active' | 'Inactive' | 'Graduated'
const statusConfig: Record<StudentStatus, { color: string; icon: string }> = {
Active: { color: 'green', icon: '✓' },
Inactive: { color: 'red', icon: '✗' },
Graduated: { color: 'blue', icon: '🎓' }
};
// If you forget a status, TypeScript errors
Use Discriminated Unions
type Result<T> =
| { ok: true; data: T }
| { ok: false; error: Error };
function handleResult<T>(result: Result<T>): void {
if (result.ok) {
console.log(result.data);
} else {
console.error(result.error);
}
}
Strict Component Props
interface StudentCardProps {
student: Student;
onDelete: (id: number) => Promise<void>;
onEdit?: (id: number) => void;
}
function StudentCard({ student, onDelete, onEdit }: StudentCardProps) {
// All props are known and typed
return <div>{student.name}</div>;
}
// ❌ Passing unknown prop is an error
// <StudentCard student={s} unknown="value" />
Exhaustive Pattern Matching
type Action =
| { type: 'LOAD_START' }
| { type: 'LOAD_SUCCESS'; data: Student[] }
| { type: 'LOAD_ERROR'; error: Error };
function reducer(state: State, action: Action): State {
switch (action.type) {
case 'LOAD_START':
return { ...state, loading: true };
case 'LOAD_SUCCESS':
return { ...state, data: action.data, loading: false };
case 'LOAD_ERROR':
return { ...state, error: action.error, loading: false };
// ❌ Error if case missing
}
}
Type Inference
// Let TypeScript infer types when obvious
const count = 0; // inferred as number
const name = "Ravi"; // inferred as string
const students = []; // inferred as unknown[]
// But be explicit when ambiguous
const students: Student[] = []; // Empty array needs explicit type
No Loose Equality
// ❌ Avoid == and !=
if (value == null) { }
// ✓ Use === and !==
if (value === null) { }
// ✓ Or optional chaining
if (!value?.property) { }
Key Takeaways
- Enable strict mode
- Avoid
any - Use discriminated unions
- Const assertions for literals
- Exhaustive pattern matching
- Type inference when obvious
- Next: Debugging and testing
- Any for convenience — Defeats purpose
- Not exhaustive — Missing cases
- Weak types — Use strong types
- Ignoring compiler — Fix all errors
# Check for issues
npx tsc --noEmit
npx eslint src/
Use ChatGPT, Claude, or Copilot to go deeper on TS Practices. Try these prompts:
"Why enable strict mode?""When use unknown vs any?""What's exhaustive checking?""Quiz me on best practices"
💡 Tip: After reading this article, paste your own code into AI and ask "What could go wrong here and why?" — fastest way to find edge cases and deepen understanding.
Quick Definitions
- Best Practices in TypeScript - The main React + TypeScript concept explained in this lesson.
- Type/interface - A contract that describes the shape of data.
- Typed props/state - React data with clear compile-time expectations.
- API DTO - The request or response shape shared with ASP.NET Core Web API.
Common Mistakes
- Using
anytoo quickly instead of defining a useful type - Typing props loosely and losing the benefit of TypeScript
- Forgetting that API data can still be missing or invalid at runtime
- Making types too complex before the component is stable
- Not sharing clear DTO shapes between frontend and backend teams
Practice Task
Create a small React TypeScript example using Best Practices in TypeScript. Keep it connected to a School Management System scenario.
Suggested practice:
- Define a clear
Student,Teacher, orAttendancetype. - Build a small typed component or hook.
- Add one valid example and one intentionally wrong example to see TypeScript errors.
- Explain the type contract in your own words.
- Rebuild the same example once without looking at the article.
Quick Revision
| Question | Answer |
|---|---|
| What is the main idea? | Use TypeScript to make Best Practices in TypeScript safer in React. |
| Where is it used? | Props, state, forms, API responses, context, hooks, and routes. |
| What should beginners avoid? | Overusing any and ignoring runtime API validation. |
| What is the best debugging habit? | Read the TypeScript error, check the data shape, and fix the type contract. |
Best Practices in TypeScript is a React + TypeScript concept that improves safety and maintainability. I would explain which values need types, how TypeScript catches mistakes early, and how it helps when consuming ASP.NET Core Web API responses.
It is used in typed props, API response models, form state, route parameters, context values, custom hooks, and reusable UI components.