Aller au contenu principal

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

Cursor TypeScript

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​

PatternRecommandé
Valeurs de retourLaisser TypeScript inférer les retours simples
Paramètres de fonctionToujours typer explicitement
TableauxUtiliser as const pour les tableaux vides
Objets de configurationTyper au niveau du module
React PropsToujours 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