TypeScript avec Cursor : Typage sûr et développement assisté par l'IA

TypeScript ajoute une puissante sécurité de typage, et l'IA de Cursor peut générer des types complexes, suggérer des améliorations et attraper des erreurs de type bien plus rapidement que manuellement. Ce guide couvre les bonnes pratiques TypeScript, les patterns avancés et les workflows assistés par l'IA.
Prérequis
Avant de commencer :
- Cursor installé (dernière version recommandée)
- Familiarité avec les bases de TypeScript (types, interfaces, génériques)
- Un projet avec tsconfig.json configuré
Configuration de TypeScript dans Cursor
Bonnes pratiques tsconfig.json
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"outDir": "./dist",
"rootDir": "./src",
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
Paramètres TypeScript de Cursor
// .vscode/settings.json
{
"typescript.preferences.importModuleSpecifier": "relative",
"typescript.suggest.autoImports": true,
"typescript.inlayHints.parameterNames.enabled": "all",
"typescript.inlayHints.variableTypes.enabled": true
}
Génération de types avec l'IA
Générer des interfaces à partir de réponses API
Collez une réponse JSON et laissez Cursor générer les types :
Génère des interfaces TypeScript pour ces réponses API :
[coller le JSON]
Cursor génère :
interface User {
id: number;
name: string;
email: string;
role: 'admin' | 'user' | 'guest';
profile: {
avatar: string;
bio: string | null;
};
createdAt: string; // Date ISO
}
interface ApiResponse<T> {
data: T;
meta: {
page: number;
total: number;
};
}
Inférence de types à partir de signatures de fonctions
// Demandez à Cursor de typer un objet de configuration
const config = {
apiUrl: 'https://api.example.com',
timeout: 5000,
retries: 3,
};
// Suggestion de Cursor :
interface ApiConfig {
readonly apiUrl: string;
readonly timeout: number;
readonly retries: number;
}
Patterns de types avancés
Types conditionnels
// Wrapper de réponse API basé sur le type
type ApiResponse<T> = T extends Array<infer U>
? { data: T; count: number }
: { data: T };
// Utilisation
const usersResponse: ApiResponse<User[]> = {
data: users,
count: users.length,
};
const userResponse: ApiResponse<User> = {
data: user,
};
Types de littéraux de modèle
type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';
type Endpoint = `/api/${string}`;
type ApiRoute = `${HttpMethod} ${Endpoint}`;
// => "GET /api/users" | "POST /api/users" | ...
Gardes de type
// Rétrécissement des unions
type Result<T, E = Error> =
| { success: true; data: T }
| { success: false; error: E };
async function fetchUser(id: string): Promise<Result<User>> {
try {
const user = await db.user.findById(id);
if (!user) {
return { success: false, error: new Error('User not found') };
}
return { success: true, data: user };
} catch (error) {
return { success: false, error: error as Error };
}
}
Patterns de génériques
Hooks typés sûrement
// useLocalStorage avec génériques
function useLocalStorage<T>(key: string, initialValue: T) {
const [value, setValue] = useState<T>(() => {
const stored = localStorage.getItem(key);
return stored ? (JSON.parse(stored) as T) : initialValue;
});
const updateValue = useCallback(
(newValue: T | ((prev: T) => T)) => {
setValue((prev) => {
const next = newValue instanceof Function ? newValue(prev) : newValue;
localStorage.setItem(key, JSON.stringify(next));
return next;
});
},
[key]
);
return [value, updateValue] as const;
}
// Utilisation
const [user, setUser] = useLocalStorage<User>('user', defaultUser);
Client API typé sûrement
interface ApiClient {
get<T>(url: string): Promise<T>;
post<T, D>(url: string, data: D): Promise<T>;
put<T, D>(url: string, data: D): Promise<T>;
delete<T>(url: string): Promise<T>;
}
// L'implémentation fournit l'inférence de types
const user = await api.get<User>('/users/1');
const created = await api.post<User, CreateUserDTO>('/users', newUser);
Bonnes pratiques d'inférence de types
| Pattern | Recommandé |
|---|---|
| Valeurs de retour | Laisser TypeScript inférer les retours simples |
| Paramètres de fonction | Toujours typer explicitement |
| Tableaux | Utiliser as const pour les tableaux vides |
| Objets de configuration | Typer au niveau du module |
| React Props | Toujours utiliser des interfaces |
Patterns TypeScript courants
Types marqués
type UserId = string & { __brand: 'UserId' };
type PostId = string & { __brand: 'PostId' };
function createUserId(id: string): UserId {
return id as UserId;
}
// Prévenir la confusion des IDs
function fetchUser(id: UserId) { ... }
function fetchPost(id: PostId) { ... }
Type Résultat
type Result<T, E = Error> =
| { success: true; data: T }
| { success: false; error: E };
async function fetchUser(id: string): Promise<Result<User>> {
try {
const user = await db.user.findById(id);
if (!user) {
return { success: false, error: new Error('User not found') };
}
return { success: true, data: user };
} catch (error) {
return { success: false, error: error as Error };
}
}
Débogage de types avec Cursor
Analyse des erreurs de type
Explique cette erreur de type et propose une correction :
[coller l'erreur]
Génération de tests de types
// Tester vos types avec des défis de types
type Assert<T, U> = T extends U ? true : false;
// Tests
type Test1 = Assert<string, string>; // true
type Test2 = Assert<number, string>; // false
Ressources connexes
Dernière mise à jour : Juillet 2025