TypeScript : Les pratiques qui changent tout
TypeScript n’est pas juste “JavaScript avec des types”. C’est un outil de design puissant qui change la façon dont nous pensons notre code.
Strict Mode : Non négociable
{
"compilerOptions": {
"strict": true,
"noUncheckedIndexedAccess": true,
"noPropertyAccessFromIndexSignature": true
}
}
Le mode strict n’est pas une option, c’est la baseline. Il attrape 80% des bugs avant même l’exécution.
Types Utilitaires : Vos meilleurs amis
TypeScript offre des utilitaires puissants. Utilisez-les :
// Au lieu de dupliquer les interfaces
type UserFormData = Pick<User, 'name' | 'email'>;
type UserDTO = Omit<User, 'password'>;
type PartialUser = Partial<User>;
type ReadonlyUser = Readonly<User>;
Discriminated Unions pour la logique complexe
Les unions discriminées éliminent les bugs et rendent le code auto-documenté :
type Result<T> =
| { success: true; data: T }
| { success: false; error: string };
function handleResult<T>(result: Result<T>) {
if (result.success) {
// TypeScript sait que result.data existe
console.log(result.data);
} else {
// TypeScript sait que result.error existe
console.error(result.error);
}
}
Branded Types pour plus de sécurité
Évitez les confusions entre types similaires :
type UserId = string & { __brand: 'UserId' };
type Email = string & { __brand: 'Email' };
function getUser(id: UserId) { /* ... */ }
const email: Email = 'user@example.com' as Email;
// Erreur de compilation : Email n'est pas assignable à UserId
// getUser(email);
Template Literal Types
Typage fort des strings dynamiques :
type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';
type APIEndpoint = `/api/${string}`;
function request(method: HTTPMethod, endpoint: APIEndpoint) {
// TypeScript garantit le format
}
request('GET', '/api/users'); // ✅
request('GET', 'users'); // ❌ Erreur de compilation
Inférence de types : Laissez TypeScript travailler
N’annotez pas tout. L’inférence est puissante :
// ❌ Redondant
const users: User[] = getUsers();
// ✅ L'inférence suffit si getUsers() retourne User[]
const users = getUsers();
Const Assertions pour l’immutabilité
const config = {
apiUrl: 'https://api.example.com',
timeout: 5000
} as const;
// Type : { readonly apiUrl: "https://api.example.com"; readonly timeout: 5000 }
// Plus précis que { apiUrl: string; timeout: number }
Génériques : Ne pas en abuser
Les génériques ajoutent de la complexité. Utilisez-les quand ils apportent vraiment de la valeur :
// ✅ Utile
function identity<T>(value: T): T {
return value;
}
// ❌ Inutile
function logMessage<T extends string>(msg: T): void {
console.log(msg);
}
// Suffit :
function logMessage(msg: string): void {
console.log(msg);
}
Conclusion
TypeScript bien utilisé n’est pas une contrainte mais un multiplicateur de productivité. Ces patterns éliminent des classes entières de bugs et rendent le code self-documenting.
Le temps investi à bien typer se rentabilise dès la première refactorisation.