Bästa praxis för TypeScript med React: Bygg robusta, skalbara och underhållsbara webbapplikationer. Fokus på struktur, komponenter, testning och optimering.
TypeScript med React: Bästa praxis för skalbara och underhållsbara applikationer
TypeScript och React är en kraftfull kombination för att bygga moderna webbapplikationer. TypeScript tillför statisk typning till JavaScript, vilket förbättrar kodkvalitet och underhållbarhet, medan React erbjuder ett deklarativt och komponentbaserat tillvägagångssätt för att bygga användargränssnitt. Detta blogginlägg utforskar bästa praxis för att använda TypeScript med React för att skapa robusta, skalbara och underhållsbara applikationer lämpliga för en global publik.
Varför använda TypeScript med React?
Innan vi dyker ner i bästa praxis, låt oss förstå varför TypeScript är ett värdefullt tillskott till React-utveckling:
- Förbättrad kodkvalitet: TypeScript's statiska typning hjälper till att fånga fel tidigt i utvecklingsprocessen, vilket minskar körtidsproblem och förbättrar kodens tillförlitlighet.
- Förbättrad underhållbarhet: Typanteckningar och gränssnitt gör koden lättare att förstå och refaktorisera, vilket leder till bättre långsiktig underhållbarhet.
- Bättre IDE-stöd: TypeScript erbjuder utmärkt IDE-stöd, inklusive autofullständigande, kodnavigering och refaktoriseringsverktyg, vilket ökar utvecklarens produktivitet.
- Minskade buggar: Statisk typning fångar många vanliga JavaScript-fel före körtid, vilket leder till en stabilare och buggfri applikation.
- Förbättrad samarbete: Tydliga typdefinitioner gör det lättare för team att samarbeta i stora projekt, eftersom utvecklare snabbt kan förstå syftet och användningen av olika komponenter och funktioner.
Konfigurera ett TypeScript React-projekt
Använda Create React App
Det enklaste sättet att starta ett nytt TypeScript React-projekt är att använda Create React App med TypeScript-mallen:
npx create-react-app my-typescript-react-app --template typescript
Detta kommando sätter upp ett grundläggande React-projekt med TypeScript konfigurerat, inklusive nödvändiga beroenden och en tsconfig.json
-fil.
Konfigurera tsconfig.json
Filen tsconfig.json
är hjärtat i din TypeScript-konfiguration. Här är några rekommenderade inställningar:
{
"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"
]
}
Viktiga alternativ att överväga:
"strict": true
: Aktiverar strikt typkontroll, vilket rekommenderas starkt för att fånga potentiella fel."esModuleInterop": true
: Aktiverar interoperabilitet mellan CommonJS- och ES-moduler."jsx": "react-jsx"
: Aktiverar den nya JSX-transformen, vilket förenklar React-kod och förbättrar prestanda.
Bästa praxis för React-komponenter med TypeScript
Typning av komponentprops
En av de viktigaste aspekterna av att använda TypeScript med React är att korrekt typa dina komponentprops. Använd gränssnitt eller typalias för att definiera formen på props-objektet.
interface MyComponentProps {
name: string;
age?: number; // Optional prop
onClick: () => void;
}
const MyComponent: React.FC<MyComponentProps> = ({ name, age, onClick }) => {
return (
<div>
<p>Hello, {name}!</p>
{age && <p>You are {age} years old.</p>}
<button onClick={onClick}>Click me</button>
</div>
);
};
Användning av React.FC<MyComponentProps>
säkerställer att komponenten är en funktionell komponent och att propsen är korrekt typade.
Typning av komponenttillstånd
Om du använder klasskomponenter måste du också typa komponentens tillstånd. Definiera ett gränssnitt eller typalias för tillståndsobjektet och använd det i komponentdefinitionen.
interface MyComponentState {
count: number;
}
class MyComponent extends React.Component<{}, MyComponentState> {
state: MyComponentState = {
count: 0
};
handleClick = () => {
this.setState({
count: this.state.count + 1
});
};
render() {
return (
<div>
<p>Count: {this.state.count}</p>
<button onClick={this.handleClick}>Increment</button>
</div>
);
}
}
För funktionella komponenter som använder useState
-hooken kan TypeScript ofta härleda typen av tillståndsvariabeln, men du kan också uttryckligen ange den:
import React, { useState } from 'react';
const MyComponent: React.FC = () => {
const [count, setCount] = useState<number>(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
};
Använda typvakter
Typvakter är funktioner som smalnar av typen av en variabel inom ett specifikt omfång. De är användbara när man hanterar unionstyper eller när du behöver säkerställa att en variabel har en specifik typ innan du utför en operation.
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;
}
}
Funktionen isCircle
är en typvakt som kontrollerar om en Shape
är en Circle
. Inom if
-blocket vet TypeScript att shape
är en Circle
och tillåter dig att komma åt dess radius
-egenskap.
Hantera händelser
När du hanterar händelser i React med TypeScript är det viktigt att korrekt typa händelseobjektet. Använd den lämpliga händelsetypen från React
-namnrymden.
const MyComponent: React.FC = () => {
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
console.log(event.target.value);
};
return (
<input type="text" onChange={handleChange} />
);
};
I det här exemplet används React.ChangeEvent<HTMLInputElement>
för att typa händelseobjektet för en ändringshändelse på ett inmatningselement. Detta ger åtkomst till target
-egenskapen, som är ett HTMLInputElement
.
Projektstruktur
En välstrukturerad projekt är avgörande för underhållbarhet och skalbarhet. Här är en föreslagen projektstruktur för en TypeScript React-applikation:
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
Nyckelfrågor:
- Komponenter: Gruppera relaterade komponenter i kataloger. Varje katalog bör innehålla komponentens TypeScript-fil, CSS-moduler (om de används) och en
index.ts
-fil för att exportera komponenten. - Sidor: Lagra komponenter på högsta nivå som representerar olika sidor i din applikation.
- Tjänster: Implementera API-anrop och andra tjänster i den här katalogen.
- Typer: Definiera globala typdefinitioner och gränssnitt i den här katalogen.
- Verktyg: Lagra hjälpfunktoner och konstanter.
- index.ts: Använd
index.ts
-filer för att återexportera moduler från en katalog, vilket ger ett rent och organiserat API för import av moduler.
Använda Hooks med TypeScript
React Hooks låter dig använda tillstånd och andra React-funktioner i funktionella komponenter. TypeScript fungerar sömlöst med Hooks, vilket ger typsäkerhet och en förbättrad utvecklarupplevelse.
useState
Som visats tidigare kan du uttryckligen typa tillståndsvariabeln när du använder useState
:
import React, { useState } from 'react';
const MyComponent: React.FC = () => {
const [count, setCount] = useState<number>(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
};
useEffect
När du använder useEffect
, var uppmärksam på beroende-arrayen. TypeScript kan hjälpa dig att fånga fel om du glömmer att inkludera ett beroende som används inom effekten.
import React, { useState, useEffect } from 'react';
const MyComponent: React.FC = () => {
const [count, setCount] = useState<number>(0);
useEffect(() => {
document.title = `Count: ${count}`;
}, [count]); // Add 'count' to the dependency array
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
};
Om du utelämnar count
från beroende-arrayen kommer effekten endast att köras en gång när komponenten monteras, och dokumentets titel kommer inte att uppdateras när räknaren ändras. TypeScript kommer att varna dig för detta potentiella problem.
useContext
När du använder useContext
måste du tillhandahålla en typ för kontextvärdet.
import React, { createContext, useContext } from 'react';
interface ThemeContextType {
theme: string;
toggleTheme: () => void;
}
const ThemeContext = createContext<ThemeContextType | undefined>(undefined);
const ThemeProvider: React.FC = ({ children }) => {
// Implement theme logic here
return (
<ThemeContext.Provider value={{ theme: 'light', toggleTheme: () => {} }}>
{children}
</ThemeContext.Provider>
);
};
const MyComponent: React.FC = () => {
const { theme, toggleTheme } = useContext(ThemeContext) as ThemeContextType;
return (
<div>
<p>Theme: {theme}</p>
<button onClick={toggleTheme}>Toggle Theme</button>
</div>
);
};
export { ThemeProvider, MyComponent };
Genom att tillhandahålla en typ för kontextvärdet säkerställer du att useContext
-hooken returnerar ett värde med korrekt typ.
Testa TypeScript React-komponenter
Testning är en väsentlig del av att bygga robusta applikationer. TypeScript förbättrar testning genom att tillhandahålla typsäkerhet och förbättrad kodtäckning.
Enhetstestning
Använd testramverk som Jest och React Testing Library för att enhetstesta dina komponenter.
// MyComponent.test.tsx
import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import MyComponent from './MyComponent';
describe('MyComponent', () => {
it('renders the component with the correct name', () => {
render(<MyComponent name="John" />);
expect(screen.getByText('Hello, John!')).toBeInTheDocument();
});
it('calls the onClick handler when the button is clicked', () => {
const onClick = jest.fn();
render(<MyComponent name="John" onClick={onClick} />);
fireEvent.click(screen.getByRole('button'));
expect(onClick).toHaveBeenCalledTimes(1);
});
});
TypeScript's typkontroll hjälper till att fånga fel i dina tester, som att skicka in felaktiga props eller använda fel händelsehanterare.
Integrationstestning
Integrationstester verifierar att olika delar av din applikation fungerar korrekt tillsammans. Använd verktyg som Cypress eller Playwright för end-to-end-testning.
Prestandaoptimering
TypeScript kan också hjälpa till med prestandaoptimering genom att fånga potentiella prestandaflaskhalsar tidigt i utvecklingsprocessen.
Memoizering
Använd React.memo
för att memoizera funktionella komponenter och förhindra onödiga omritningar.
import React from 'react';
interface MyComponentProps {
name: string;
}
const MyComponent: React.FC<MyComponentProps> = ({ name }) => {
console.log('Rendering MyComponent');
return (
<p>Hello, {name}!</p>
);
};
export default React.memo(MyComponent);
React.memo
kommer endast att rita om komponenten om propsen har ändrats. Detta kan avsevärt förbättra prestandan, särskilt för komplexa komponenter.
Koduppdelning
Använd dynamiska importer för att dela upp din kod i mindre delar och ladda dem vid behov. Detta kan minska den initiala laddningstiden för din applikation.
import React, { Suspense } from 'react';
const MyComponent = React.lazy(() => import('./MyComponent'));
const App: React.FC = () => {
return (
<Suspense fallback={<div>Loading...</div>}>
<MyComponent />
</Suspense>
);
};
React.lazy
låter dig dynamiskt importera komponenter, som laddas endast när de behövs. Suspense
-komponenten tillhandahåller ett reservgränssnitt medan komponenten laddas.
Slutsats
Att använda TypeScript med React kan avsevärt förbättra kvaliteten, underhållbarheten och skalbarheten i dina webbapplikationer. Genom att följa dessa bästa praxis kan du utnyttja kraften i TypeScript för att bygga robusta och högpresterande applikationer som möter behoven hos en global publik. Kom ihåg att fokusera på tydliga typdefinitioner, välstrukturerad projektorganisation och noggrann testning för att säkerställa dina projekts långsiktiga framgång.