Pourquoi Nuxt avec TypeScript : guide complet ?
Au quotidien, un développeur backend ou frontend peut être confronté à des projets qui nécessitent une gestion plus complexe et robuste des données et de la logique métier. L'utilisation de TypeScript avec Nuxt.js offre plusieurs avantages notables :
- Type Safety : TypeScript ajoute un niveau supplémentaire de sécurité en vérifiant les types à la compilation, ce qui réduit le nombre d'erreurs runtime.
- IntelliSense et Autocomplétion : L'utilisation des fichiers
.tsau lieu de.jspermet une meilleure assistance du code avec des suggestions et autocomplétions intelligentes. - Maintenance Facile : Le type système aide à maintenir le code propre, réduisant les erreurs humaines et rendant la maintenance plus facile.
- Ecosystem Actif : Nuxt.js a un grand écosystème actif et une communauté engagée qui contribue à l'ajout de plugins, modules et autres outils utiles.
Un cas concret d'utilisation serait le développement d'une application web moderne nécessitant une gestion complexe des états (state management) et des interactions avec une base de données. Nuxt.js avec TypeScript pourrait être idéal pour ce type de projet, offrant un environnement de développement robuste et sécurisé.
Prerequis
Connaissances requises :
- JavaScript ES6+
- Vue.js
- Typescript
- Connaissance de l'architecture Nuxt.js
- Familiarité avec les outils de gestion de projet (npm, yarn)
Outils à installer :
- Node.js (v14.0+)
- npm (v6.0+)
- Yarn (v1.22+)
Concepts fondamentaux
1. Typescript dans Nuxt.js
Nuxt.js est un cadre basé sur Vue.js qui offre une structure optimale pour les applications web. En utilisant TypeScript, vous pouvez ajouter des types à vos composants Vue, pages et plugins.
// pages/index.ts
<template>
<h1>message</h1>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({
data() {
return {
message: 'Hello Nuxt with TypeScript' as string,
};
},
});
</script>
2. Type Inference
TypeScript est capable d'inferer le type des variables et des propriétés sans l'affecter explicitement.
// utils/string.ts
export function reverseString(str: string): string {
return str.split('').reverse().join('');
}
3. Types de données complexes
Pour gérer des données complexes, vous pouvez définir des interfaces et des types.
// models/user.ts
export interface User {
id: number;
name: string;
email: string;
}
// stores/userStore.ts
import { defineStore } from 'pinia';
import { User } from '../models/user';
interface State {
users: User[];
}
export const useUserStore = defineStore('user', {
state: (): State => ({
users: [],
}),
actions: {
addUser(user: User) {
this.users.push(user);
},
},
});
4. Middleware
Les middleware en TypeScript permettent d'ajouter du comportement avant ou après les requêtes entrantes.
// middleware/auth.ts
import { defineNuxtRouteMiddleware } from '#app';
export default defineNuxtRouteMiddleware((to, from) => {
const user = useUserStore();
if (!user.isAuthenticated) {
return navigateTo('/login');
}
});
5. Hooks
Les hooks en TypeScript permettent d'ajouter du comportement à des événements spécifiques.
// hooks/useFetch.ts
import { ref, onMounted } from 'vue';
import axios from 'axios';
export function useFetch<T>(url: string) {
const data = ref<T | null>(null);
const error = ref<string | null>(null);
onMounted(async () => {
try {
const response = await axios.get(url);
data.value = response.data;
} catch (err) {
error.value = err.message;
}
});
return { data, error };
}
Mise en pratique : projet fil rouge
Étape 1 : Création du projet Nuxt.js avec TypeScript
Commencez par créer un nouveau projet Nuxt.js avec TypeScript.
npx nuxi init my-nuxt-ts-project --template typescript
cd my-nuxt-ts-project
npm install
Étape 2 : Configuration de l'environnement
Assurez-vous que le fichier tsconfig.json est correctement configuré pour votre projet.
{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"strict": true,
"jsx": "preserve",
"importHelpers": true,
"moduleResolution": "node",
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"sourceMap": true,
"baseUrl": ".",
"types": [
"webpack-env"
],
"paths": {
"@/*": [
"src/*"
]
},
"lib": [
"esnext",
"dom",
"dom.iterable",
"scripthost"
]
},
"include": [
"src/**/*.ts",
"src/**/*.tsx",
"src/**/*.vue"
],
"exclude": [
"node_modules"
]
}
Étape 3 : Création d'une page avec des types
Créez une nouvelle page pages/index.ts et ajoutez un type pour le composant.
// pages/index.ts
<template>
<div>
<h1>message</h1>
<button @click="increment">Click me</button>
<p>Count: count</p>
</div>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
export default defineComponent({
data() {
return {
message: 'Hello Nuxt with TypeScript' as string,
count: ref(0) as Ref<number>,
};
},
methods: {
increment() {
this.count.value++;
},
},
});
</script>
Étape 4 : Utilisation du type système
Créez un service pour gérer des données.
// services/dataService.ts
import axios from 'axios';
interface User {
id: number;
name: string;
email: string;
}
export async function getUsers(): Promise<User[]> {
const response = await axios.get('https://jsonplaceholder.typicode.com/users');
return response.data as User[];
}
Étape 5 : Utilisation des services dans une page
Utilisez le service dans une page pour récupérer et afficher les données.
// pages/users/index.ts
<template>
<div>
<h1>Users</h1>
<ul v-if="users">
<li v-for="user in users" :key="user.id">user.name</li>
</ul>
<p v-else>Loading...</p>
</div>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
import { getUsers } from '@/services/dataService';
export default defineComponent({
async setup() {
const users = ref<User[] | null>(null);
try {
users.value = await getUsers();
} catch (error) {
console.error('Error fetching users:', error);
}
return { users };
},
});
</script>
Étape 6 : Ajout de middleware pour la protection des routes
Ajoutez un middleware pour protéger les routes qui nécessitent une authentification.
// middleware/auth.ts
import { defineNuxtRouteMiddleware } from '#app';
export default defineNuxtRouteMiddleware((to, from) => {
const user = useUserStore();
if (!user.isAuthenticated) {
return navigateTo('/login');
}
});
Étape 7 : Configuration du middleware dans les routes
Ajoutez le middleware à la page pages/dashboard/index.ts.
// pages/dashboard/index.ts
<template>
<div>
<h1>Dashboard</h1>
<p>Welcome, user.name!</p>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import useUserStore from '@/stores/userStore';
export default defineComponent({
middleware: ['auth'],
setup() {
const user = useUserStore();
return { user };
},
});
</script>
Étape 8 : Création d'un store pour la gestion de l'état
Créez un store pour gérer l'état des utilisateurs.
// stores/userStore.ts
import { defineStore } from 'pinia';
interface State {
isAuthenticated: boolean;
user: any | null;
}
export const useUserStore = defineStore('user', {
state: (): State => ({
isAuthenticated: false,
user: null,
}),
actions: {
login(user) {
this.isAuthenticated = true;
this.user = user;
},
logout() {
this.isAuthenticated = false;
this.user = null;
},
},
});
Erreurs frequentes et debugging
Erreur 1 : Type 'string' is not assignable to type 'number'.
// ❌ Mauvais
const count: number = '5';
// ✅ Correct
const count: number = parseInt('5', 10);
Erreur 2 : Property 'name' does not exist on type '{}'.
// ❌ Mauvais
interface User {
id: number;
}
const user: User = { name: 'John' };
// ✅ Correct
interface User {
id: number;
name?: string;
}
Erreur 3 : No overload matches this call.
// ❌ Mauvais
import axios from 'axios';
async function fetchData(url) {
const response = await axios.get(url);
return response.data;
}
// ✅ Correct
import axios, { AxiosResponse } from 'axios';
interface User {
id: number;
name: string;
}
async function fetchData(url): Promise<User> {
const response: AxiosResponse<User> = await axios.get(url);
return response.data;
}
Pour aller plus loin
- Navigation et Guards : Explorez les guards de navigation pour contrôler l'accès aux routes.
- Plugins personnalisés : Créez des plugins personnalisés pour ajouter des fonctionnalités réutilisables à votre application.
- Test unitaires : Ajoutez des tests unitaires pour vous assurer que votre code fonctionne comme prévu.
Défi pratique
Créez un petit plugin Nuxt.js qui utilise TypeScript pour gérer les logs de l'application. Le plugin devrait permettre de définir différents niveaux de logs (info, warn, error) et d'afficher ces logs dans la console ou sur une interface utilisateur.
Ce guide complet couvre les concepts fondamentaux de Nuxt.js avec TypeScript et met en pratique ces connaissances à travers un projet réel. En suivant ce tutoriel, vous serez prêt à développer des applications robustes et sécurisées utilisant Nuxt.js et TypeScript.