Pourquoi Next.js avec TypeScript : guide complet ?
La croissance rapide des applications web nécessite une meilleure gestion du code et de l'interface utilisateur. En utilisant Next.js avec TypeScript, vous pouvez écrire une application plus robuste, éviter les erreurs à la compilation et bénéficier d'une meilleure type-sécurité.
Un cas concret : Vous travaillez sur un e-commerce en ligne et vous avez besoin d'un backend performant pour gérer les commandes, le stockage des produits et l'authentification des utilisateurs. TypeScript peut aider à prévenir les bugs potentiels et à améliorer la performance globale de votre application.
Prerequis
- Connaissance approfondie de JavaScript
- Familiarité avec React.js (conseillé)
- Installation de Node.js v14 ou supérieure
- Yarn ou npm pour gérer les dépendances
- Visual Studio Code (VSCode) avec l'extension ESLint et Prettier
Concepts fondamentaux
1. Création d'un projet Next.js avec TypeScript
Tout d'abord, vous devrez installer le CLI de Next.js et créer un nouveau projet :
npx create-next-app@latest my-next-ts-app --typescript
Cela va créer un répertoire appelé my-next-ts-app avec les fichiers nécessaires pour une application Next.js en utilisant TypeScript.
2. Comprendre le fichier tsconfig.json
Ce fichier est crucial pour la configuration de TypeScript dans votre projet Next.js. Voici un exemple du contenu par défaut :
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve"
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
"exclude": ["node_modules"]
}
Ce fichier est généralement correct pour la plupart des projets, mais vous pouvez le modifier en fonction de vos besoins spécifiques.
3. Utilisation des composants React avec TypeScript
Créons un composant simple utilisant TypeScript :
// src/components/HelloWorld.tsx
import { FC } from 'react';
interface HelloWorldProps {
name: string;
}
const HelloWorld: FC<HelloWorldProps> = ({ name }) => (
<h1>Hello, {name}!</h1>
);
export default HelloWorld;
Dans ce code, nous définissons une interface HelloWorldProps pour spécifier les props attendues par le composant. Ensuite, nous utilisons cette interface comme type générique pour notre composant.
4. Utilisation des hooks React avec TypeScript
Les hooks de React peuvent être utilisés avec TypeScript en spécifiant leurs types de retour :
// src/hooks/useCounter.tsx
import { useState } from 'react';
interface UseCounterReturn {
count: number;
increment: () => void;
}
const useCounter = (): UseCounterReturn => {
const [count, setCount] = useState(0);
const increment = () => {
setCount(count + 1);
};
return { count, increment };
};
export default useCounter;
Dans ce code, nous définissons une interface UseCounterReturn pour spécifier le type de retour du hook. Ensuite, nous utilisons cette interface pour déclarer les types des variables et fonctions retournées par le hook.
5. Configuration de l'API Next.js avec TypeScript
Pour utiliser la fonctionnalité API de Next.js, vous pouvez créer des fichiers .ts ou .tsx dans le répertoire pages/api :
// pages/api/hello.tsx
import type { NextApiRequest, NextApiResponse } from 'next';
export default function handler(
req: NextApiRequest,
res: NextApiResponse
) {
if (req.method === 'POST') {
const data = JSON.parse(req.body);
return res.status(200).json({ message: 'Received POST request', data });
} else {
return res.status(405).json({ message: 'Method not allowed' });
}
}
Dans ce code, nous utilisons le type NextApiRequest et NextApiResponse pour spécifier les types des paramètres du handler de l'API.
Mise en pratique : projet fil rouge
Étape 1 : Création d'une application Next.js avec TypeScript
Commencez par créer un nouveau projet Next.js avec TypeScript :
npx create-next-app@latest my-todo-app --typescript
cd my-todo-app
Étape 2 : Création d'un composant de tâche
Créons un composant TodoItem.tsx pour afficher une tâche individuelle :
// src/components/TodoItem.tsx
import { FC } from 'react';
interface TodoItemProps {
todo: { id: number; text: string };
}
const TodoItem: FC<TodoItemProps> = ({ todo }) => (
<li>
{todo.text}
</li>
);
export default TodoItem;
Étape 3 : Création d'un composant de liste de tâches
Créons un composant TodoList.tsx pour afficher la liste complète des tâches :
// src/components/TodoList.tsx
import { FC } from 'react';
import TodoItem from './TodoItem';
interface TodoListProps {
todos: { id: number; text: string }[];
}
const TodoList: FC<TodoListProps> = ({ todos }) => (
<ul>
{todos.map(todo => (
<TodoItem key={todo.id} todo={todo} />
))}
</ul>
);
export default TodoList;
Étape 4 : Création d'un composant de formulaire pour ajouter des tâches
Créons un composant AddTodoForm.tsx pour permettre l'ajout de nouvelles tâches :
// src/components/AddTodoForm.tsx
import { FC, useState } from 'react';
interface AddTodoFormProps {
onAdd: (text: string) => void;
}
const AddTodoForm: FC<AddTodoFormProps> = ({ onAdd }) => {
const [inputValue, setInputValue] = useState('');
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
if (inputValue.trim() !== '') {
onAdd(inputValue);
setInputValue('');
}
};
return (
<form onSubmit={handleSubmit}>
<input
type="text"
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
placeholder="Add a new task"
/>
<button type="submit">Add</button>
</form>
);
};
export default AddTodoForm;
Étape 5 : Intégration des composants dans la page
Enfin, intégrez ces composants dans la page index.tsx :
// pages/index.tsx
import { useState } from 'react';
import TodoList from '../components/TodoList';
import AddTodoForm from '../components/AddTodoForm';
const Home: FC = () => {
const [todos, setTodos] = useState<{ id: number; text: string }[]>([]);
const handleAddTodo = (text: string) => {
setTodos([...todos, { id: todos.length + 1, text }]);
};
return (
<div>
<h1>Todo App</h1>
<AddTodoForm onAdd={handleAddTodo} />
<TodoList todos={todos} />
</div>
);
};
export default Home;
Étape 6 : Test de l'application
Exécutez votre application et vérifiez qu'elle fonctionne correctement :
npm run dev
Ouvrez votre navigateur et accédez à http://localhost:3000. Vous devriez voir une interface simple avec un formulaire pour ajouter des tâches et une liste qui affiche les tâches ajoutées.
Erreurs frequentes et debugging
1. Erreur : Type 'string' is not assignable to type 'never'
Cette erreur peut survenir si vous utilisez incorrectement l'opérateur de type as :
// ❌ Mauvais
const id = '123' as number;
Pour corriger cette erreur, assurez-vous que le type est correct :
// ✅ Correct
const id = parseInt('123', 10) as number;
2. Erreur : Type error in props of component 'MyComponent'
Si vous avez une erreur de type dans les props d'un composant, vérifiez la signature des props :
// ❌ Mauvais
interface MyComponentProps {
name: string;
}
const MyComponent: FC<MyComponentProps> = ({ name }) => (
<div>{name.toUpperCase()}</div>
);
Pour corriger cette erreur, ajoutez une validation de type avec React.Validator :
// ✅ Correct
import React from 'react';
interface MyComponentProps {
name: string;
}
const MyComponent: FC<MyComponentProps> = ({ name }) => (
<div>{name.toUpperCase()}</div>
);
MyComponent.propTypes = {
name: React.PropTypes.string.isRequired,
};
3. Erreur : Property 'map' does not exist on type 'never'
Cette erreur peut survenir si vous utilisez incorrectement l'opérateur de type as :
// ❌ Mauvais
const items = ['a', 'b', 'c'] as never[];
Pour corriger cette erreur, assurez-vous que le type est correct :
// ✅ Correct
const items = ['a', 'b', 'c'] as string[];
Pour aller plus loin
1. Utilisation de TypeScript avec Next.js API routes
Vous pouvez créer des fichiers .ts ou .tsx dans le répertoire pages/api pour créer des routes API en utilisant TypeScript :
// pages/api/hello.tsx
import type { NextApiRequest, NextApiResponse } from 'next';
export default function handler(
req: NextApiRequest,
res: NextApiResponse
) {
if (req.method === 'POST') {
const data = JSON.parse(req.body);
return res.status(200).json({ message: 'Received POST request', data });
} else {
return res.status(405).json({ message: 'Method not allowed' });
}
}
2. Utilisation de TypeScript avec Next.js Static Generation
Vous pouvez créer des fichiers .ts ou .tsx dans le répertoire pages pour générer statiquement des pages en utilisant TypeScript :
// pages/posts/[id].tsx
import type { GetStaticProps, GetStaticPaths } from 'next';
interface Post {
id: number;
title: string;
content: string;
}
const Post: FC<{ post: Post }> = ({ post }) => (
<div>
<h1>{post.title}</h1>
<p>{post.content}</p>
</div>
);
export default Post;
export const getStaticPaths: GetStaticPaths = async () => {
// Fetch your list of posts
const posts = await fetchPosts();
return {
paths: posts.map(post => ({ params: { id: post.id.toString() } })),
fallback: false,
};
};
export const getStaticProps: GetStaticProps<{ post: Post }> = async ({ params }) => {
// Fetch the specific post
const post = await fetchPostById(params.id as string);
return {
props: { post },
};
};
3. Utilisation de TypeScript avec Next.js Serverless Functions
Vous pouvez créer des fichiers .ts ou .tsx dans le répertoire pages/api pour créer des fonctions serveurless en utilisant TypeScript :
// pages/api/hello.tsx
import type { NextApiRequest, NextApiResponse } from 'next';
export default function handler(
req: NextApiRequest,
res: NextApiResponse
) {
if (req.method === 'POST') {
const data = JSON.parse(req.body);
return res.status(200).json({ message: 'Received POST request', data });
} else {
return res.status(405).json({ message: 'Method not allowed' });
}
}
Défi pratique
Créez une application Next.js avec TypeScript pour un gestionnaire de notes. L'application devrait permettre d'afficher une liste de notes, d'ajouter de nouvelles notes et de supprimer des notes existantes.
- Créez un composant
Note.tsxpour afficher une note individuelle. - Créez un composant
NoteList.tsxpour afficher la liste complète des notes. - Créez un composant
AddNoteForm.tsxpour permettre l'ajout de nouvelles notes. - Créez un composant
DeleteNoteButton.tsxpour permettre la suppression de notes existantes. - Intégrez ces composants dans la page
index.tsx. - Ajoutez des fonctionnalités de gestion du statut (complétées/à faire) pour chaque note.
Bonne chance avec votre défi ! N'hésitez pas à demander de l'aide si vous en avez besoin.