Ontdek best practices voor het gebruik van TypeScript met React om robuuste, schaalbare en onderhoudbare webapplicaties te bouwen. Leer over projectstructuur, componentontwerp, testen en optimalisatie.
TypeScript met React: Best Practices voor Schaalbare en Onderhoudbare Applicaties
TypeScript en React zijn een krachtige combinatie voor het bouwen van moderne webapplicaties. TypeScript voegt statische typering toe aan JavaScript, wat de codekwaliteit en onderhoudbaarheid verbetert, terwijl React een declaratieve en op componenten gebaseerde aanpak biedt voor het bouwen van gebruikersinterfaces. Deze blogpost verkent best practices voor het gebruik van TypeScript met React om robuuste, schaalbare en onderhoudbare applicaties te creëren die geschikt zijn voor een wereldwijd publiek.
Waarom TypeScript met React gebruiken?
Voordat we ingaan op de best practices, laten we eerst begrijpen waarom TypeScript een waardevolle toevoeging is aan React-ontwikkeling:
- Verbeterde Codekwaliteit: De statische typering van TypeScript helpt fouten vroeg in het ontwikkelingsproces op te sporen, wat runtimeproblemen vermindert en de betrouwbaarheid van de code verbetert.
- Verbeterde Onderhoudbaarheid: Type-annotaties en interfaces maken code gemakkelijker te begrijpen en te refactoren, wat leidt tot betere onderhoudbaarheid op de lange termijn.
- Betere IDE-ondersteuning: TypeScript biedt uitstekende IDE-ondersteuning, inclusief autocompletie, codenavigatie en refactoring-tools, wat de productiviteit van ontwikkelaars verhoogt.
- Minder Bugs: Statische typering vangt veelvoorkomende JavaScript-fouten op voordat ze in runtime optreden, wat leidt tot een stabielere en bug-vrije applicatie.
- Verbeterde Samenwerking: Duidelijke type-definities maken het voor teams gemakkelijker om samen te werken aan grote projecten, omdat ontwikkelaars snel het doel en het gebruik van verschillende componenten en functies kunnen begrijpen.
Een TypeScript React-project opzetten
Create React App gebruiken
De eenvoudigste manier om een nieuw TypeScript React-project te starten is met Create React App en de TypeScript-template:
npx create-react-app my-typescript-react-app --template typescript
Dit commando zet een basis React-project op met TypeScript geconfigureerd, inclusief de benodigde afhankelijkheden en een tsconfig.json
-bestand.
tsconfig.json
configureren
Het tsconfig.json
-bestand is het hart van je TypeScript-configuratie. Hier zijn enkele aanbevolen instellingen:
{
"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,
"noEmit": true,
"jsx": "react-jsx"
},
"include": [
"src"
]
}
Belangrijke opties om te overwegen:
"strict": true
: Schakelt strikte type-checking in, wat sterk wordt aanbevolen om potentiële fouten op te sporen."esModuleInterop": true
: Maakt interoperabiliteit tussen CommonJS en ES-modules mogelijk."jsx": "react-jsx"
: Activeert de nieuwe JSX-transformatie, wat React-code vereenvoudigt en de prestaties verbetert.
Best Practices voor React-componenten met TypeScript
Component Props typeren
Een van de belangrijkste aspecten van het gebruik van TypeScript met React is het correct typeren van je component props. Gebruik interfaces of type-aliassen om de vorm van het props-object te definiëren.
interface MyComponentProps {
name: string;
age?: number; // Optionele prop
onClick: () => void;
}
const MyComponent: React.FC = ({ name, age, onClick }) => {
return (
Hallo, {name}!
{age && Je bent {age} jaar oud.
}
);
};
Het gebruik van React.FC<MyComponentProps>
zorgt ervoor dat het component een functioneel component is en dat de props correct getypeerd zijn.
Component State typeren
Als je class-componenten gebruikt, moet je ook de state van het component typeren. Definieer een interface of type-alias voor het state-object en gebruik deze in de componentdefinitie.
interface MyComponentState {
count: number;
}
class MyComponent extends React.Component<{}, MyComponentState> {
state: MyComponentState = {
count: 0
};
handleClick = () => {
this.setState({
count: this.state.count + 1
});
};
render() {
return (
Aantal: {this.state.count}
);
}
}
Voor functionele componenten die de useState
-hook gebruiken, kan TypeScript vaak het type van de state-variabele afleiden, maar je kunt het ook expliciet opgeven:
import React, { useState } from 'react';
const MyComponent: React.FC = () => {
const [count, setCount] = useState(0);
return (
Aantal: {count}
);
};
Type Guards gebruiken
Type guards zijn functies die het type van een variabele binnen een specifieke scope verfijnen. Ze zijn nuttig bij het omgaan met union-types of wanneer je moet verzekeren dat een variabele een specifiek type heeft voordat je een operatie uitvoert.
interface Circle {
kind: "circle";
radius: number;
}
interface Square {
kind: "square";
side: number;
}
type Shape = Circle | Square;
function isCircle(shape: Shape): shape is Circle {
return shape.kind === "circle";
}
function getArea(shape: Shape): number {
if (isCircle(shape)) {
return Math.PI * shape.radius ** 2;
} else {
return shape.side ** 2;
}
}
De isCircle
-functie is een type guard die controleert of een Shape
een Circle
is. Binnen het if
-blok weet TypeScript dat shape
een Circle
is en staat het je toe om de radius
-eigenschap te benaderen.
Events afhandelen
Bij het afhandelen van events in React met TypeScript is het belangrijk om het event-object correct te typeren. Gebruik het juiste event-type uit de React
-namespace.
const MyComponent: React.FC = () => {
const handleChange = (event: React.ChangeEvent) => {
console.log(event.target.value);
};
return (
);
};
In dit voorbeeld wordt React.ChangeEvent<HTMLInputElement>
gebruikt om het event-object voor een change-event op een input-element te typeren. Dit geeft toegang tot de target
-eigenschap, wat een HTMLInputElement
is.
Projectstructuur
Een goed gestructureerd project is cruciaal voor onderhoudbaarheid en schaalbaarheid. Hier is een voorgestelde projectstructuur voor een TypeScript React-applicatie:
src/
├── components/
│ ├── MyComponent/
│ │ ├── MyComponent.tsx
│ │ ├── MyComponent.module.css
│ │ └── index.ts
├── pages/
│ ├── HomePage.tsx
│ └── AboutPage.tsx
├── services/
│ ├── api.ts
│ └── auth.ts
├── types/
│ ├── index.ts
│ └── models.ts
├── utils/
│ ├── helpers.ts
│ └── constants.ts
├── App.tsx
├── index.tsx
├── react-app-env.d.ts
└── tsconfig.json
Kernpunten:
- Componenten: Groepeer gerelateerde componenten in mappen. Elke map moet het TypeScript-bestand van het component, CSS-modules (indien gebruikt) en een
index.ts
-bestand voor het exporteren van het component bevatten. - Pagina's: Sla hier top-level componenten op die verschillende pagina's van je applicatie vertegenwoordigen.
- Services: Implementeer API-aanroepen en andere services in deze map.
- Types: Definieer globale type-definities en interfaces in deze map.
- Utils: Sla hulpfuncties en constanten op.
- index.ts: Gebruik
index.ts
-bestanden om modules opnieuw te exporteren vanuit een map, wat zorgt voor een schone en georganiseerde API voor het importeren van modules.
Hooks gebruiken met TypeScript
Met React Hooks kun je state en andere React-functies gebruiken in functionele componenten. TypeScript werkt naadloos samen met Hooks, wat zorgt voor typeveiligheid en een verbeterde ontwikkelaarservaring.
useState
Zoals eerder getoond, kun je de state-variabele expliciet typeren bij gebruik van useState
:
import React, { useState } from 'react';
const MyComponent: React.FC = () => {
const [count, setCount] = useState(0);
return (
Aantal: {count}
);
};
useEffect
Wanneer je useEffect
gebruikt, let dan op de dependency array. TypeScript kan je helpen fouten op te sporen als je vergeet een afhankelijkheid op te nemen die binnen het effect wordt gebruikt.
import React, { useState, useEffect } from 'react';
const MyComponent: React.FC = () => {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `Aantal: ${count}`;
}, [count]); // Voeg 'count' toe aan de dependency array
return (
Aantal: {count}
);
};
Als je count
weglaat uit de dependency array, zal het effect slechts één keer worden uitgevoerd wanneer het component wordt gemount, en zal de documenttitel niet worden bijgewerkt wanneer de count verandert. TypeScript zal je waarschuwen voor dit potentiële probleem.
useContext
Bij het gebruik van useContext
moet je een type opgeven voor de contextwaarde.
import React, { createContext, useContext } from 'react';
interface ThemeContextType {
theme: string;
toggleTheme: () => void;
}
const ThemeContext = createContext(undefined);
const ThemeProvider: React.FC = ({ children }) => {
// Implementeer hier de themalogica
return (
{} }}>
{children}
);
};
const MyComponent: React.FC = () => {
const { theme, toggleTheme } = useContext(ThemeContext) as ThemeContextType;
return (
Thema: {theme}
);
};
export { ThemeProvider, MyComponent };
Door een type voor de contextwaarde op te geven, zorg je ervoor dat de useContext
-hook een waarde met het juiste type retourneert.
TypeScript React-componenten testen
Testen is een essentieel onderdeel van het bouwen van robuuste applicaties. TypeScript verbetert het testen door typeveiligheid en een betere codedekking te bieden.
Unit Testing
Gebruik testframeworks zoals Jest en React Testing Library om je componenten te unit-testen.
// MyComponent.test.tsx
import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import MyComponent from './MyComponent';
describe('MyComponent', () => {
it('rendert het component met de juiste naam', () => {
render( );
expect(screen.getByText('Hallo, John!')).toBeInTheDocument();
});
it('roept de onClick-handler aan wanneer op de knop wordt geklikt', () => {
const onClick = jest.fn();
render( );
fireEvent.click(screen.getByRole('button'));
expect(onClick).toHaveBeenCalledTimes(1);
});
});
De type-checking van TypeScript helpt bij het opsporen van fouten in je tests, zoals het doorgeven van onjuiste props of het gebruiken van de verkeerde event handlers.
Integratietesten
Integratietests verifiëren dat verschillende delen van je applicatie correct samenwerken. Gebruik tools zoals Cypress of Playwright voor end-to-end testen.
Prestatieoptimalisatie
TypeScript kan ook helpen bij prestatieoptimalisatie door potentiële prestatieknelpunten vroeg in het ontwikkelingsproces op te sporen.
Memoization
Gebruik React.memo
om functionele componenten te memoïzeren en onnodige re-renders te voorkomen.
import React from 'react';
interface MyComponentProps {
name: string;
}
const MyComponent: React.FC = ({ name }) => {
console.log('Rendering MyComponent');
return (
Hallo, {name}!
);
};
export default React.memo(MyComponent);
React.memo
zal het component alleen opnieuw renderen als de props zijn gewijzigd. Dit kan de prestaties aanzienlijk verbeteren, vooral bij complexe componenten.
Code Splitting
Gebruik dynamische imports om je code op te splitsen in kleinere chunks en deze op aanvraag te laden. Dit kan de initiële laadtijd van je applicatie verminderen.
import React, { Suspense } from 'react';
const MyComponent = React.lazy(() => import('./MyComponent'));
const App: React.FC = () => {
return (
Laden...
React.lazy
stelt je in staat om componenten dynamisch te importeren, die alleen worden geladen wanneer ze nodig zijn. Het Suspense
-component biedt een fallback-UI terwijl het component laadt.
Conclusie
Het gebruik van TypeScript met React kan de kwaliteit, onderhoudbaarheid en schaalbaarheid van je webapplicaties aanzienlijk verbeteren. Door deze best practices te volgen, kun je de kracht van TypeScript benutten om robuuste en performante applicaties te bouwen die voldoen aan de behoeften van een wereldwijd publiek. Vergeet niet te focussen op duidelijke type-definities, een goed gestructureerde projectorganisatie en grondig testen om het succes van je projecten op lange termijn te verzekeren.