Table of Contents
Introduction
Vous etes peut-etre deja familiarise avec la programmation orientee objet dans Vue.js et avez utilise l’API de composition pour construire vos composants. Mais avez-vous deja explore les fonctionnalites de TypeScript dans votre application Vue ? Dans ce guide complet, nous allons presenter les fondements du TypeScript et montrer comment l’utiliser efficacement avec la Composition API de Vue 3.
L’adoption de TypeScript dans l’ecosysteme Vue.js a connu une croissance exponentielle ces dernieres annees. Vue 3 a ete entierement reecrit en TypeScript, ce qui garantit une integration native et une experience developpeur optimale. Cette decision strategique de l’equipe Vue temoigne de l’importance du typage statique dans le developpement d’applications modernes.
Dans cet article, nous allons explorer en profondeur comment TypeScript ameliore votre code Vue, depuis les types de base jusqu’aux patterns avances de typage des composants. Que vous soyez debutant en TypeScript ou developpeur experimente cherchant a optimiser vos pratiques, ce guide vous fournira les connaissances necessaires pour maitriser cette combinaison puissante.
Pourquoi utiliser TypeScript avec Vue.js ?
Le JavaScript est un langage faiblement type, ce qui signifie que vous pouvez assigner n’importe quel type de donnees a une variable sans erreur. Par exemple :
// JavaScript - Pas d'erreur a la compilation
const one = 1;
const two = 'two';
// Ceci peut causer des bugs subtils
function add(a, b) {
return a + b;
}
add(1, '2'); // Retourne '12' au lieu de 3 !
Cependant, cela peut conduire a des erreurs difficiles a detecter lorsque votre code devient plus complexe. Le TypeScript est un langage superset du JavaScript qui ajoute des fonctionnalites de typage statique pour empecher ces types d’erreurs.
Les avantages concrets de TypeScript
1. Detection des erreurs a la compilation
TypeScript detecte les erreurs avant meme que votre code ne s’execute :
function add(a: number, b: number): number {
return a + b;
}
add(1, '2'); // Erreur TypeScript : l'argument de type 'string'
// n'est pas assignable au parametre de type 'number'
2. Autocompletion intelligente
Votre IDE connait exactement les proprietes et methodes disponibles :
interface User {
id: number;
name: string;
email: string;
createdAt: Date;
}
const user: User = { /* ... */ };
user. // L'IDE suggere : id, name, email, createdAt
3. Refactoring securise
Renommer une propriete ou modifier une signature de fonction devient sur car TypeScript signale toutes les utilisations incorrectes.
4. Documentation integree
Les types servent de documentation vivante pour votre code :
// La signature de la fonction documente son utilisation
function formatUserName(
firstName: string,
lastName: string,
options?: { uppercase?: boolean }
): string {
const fullName = `${firstName} ${lastName}`;
return options?.uppercase ? fullName.toUpperCase() : fullName;
}
Qu’est-ce que le TypeScript ?
Le TypeScript a ete cree en 2012 par Microsoft et est desormais maintenu par une large communaute. Il est concu pour :
- Ameliorer la lisibilite du code grace aux annotations de type
- Prevenir les erreurs de programmation courantes avant l’execution
- Reduire le temps et l’effort necessaires pour deboguer des applications
- Faciliter le travail en equipe grace a des contrats clairs entre modules
- Permettre une meilleure scalabilite des projets
Le TypeScript n’est pas un langage different, mais une extension du JavaScript qui ajoute des fonctionnalites de typage statique. Les types sont verifies pendant la compilation (statiquement) au lieu de la phase d’execution (dynamique).
Les types de base TypeScript
Avant de plonger dans l’integration avec Vue, maitrisons les types fondamentaux de TypeScript.
Types primitifs
// String - chaines de caracteres
const name: string = 'Mahmoud';
const greeting: string = `Bonjour, ${name}`;
// Number - nombres (entiers et decimaux)
const age: number = 30;
const price: number = 19.99;
const hex: number = 0xf00d;
// Boolean - valeurs booleennes
const isActive: boolean = true;
const hasPermission: boolean = false;
// Null et Undefined
const nullValue: null = null;
const undefinedValue: undefined = undefined;
// Symbol (ES6)
const uniqueKey: symbol = Symbol('key');
// BigInt (grands nombres)
const bigNumber: bigint = 9007199254740991n;
Types complexes : Arrays
// Tableau de nombres - deux syntaxes equivalentes
const numbers: number[] = [1, 2, 3, 4, 5];
const scores: Array<number> = [98, 85, 92];
// Tableau de chaines
const fruits: string[] = ['pomme', 'banane', 'orange'];
// Tableau d'objets
interface Product {
id: number;
name: string;
price: number;
}
const products: Product[] = [
{ id: 1, name: 'Laptop', price: 999 },
{ id: 2, name: 'Mouse', price: 29 }
];
// Tableau mixte avec tuple
const tuple: [string, number, boolean] = ['test', 42, true];
Types complexes : Objects
// Objet simple avec type inline
const user: { name: string; age: number } = {
name: 'Alice',
age: 25
};
// Objet avec proprietes optionnelles
const config: {
host: string;
port: number;
ssl?: boolean; // optionnel
} = {
host: 'localhost',
port: 3000
// ssl est optionnel, pas besoin de le definir
};
// Record pour les objets dynamiques
const userRoles: Record<string, string[]> = {
admin: ['read', 'write', 'delete'],
editor: ['read', 'write'],
viewer: ['read']
};
Interfaces et Types personnalises
Les interfaces et les types personnalises sont essentiels pour definir des structures de donnees complexes dans vos applications Vue.
Interfaces
// Interface de base
interface User {
id: number;
username: string;
email: string;
createdAt: Date;
}
// Interface avec proprietes optionnelles et readonly
interface UserProfile extends User {
readonly id: number; // ne peut pas etre modifie
avatar?: string; // optionnel
bio?: string;
socialLinks?: {
twitter?: string;
github?: string;
linkedin?: string;
};
}
// Interface pour les fonctions
interface Validator {
(value: string): boolean;
}
const emailValidator: Validator = (value) => {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
};
// Interface generique
interface ApiResponse<T> {
data: T;
status: number;
message: string;
timestamp: Date;
}
// Utilisation
const userResponse: ApiResponse<User> = {
data: { id: 1, username: 'john', email: 'john@example.com', createdAt: new Date() },
status: 200,
message: 'Success',
timestamp: new Date()
};
Types avec type alias
// Type alias simple
type ID = number | string;
// Union types
type Status = 'pending' | 'active' | 'completed' | 'cancelled';
// Type conditionnel
type Nullable<T> = T | null;
// Type avec intersection
type Employee = User & {
department: string;
salary: number;
hireDate: Date;
};
// Type pour les evenements Vue
type EventPayload = {
type: string;
target: HTMLElement;
data?: unknown;
};
// Type utilitaire : Partial (toutes les proprietes optionnelles)
type PartialUser = Partial<User>;
// Type utilitaire : Pick (selection de proprietes)
type UserCredentials = Pick<User, 'email' | 'username'>;
// Type utilitaire : Omit (exclusion de proprietes)
type PublicUser = Omit<User, 'email' | 'createdAt'>;
Quand utiliser Interface vs Type ?
| Caracteristique | Interface | Type |
|---|---|---|
| Extension | extends | & (intersection) |
| Declaration fusionnee | Oui | Non |
| Union types | Non | Oui |
| Tuples | Non | Oui |
| Primitifs | Non | Oui |
Recommandation : Utilisez interface pour les objets et les classes, type pour les unions, les tuples et les types complexes.
Typage de ref() et reactive()
La Composition API de Vue 3 offre deux methodes principales pour creer des donnees reactives : ref() et reactive(). Voyons comment les typer correctement.
Typage de ref()
import { ref, Ref } from 'vue';
// Inference automatique - TypeScript deduit le type
const count = ref(0); // Ref<number>
const message = ref('Hello'); // Ref<string>
const isVisible = ref(true); // Ref<boolean>
// Typage explicite - recommande pour les types complexes
const user = ref<User | null>(null);
const items = ref<Product[]>([]);
// Typage avec interface
interface FormData {
username: string;
email: string;
password: string;
rememberMe: boolean;
}
const formData = ref<FormData>({
username: '',
email: '',
password: '',
rememberMe: false
});
// Acces a la valeur (TypeScript connait le type)
console.log(formData.value.username); // string
formData.value.email = 'test@example.com'; // OK
formData.value.invalidProp = 'test'; // Erreur TypeScript !
Typage de reactive()
import { reactive } from 'vue';
// Inference automatique
const state = reactive({
count: 0,
message: 'Hello'
});
// Typage explicite avec interface
interface AppState {
user: User | null;
isAuthenticated: boolean;
notifications: Notification[];
theme: 'light' | 'dark';
}
const appState = reactive<AppState>({
user: null,
isAuthenticated: false,
notifications: [],
theme: 'light'
});
// Acces direct (pas de .value avec reactive)
appState.isAuthenticated = true;
appState.theme = 'dark';
appState.theme = 'invalid'; // Erreur : 'invalid' n'est pas assignable a 'light' | 'dark'
// Pattern recommande : definir l'interface separement
interface CartState {
items: CartItem[];
total: number;
couponCode: string | null;
isLoading: boolean;
}
interface CartItem {
productId: number;
quantity: number;
price: number;
}
const cart = reactive<CartState>({
items: [],
total: 0,
couponCode: null,
isLoading: false
});
Difference entre ref et reactive
// ref : pour les valeurs primitives et les references
const count = ref(0);
count.value++; // Acces via .value
// reactive : pour les objets complexes
const state = reactive({ count: 0 });
state.count++; // Acces direct
// Attention : reactive perd la reactivite si destructure
const { count } = reactive({ count: 0 }); // count n'est plus reactif !
// Solution : utiliser toRefs
import { toRefs } from 'vue';
const state = reactive({ count: 0, name: 'test' });
const { count, name } = toRefs(state); // Maintenant reactif !
Typage des computed et watch
Les proprietes calculees et les observateurs sont des elements cles de la reactivite Vue. Voici comment les typer correctement.
Typage de computed()
import { ref, computed, ComputedRef } from 'vue';
// Computed simple - inference automatique
const firstName = ref('John');
const lastName = ref('Doe');
const fullName = computed(() => `${firstName.value} ${lastName.value}`);
// Type infere : ComputedRef<string>
// Computed avec typage explicite
const items = ref<Product[]>([]);
const totalPrice: ComputedRef<number> = computed(() => {
return items.value.reduce((sum, item) => sum + item.price, 0);
});
// Computed avec getter et setter
const selectedId = ref<number | null>(null);
const users = ref<User[]>([]);
const selectedUser = computed<User | undefined>({
get: () => users.value.find(u => u.id === selectedId.value),
set: (user) => {
selectedId.value = user?.id ?? null;
}
});
// Computed avec type complexe
interface FilteredResult {
items: Product[];
count: number;
hasMore: boolean;
}
const searchQuery = ref('');
const filteredProducts = computed<FilteredResult>(() => {
const filtered = items.value.filter(item =>
item.name.toLowerCase().includes(searchQuery.value.toLowerCase())
);
return {
items: filtered.slice(0, 10),
count: filtered.length,
hasMore: filtered.length > 10
};
});
Typage de watch()
import { ref, watch, WatchStopHandle } from 'vue';
// Watch simple
const searchQuery = ref('');
watch(searchQuery, (newValue, oldValue) => {
// newValue et oldValue sont types comme string
console.log(`Query changed from "${oldValue}" to "${newValue}"`);
});
// Watch avec options
const userId = ref<number | null>(null);
watch(
userId,
async (newId, oldId) => {
if (newId !== null) {
// Logique de chargement
await loadUserData(newId);
}
},
{
immediate: true, // Execute immediatement
deep: false // Pas de surveillance profonde
}
);
// Watch multiple sources
const page = ref(1);
const perPage = ref(10);
watch(
[page, perPage],
([newPage, newPerPage], [oldPage, oldPerPage]) => {
// Types : [number, number]
console.log(`Page: ${oldPage} -> ${newPage}`);
console.log(`Per page: ${oldPerPage} -> ${newPerPage}`);
}
);
// Watch avec objet reactif
interface Filters {
category: string;
minPrice: number;
maxPrice: number;
inStock: boolean;
}
const filters = reactive<Filters>({
category: 'all',
minPrice: 0,
maxPrice: 1000,
inStock: true
});
watch(
() => ({ ...filters }), // Copie pour detecter les changements
(newFilters, oldFilters) => {
// newFilters et oldFilters sont types comme Filters
applyFilters(newFilters);
},
{ deep: true }
);
// Stopper un watcher
const stopWatch: WatchStopHandle = watch(searchQuery, () => {
// ...
});
// Plus tard, arreter la surveillance
stopWatch();
watchEffect()
import { ref, watchEffect, WatchStopHandle } from 'vue';
const userId = ref<number | null>(null);
const userData = ref<User | null>(null);
// watchEffect detecte automatiquement les dependances
const stop: WatchStopHandle = watchEffect(async (onCleanup) => {
if (userId.value === null) {
userData.value = null;
return;
}
const controller = new AbortController();
onCleanup(() => {
controller.abort(); // Annuler la requete si le watcher est relance
});
try {
const response = await fetch(`/api/users/${userId.value}`, {
signal: controller.signal
});
userData.value = await response.json();
} catch (error) {
if (error instanceof Error && error.name !== 'AbortError') {
console.error('Failed to fetch user:', error);
}
}
});
Typage des Props et Emits
Le typage des props et des emits est crucial pour creer des composants robustes et reutilisables.
defineProps() avec typage
<script setup lang="ts">
// Methode 1 : Typage avec generique (recommande)
interface Props {
title: string;
count?: number;
items: string[];
user: User | null;
variant?: 'primary' | 'secondary' | 'danger';
}
const props = defineProps<Props>();
// Acces aux props
console.log(props.title); // string
console.log(props.count); // number | undefined
console.log(props.items); // string[]
console.log(props.variant); // 'primary' | 'secondary' | 'danger' | undefined
// Methode 2 : Avec valeurs par defaut (withDefaults)
interface PropsWithDefaults {
title: string;
count?: number;
variant?: 'primary' | 'secondary' | 'danger';
disabled?: boolean;
}
const props = withDefaults(defineProps<PropsWithDefaults>(), {
count: 0,
variant: 'primary',
disabled: false
});
// Maintenant props.count est number (pas number | undefined)
console.log(props.count); // number
</script>
defineEmits() avec typage
<script setup lang="ts">
// Methode 1 : Typage avec interface
interface Emits {
(event: 'update', value: string): void;
(event: 'submit', data: FormData): void;
(event: 'close'): void;
(event: 'error', message: string, code: number): void;
}
const emit = defineEmits<Emits>();
// Utilisation
emit('update', 'nouvelle valeur'); // OK
emit('submit', formData); // OK
emit('close'); // OK
emit('error', 'Something went wrong', 500); // OK
emit('update', 123); // Erreur : 123 n'est pas une string
// Methode 2 : Syntaxe alternative (Vue 3.3+)
const emit = defineEmits<{
update: [value: string];
submit: [data: FormData];
close: [];
error: [message: string, code: number];
}>();
// Methode 3 : Avec validation runtime
const emit = defineEmits({
update: (value: string) => {
return value.length > 0;
},
submit: (data: FormData) => {
return data !== null;
}
});
</script>
Exemple complet de composant type
<script setup lang="ts">
import { ref, computed, watch } from 'vue';
// Types
interface User {
id: number;
name: string;
email: string;
role: 'admin' | 'user' | 'guest';
}
interface Props {
users: User[];
selectedId?: number | null;
searchable?: boolean;
maxDisplay?: number;
}
interface Emits {
(event: 'select', user: User): void;
(event: 'delete', userId: number): void;
(event: 'search', query: string): void;
}
// Props avec defaults
const props = withDefaults(defineProps<Props>(), {
selectedId: null,
searchable: true,
maxDisplay: 10
});
// Emits
const emit = defineEmits<Emits>();
// State local
const searchQuery = ref('');
const isDropdownOpen = ref(false);
// Computed
const filteredUsers = computed(() => {
let result = props.users;
if (searchQuery.value) {
const query = searchQuery.value.toLowerCase();
result = result.filter(user =>
user.name.toLowerCase().includes(query) ||
user.email.toLowerCase().includes(query)
);
}
return result.slice(0, props.maxDisplay);
});
const selectedUser = computed(() =>
props.users.find(u => u.id === props.selectedId)
);
// Watchers
watch(searchQuery, (newQuery) => {
emit('search', newQuery);
});
// Methods
function handleSelect(user: User): void {
emit('select', user);
isDropdownOpen.value = false;
}
function handleDelete(userId: number): void {
if (confirm('Etes-vous sur de vouloir supprimer cet utilisateur ?')) {
emit('delete', userId);
}
}
</script>
<template>
<div class="user-selector">
<input
v-if="searchable"
v-model="searchQuery"
type="text"
placeholder="Rechercher..."
/>
<ul v-if="filteredUsers.length">
<li
v-for="user in filteredUsers"
:key="user.id"
:class="{ selected: user.id === selectedId }"
@click="handleSelect(user)"
>
{{ user.name }} ({{ user.email }})
<button @click.stop="handleDelete(user.id)">Supprimer</button>
</li>
</ul>
<p v-else>Aucun utilisateur trouve</p>
</div>
</template>
Tableau comparatif JavaScript vs TypeScript
| Aspect | JavaScript | TypeScript |
|---|---|---|
| Typage | Dynamique (runtime) | Statique (compilation) |
| Detection erreurs | A l’execution | A la compilation |
| Autocompletion | Limitee | Complete et precise |
| Refactoring | Risque | Securise |
| Documentation | Commentaires manuels | Types = documentation |
| Courbe d’apprentissage | Facile | Moderee |
| Configuration | Aucune | tsconfig.json |
| Compatibilite | Universelle | Necessite compilation |
| Productivite | Rapide au debut | Rapide a long terme |
| Maintenance | Difficile sur gros projets | Facilitee |
| Taille equipe | Petite equipe OK | Ideal grandes equipes |
| Support IDE | Basique | Excellent |
Configuration du projet Vue + TypeScript
Creation d’un nouveau projet
Pour creer un projet Vue avec TypeScript, vous pouvez utiliser l’outil CLI de Vue. Lorsque vous creez un nouveau projet avec npm create vue@latest, choisissez l’option TypeScript pour activer la compilation TypeScript.
npm create vue@latest my-project
# Selectionnez "Yes" pour TypeScript
# Selectionnez "Yes" pour Vue Router (si necessaire)
# Selectionnez "Yes" pour Pinia (si necessaire)
Configuration tsconfig.json
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"skipLibCheck": true,
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "preserve",
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"paths": {
"@/*": ["./src/*"]
}
},
"include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"],
"references": [{ "path": "./tsconfig.node.json" }]
}
Editeur de code
Nous recommandons d’utiliser Visual Studio Code pour developper votre application TypeScript. Cet editeur fournit une configuration out-of-the-box pour le TypeScript et vous permettra d’utiliser des fonctionnalites comme la prise en charge de l’inference TypeScript.
Installez egalement les extensions suivantes :
- Volar : Extension officielle pour Vue 3 avec support TypeScript complet
- TypeScript Vue Plugin : Integration avancee TypeScript/Vue
- ESLint : Detection des erreurs et warnings dans votre editeur
- Prettier : Formatage automatique du code
Bonnes Pratiques TypeScript avec Vue
1. Toujours definir les interfaces pour les props
// Mauvais - Types inline
const props = defineProps<{
title: string;
items: { id: number; name: string }[];
}>();
// Bon - Interface separee et reutilisable
interface Item {
id: number;
name: string;
}
interface Props {
title: string;
items: Item[];
}
const props = defineProps<Props>();
2. Utiliser des types stricts pour les etats
// Mauvais - Type trop generique
const status = ref<string>('loading');
// Bon - Union type restrictif
type LoadingStatus = 'idle' | 'loading' | 'success' | 'error';
const status = ref<LoadingStatus>('idle');
3. Typer explicitement les refs nullables
// Mauvais - Le type initial peut etre trompeur
const user = ref(null); // Ref<null> - probleme !
// Bon - Type explicite
const user = ref<User | null>(null); // Ref<User | null>
4. Creer des types utilitaires reutilisables
// types/api.ts
export interface ApiResponse<T> {
data: T;
status: number;
message: string;
}
export interface PaginatedResponse<T> extends ApiResponse<T[]> {
meta: {
currentPage: number;
totalPages: number;
totalItems: number;
perPage: number;
};
}
export type AsyncState<T> =
| { status: 'idle' }
| { status: 'loading' }
| { status: 'success'; data: T }
| { status: 'error'; error: string };
5. Utiliser les generiques pour les composables
// composables/useFetch.ts
export function useFetch<T>(url: string) {
const data = ref<T | null>(null);
const error = ref<string | null>(null);
const isLoading = ref(false);
async function execute(): Promise<void> {
isLoading.value = true;
error.value = null;
try {
const response = await fetch(url);
if (!response.ok) throw new Error('Network error');
data.value = await response.json();
} catch (e) {
error.value = e instanceof Error ? e.message : 'Unknown error';
} finally {
isLoading.value = false;
}
}
return { data, error, isLoading, execute };
}
// Utilisation
const { data, isLoading } = useFetch<User[]>('/api/users');
6. Organiser les types dans des fichiers dedies
src/
├── types/
│ ├── index.ts # Re-export tous les types
│ ├── user.ts # Types lies aux utilisateurs
│ ├── product.ts # Types lies aux produits
│ ├── api.ts # Types pour les reponses API
│ └── forms.ts # Types pour les formulaires
├── components/
├── composables/
└── ...
Pieges Courants a Eviter
1. Oublier le typage des refs dans les templates
// Piege : ref.value n'est pas automatiquement type dans les event handlers
const inputRef = ref<HTMLInputElement | null>(null);
// Mauvais - inputRef.value pourrait etre null
function focusInput() {
inputRef.value.focus(); // Erreur potentielle !
}
// Bon - Verification de nullite
function focusInput() {
inputRef.value?.focus();
// ou
if (inputRef.value) {
inputRef.value.focus();
}
}
2. Confusion entre ref et reactive avec le destructuring
// Piege : Perte de reactivite
const state = reactive({ count: 0, name: 'test' });
const { count } = state; // count n'est plus reactif !
count++; // Ne declenche pas de mise a jour
// Solution : Utiliser toRefs
import { toRefs } from 'vue';
const { count, name } = toRefs(state); // Maintenant reactif
count.value++; // Fonctionne correctement
3. Type any trop permissif
// Mauvais - Desactive la verification de type
const data: any = fetchData();
data.whatever.you.want; // Pas d'erreur mais dangereux !
// Bon - Type unknown plus sur
const data: unknown = fetchData();
if (isUser(data)) { // Type guard
console.log(data.name); // Maintenant type comme User
}
4. Ignorer les types de retour des fonctions async
// Mauvais - Type de retour implicite
async function fetchUser(id: number) {
const response = await fetch(`/api/users/${id}`);
return response.json(); // Type: Promise<any>
}
// Bon - Type de retour explicite
async function fetchUser(id: number): Promise<User> {
const response = await fetch(`/api/users/${id}`);
return response.json() as User;
}
5. Mauvaise utilisation des assertions de type
// Mauvais - Assertion sans verification
const user = data as User; // Dangereux si data n'est pas un User
// Bon - Utiliser un type guard
function isUser(obj: unknown): obj is User {
return (
typeof obj === 'object' &&
obj !== null &&
'id' in obj &&
'name' in obj &&
'email' in obj
);
}
if (isUser(data)) {
// data est maintenant type comme User de maniere sure
console.log(data.email);
}
Conclusion
Dans ce guide complet, nous avons explore en profondeur l’integration de TypeScript avec Vue.js et la Composition API. Voici un recapitulatif des points cles a retenir :
Les fondamentaux :
- TypeScript ajoute un typage statique au JavaScript, detectant les erreurs avant l’execution
- Vue 3 est nativement ecrit en TypeScript, garantissant une integration optimale
- Les types de base (string, number, boolean, array, object) forment la fondation du typage
Le typage Vue specifique :
ref<T>()pour les valeurs primitives avec acces via.valuereactive<T>()pour les objets complexes avec acces directcomputed<T>()avec inference automatique ou typage explicitewatch()etwatchEffect()pour la surveillance reactive typeedefineProps<T>()etdefineEmits<T>()pour les composants type-safe
Les bonnes pratiques :
- Definir des interfaces reutilisables pour les structures de donnees
- Utiliser des unions types restrictives plutot que des strings generiques
- Creer des composables generiques pour la reutilisabilite
- Organiser les types dans des fichiers dedies
- Toujours verifier les valeurs nullables avant utilisation
Les pieges a eviter :
- Ne pas oublier la perte de reactivite lors du destructuring
- Eviter le type
anyau profit deunknownavec type guards - Toujours typer explicitement les retours de fonctions async
- Preferer les type guards aux assertions de type non securisees
TypeScript avec Vue 3 represente une combinaison puissante pour developper des applications robustes et maintenables. L’investissement initial dans l’apprentissage du typage est largement compense par la reduction des bugs, l’amelioration de la productivite et la facilite de maintenance a long terme.
Nous vous recommandons de commencer par activer le mode strict dans votre configuration TypeScript et d’adopter progressivement les bonnes pratiques presentees dans ce guide. Avec le temps, le typage deviendra naturel et vous ne pourrez plus vous en passer !
N’hesitez pas a partager vos questions ou vos commentaires. Bon developpement avec Vue.js et TypeScript !
In-Article Ad
Dev Mode
Mahmoud DEVO
Senior Full-Stack Developer
I'm a passionate full-stack developer with 10+ years of experience building scalable web applications. I write about Vue.js, Node.js, PostgreSQL, and modern DevOps practices.
Enjoyed this article?
Subscribe to get more tech content delivered to your inbox.
Related Articles
Introduction à la Composition API Vue.js : setup(), ref() et reactive()
Découvrez la Composition API de Vue 3. Maîtrisez setup(), ref() pour les primitives et reactive() pour les objets avec des exemples pratiques.
Introduction a la Composition API Vue.js : Guide Pratique avec Vuex
Apprenez a utiliser la Composition API de Vue 3 pour creer des composants maintenables. Setup, computed, refs et integration Vuex expliques.
Migrer vers la Composition API Vue 3 : Guide Etape par Etape
Migrez vos composants Vue vers la Composition API. useStore, ref, onMounted et lifecycle hooks expliques avec des exemples pratiques.