Hallitse TypeScript-virherajat kestäviin sovelluksiin. Tutustu virheenkäsittelytyyppimalleihin, parhaisiin käytäntöihin ja todellisiin esimerkkeihin.
TypeScript-virherajat: Virheenkäsittelytyyppimallit kestäviin sovelluksiin
Ohjelmistokehityksen maailmassa odottamattomat virheet ovat väistämättömiä. Verkkovirheistä odottamattomiin tietomuotoihin sovellusten on oltava valmiita käsittelemään näitä tilanteita moitteettomasti. TypeScript, tehokkaalla tyyppijärjestelmällään, tarjoaa vankan kehyksen kestävien sovellusten rakentamiseen. Tämä artikkeli syventyy TypeScriptin virherajojen käsitteeseen, tutkien erilaisia virheenkäsittelytyyppimalleja, parhaita käytäntöjä ja todellisia esimerkkejä, jotta sinulla olisi tietoa vakaamman ja ylläpidettävämmän koodin luomiseen.
Virheenkäsittelyn merkityksen ymmärtäminen
Tehokas virheenkäsittely on ratkaisevan tärkeää positiivisen käyttökokemuksen ja sovelluksen yleisen terveyden kannalta. Kun virheitä ei käsitellä, ne voivat johtaa:
- Kaatumiset ja arvaamaton käyttäytyminen: Käsittelemättömät poikkeukset voivat pysäyttää koodin suorituksen, mikä johtaa kaatumisiin tai arvaamattomiin tuloksiin.
- Tietojen menetys ja vioittuminen: Virheet tietojen käsittelyn tai tallennuksen aikana voivat johtaa tietojen menetykseen tai vioittumiseen, mikä vaikuttaa käyttäjiin ja järjestelmän eheyteen.
- Tietoturva-aukkoja: Huono virheenkäsittely voi paljastaa arkaluonteisia tietoja tai luoda mahdollisuuksia haitallisille hyökkäyksille.
- Negatiivinen käyttökokemus: Käyttäjät, jotka kohtaavat salaperäisiä virheilmoituksia tai sovelluksen vikoja, kokevat todennäköisesti turhauttavan kokemuksen, mikä johtaa luottamuksen ja käyttöönoton menetykseen.
- Heikentynyt tuottavuus: Kehittäjät käyttävät aikaa käsittelemättömien virheiden virheenkorjaukseen ja ratkaisemiseen, mikä haittaa yleistä kehitystuottavuutta ja hidastaa julkaisusyklejä.
Hyvä virheenkäsittely puolestaan tarjoaa:
- Hallittu heikkeneminen: Sovellus jatkaa toimintaansa, vaikka jokin tietty osa kohtaa virheen.
- Informatiivinen palaute: Käyttäjät saavat selkeitä ja ytimekkäitä virheilmoituksia, jotka auttavat heitä ymmärtämään ja ratkaisemaan ongelman.
- Tietojen eheys: Tärkeitä toimintoja hallitaan transaktiivisesti, mikä suojaa tärkeitä käyttäjätietoja.
- Parannettu vakaus: Sovelluksesta tulee kestävämpi odottamattomille tapahtumille.
- Parempi ylläpidettävyys: Ongelmien tunnistaminen, diagnosointi ja korjaaminen on helpompaa, kun niitä ilmenee.
Mitä ovat virherajat TypeScriptissä?
Virherajat ovat suunnittelumalli, jota käytetään JavaScript-virheiden sieppaamiseen komponenttipuun tietyssä osassa ja varajärjestelmän käyttöliittymän näyttämiseen koko sovelluksen kaatumisen sijaan. Vaikka TypeScriptillä itsellään ei ole erityistä "virheraja"-ominaisuutta, tällaisten rajojen luomisen periaatteet ja tekniikat ovat helposti sovellettavissa ja parannettavissa TypeScriptin tyyppiturvallisuudella.
Ydinajatuksena on eristää mahdollisesti virhealtis koodi omaksi komponentiksi tai moduuliksi. Tämä komponentti toimii kääreenä ja valvoo sen sisällä olevaa koodia. Jos virhe ilmenee, virherajakomponentti "sieppaa" virheen estäen sen leviämisen komponenttipuussa ja mahdollisesti kaatamasta sovellusta. Sen sijaan virheraja voi näyttää varajärjestelmän käyttöliittymän, kirjata virheen tai yrittää palautua ongelmasta.
Virherajojen käytön edut ovat:
- Eristys: Estää yhden osan virheitä vaikuttamasta muihin osiin sovelluksessasi.
- Varajärjestelmän käyttöliittymä: Tarjoaa käyttäjäystävällisemmän kokemuksen kuin täysin rikkinäinen sovellus.
- Virheiden kirjaaminen: Helpottaa virhetietojen keräämistä virheenkorjausta ja valvontaa varten.
- Parempi ylläpidettävyys: Yksinkertaistaa virheenkäsittelylogiikkaa ja helpottaa koodin päivittämistä ja ylläpitämistä.
Virheenkäsittelytyyppimallit TypeScriptissä
TypeScriptin tyyppijärjestelmä on erittäin tehokas, kun se yhdistetään oikeisiin virheenkäsittelymalleihin. Tässä on joitakin yleisiä ja tehokkaita malleja virheiden hallintaan TypeScript-sovelluksissasi:
1. Try-Catch-lohkot
JavaScriptin ja TypeScriptin virheenkäsittelyn perusrakennuspalikka on `try-catch`-lohko. Se sallii koodin suorittamisen `try`-lohkossa ja kaikkien heitettyjen poikkeusten sieppaamisen. Tämä on synkroninen toiminto, ihanteellinen virheiden käsittelyyn suoraan funktion sisällä.
function fetchData(url: string): Promise<any> {
try {
return fetch(url).then(response => {
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
return response.json();
});
} catch (error) {
console.error("An error occurred while fetching data:", error);
// Handle the error (e.g., display an error message to the user)
return Promise.reject(error);
}
}
Tässä esimerkissä `fetchData`-funktio yrittää noutaa tietoja annetusta URL-osoitteesta. Jos `fetch`-kutsu epäonnistuu (esim. verkkovirhe, virheellinen URL) tai jos vastauksen tila ei ole OK, heitetään virhe. `catch`-lohko käsittelee sitten virheen. Huomaa `Promise.reject(error)` -käyttö virheen levittämiseksi, jotta kutsuva koodi voi myös käsitellä sen. Tämä on yleistä asynkronisille toiminnoille.
2. Lupaukset ja asynkroninen virheenkäsittely
Asynkroniset toiminnot ovat yleisiä JavaScriptissä, erityisesti käsiteltäessä API-kutsuja, tietokantavuorovaikutuksia ja tiedosto-I/O:ta. Lupaukset (Promises) tarjoavat tehokkaan mekanismin virheiden käsittelyyn näissä skenaarioissa. `try-catch`-lohko on hyödyllinen, mutta monissa tapauksissa käsittelet virheitä Lupauksen `.then()`- ja `.catch()`-metodien sisällä.
function fetchData(url: string): Promise<any> {
return fetch(url)
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
return response.json();
})
.catch(error => {
console.error("An error occurred while fetching data:", error);
// Handle the error (e.g., display an error message to the user)
return Promise.reject(error);
});
}
fetchData('https://api.example.com/data')
.then(data => {
console.log("Data fetched successfully:", data);
})
.catch(error => {
console.error("Failed to fetch data:", error);
// Display a user-friendly error message
});
Tässä esimerkissä `fetchData`-funktio käyttää lupausta asynkronisen `fetch`-toiminnon käsittelyyn. Virheet siepataan `.catch()`-lohkossa, jotta voit käsitellä ne nimenomaan asynkronista toimintoa varten.
3. Virheluokat ja mukautetut virhetyypit
TypeScriptin avulla voit määrittää mukautettuja virheluokkia, jotka tarjoavat jäsennellymmän ja informatiivisemman virheenkäsittelyn. Tämä on erinomainen käytäntö uudelleenkäytettävän ja tyyppiturvallisen virheenkäsittelylogiikan luomiseen. Luomalla mukautettuja virheluokkia voit:
- Lisää erityisiä virhekoodeja: Erottele eri virhetyypit toisistaan.
- Tarjoa konteksti: Tallenna virheeseen liittyviä lisätietoja.
- Paranna luettavuutta ja ylläpidettävyyttä: Tee virheenkäsittelykoodistasi helpommin ymmärrettävää.
class ApiError extends Error {
statusCode: number;
code: string;
constructor(message: string, statusCode: number, code: string) {
super(message);
this.name = 'ApiError';
this.statusCode = statusCode;
this.code = code;
// Assign the prototype explicitly
Object.setPrototypeOf(this, ApiError.prototype);
}
}
async function getUserData(userId: number): Promise<any> {
try {
const response = await fetch(`https://api.example.com/users/${userId}`);
if (!response.ok) {
let errorMessage = 'Failed to fetch user data';
if (response.status === 404) {
errorMessage = 'User not found';
}
throw new ApiError(errorMessage, response.status, 'USER_NOT_FOUND');
}
return await response.json();
} catch (error: any) {
if (error instanceof ApiError) {
console.error("API Error:", error.message, error.statusCode, error.code);
// Handle specific API error based on the code
if (error.code === 'USER_NOT_FOUND') {
// Show a 'user not found' message
}
} else {
console.error("An unexpected error occurred:", error);
// Handle other errors
}
throw error; // Re-throw or handle the error
}
}
getUserData(123)
.then(userData => console.log("User data:", userData))
.catch(error => console.error("Error retrieving user data:", error));
Tämä esimerkki määrittelee `ApiError`-luokan, joka perii sisäänrakennetun `Error`-luokan. Se sisältää `statusCode`- ja `code`-ominaisuudet lisäkontekstin tarjoamiseksi. `getUserData`-funktio käyttää tätä mukautettua virheluokkaa, siepaten ja käsitellen tietyntyyppisiä virheitä. `instanceof`-operaattorin käyttö mahdollistaa tyyppiturvallisen tarkistuksen ja virhekohtaisen käsittelyn virheen tyypin perusteella.
4. `Result`-tyyppi (funktionaalinen virheenkäsittely)
Funktionaalinen ohjelmointi käyttää usein `Result`-tyyppiä (kutsutaan myös `Either`-tyypiksi) edustamaan joko onnistunutta tulosta tai virhettä. Tämä malli tarjoaa puhtaan ja tyyppiturvallisen tavan käsitellä virheitä. `Result`-tyypillä on tyypillisesti kaksi varianttia: `Ok` (onnistumiselle) ja `Err` (epäonnistumiselle).
// Define a generic Result type
interface Ok<T> {
type: 'ok';
value: T;
}
interface Err<E> {
type: 'err';
error: E;
}
type Result<T, E> = Ok<T> | Err<E>
function divide(a: number, b: number): Result<number, string> {
if (b === 0) {
return { type: 'err', error: 'Division by zero' };
}
return { type: 'ok', value: a / b };
}
const result1 = divide(10, 2);
const result2 = divide(10, 0);
if (result1.type === 'ok') {
console.log('Result:', result1.value);
} else {
console.error('Error:', result1.error);
}
if (result2.type === 'ok') {
console.log('Result:', result2.value);
} else {
console.error('Error:', result2.error);
}
`divide`-funktio palauttaa joko tyypin `Ok` `Result`-objektin, joka sisältää jakolaskun tuloksen, tai tyypin `Err` `Result`-objektin, joka sisältää virheilmoituksen. Tämä malli varmistaa, että kutsujan on pakko käsitellä sekä onnistumis- että epäonnistumistilanteet, mikä estää käsittelemättömät virheet.
5. Dekoratoorit (edistyneeseen virheenkäsittelyyn - harvoin käytetään suoraan rajojen toteutukseen)
Vaikka dekoratoorit eivät ole suoraan virherajojen malli, niitä voidaan käyttää virheenkäsittelylogiikan soveltamiseen metodeihin deklaratiivisella tavalla. Tämä voi vähentää koodin toistuvuutta. Tämä käyttö on kuitenkin harvinaisempaa kuin muut yllä olevat mallit varsinaisen virherajojen toteutuksessa.
function handleError(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
descriptor.value = async function (...args: any[]) {
try {
const result = await originalMethod.apply(this, args);
return result;
} catch (error: any) {
console.error(`Error in ${propertyKey}:`, error);
// Handle the error here (e.g., log, display a default value, etc.)
return null; // Or throw a more specific error
}
};
return descriptor;
}
class MyService {
@handleError
async fetchData(url: string): Promise<any> {
// Simulate an error
if (Math.random() < 0.5) {
throw new Error('Simulated network error');
}
const response = await fetch(url);
return await response.json();
}
}
Tämä esimerkki määrittelee `@handleError`-dekoratorin. Dekoratori käärii alkuperäisen metodin, sieppaa kaikki virheet ja kirjaa ne. Tämä mahdollistaa virheenkäsittelyn muuttamatta alkuperäisen metodin koodia suoraan.
Virherajojen toteuttaminen frontend-kehyksissä (React-esimerkki)
Vaikka ydinkonseptit pysyvät samankaltaisina, virherajojen toteutus vaihtelee hieman käyttämästäsi frontend-kehyksestä riippuen. Keskitytään Reactiin, joka on yleisin kehys interaktiivisten käyttöliittymien rakentamiseen.
React-virherajat
React tarjoaa erityisen mekanismin virherajojen luomiseen. Virheraja on React-komponentti, joka sieppaa JavaScript-virheet missä tahansa lapsikomponenttipuussaan, kirjaa kyseiset virheet ja näyttää varajärjestelmän käyttöliittymän koko sovelluksen kaatumisen sijaan. Virherajat sieppaavat virheitä renderöinnin, elinkaarimetodien ja kaikkien lapsikomponenttiensa konstruktorien aikana.
Keskeiset metodit virherajan luomiseen Reactissa:
- `static getDerivedStateFromError(error)`: Tämä staattinen metodi kutsutaan sen jälkeen, kun alikomponentti heittää virheen. Se vastaanottaa virheen parametrina ja sen tulisi palauttaa objekti tilan päivittämiseksi. Sitä käytetään tilan päivittämiseen, kuten `error`-lipun asettamiseen `true`:ksi varajärjestelmän käyttöliittymän käynnistämiseksi.
- `componentDidCatch(error, info)`: Tämä metodi kutsutaan sen jälkeen, kun alikomponentti heittää virheen. Se vastaanottaa virheen ja objektin, joka sisältää tietoja virheen heittäneestä komponentista. Sitä käytetään tyypillisesti virheen kirjaamiseen. Tämä metodi kutsutaan vain virheille, jotka ilmenevät sen jälkeläisten renderöinnin aikana.
import React from 'react';
interface Props {
children: React.ReactNode;
}
interface State {
hasError: boolean;
error: Error | null;
}
class ErrorBoundary extends React.Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = { hasError: false, error: null };
}
static getDerivedStateFromError(error: Error) {
// Update state so the next render will show the fallback UI.
return { hasError: true, error: error };
}
componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
// You can also log the error to an error reporting service
console.error('Uncaught error:', error, errorInfo);
}
render() {
if (this.state.hasError) {
// You can render any custom fallback UI
return (
<div className="error-boundary">
<h2>Something went wrong.</h2>
<p>We're working on fixing it!</p>
<details style={{ whiteSpace: 'pre-wrap' }}>
{this.state.error && this.state.error.stack}
</details>
</div>
);
}
return this.props.children;
}
}
export default ErrorBoundary;
Tämä `ErrorBoundary`-komponentti käärii lapsikomponenttinsa. Jos käärittyjen komponenttien sisällä heitetään virhe, `getDerivedStateFromError`-metodi kutsutaan tilan päivittämiseksi, mikä saa komponentin renderöimään uudelleen varajärjestelmän käyttöliittymällä. `componentDidCatch`-metodia käytetään virheiden kirjaamiseen. Käyttääksesi ErrorBoundarya, käärisit yksinkertaisesti osia sovelluksestasi sen sisään:
import ErrorBoundary from './ErrorBoundary';
function App() {
return (
<div>
<ErrorBoundary>
<MyComponentThatMightError />
</ErrorBoundary>
<AnotherComponent />
</div>
);
}
Asettamalla `ErrorBoundary`-komponentin potentiaalisesti ongelmallisten komponenttien ympärille, eristät nämä komponentit ja tarjoat varajärjestelmän käyttöliittymän virheiden sattuessa, mikä estää koko sovelluksen kaatumisen.
Virherajat muissa kehyksissä (käsitteellinen)
Vaikka toteutuksen yksityiskohdat eroavat, virherajojen perusperiaatteet voidaan soveltaa muihin frontend-kehyksiin, kuten Angulariin ja Vue.js:ään. Saavuttaisit tämän tyypillisesti käyttämällä samankaltaisia strategioita:
- Angular: Käyttäen komponenttien virheenkäsittelyä, mukautettuja virhekäsittelijöitä ja sieppaimia. Harkitse Angularin `ErrorHandler`-luokan hyödyntämistä ja potentiaalisesti ongelmallisten komponenttien käärimistä virheenkäsittelylogiikkaan.
- Vue.js: Käyttämällä `try...catch`-lohkoja komponenttien sisällä tai globaaleja virhekäsittelijöitä, jotka on rekisteröity `Vue.config.errorHandler`:in kautta. Vuella on myös komponenttitason virheenkäsittelyominaisuuksia, jotka ovat samankaltaisia kuin Reactin virherajat.
Parhaat käytännöt virherajoille ja virheenkäsittelylle
Jotta voit hyödyntää virherajoja ja virheenkäsittelytyyppimalleja tehokkaasti, harkitse näitä parhaita käytäntöjä:
- Eristä virhealtis koodi: Kääri komponentit tai koodiosat, jotka todennäköisesti heittävät virheitä, virherajojen tai asianmukaisten virheenkäsittelyrakenteiden sisään.
- Tarjoa selkeitä virheilmoituksia: Suunnittele käyttäjäystävällisiä virheilmoituksia, jotka tarjoavat kontekstin ja ohjeita käyttäjälle. Vältä kryptistä tai teknistä ammattikieltä.
- Kirjaa virheet tehokkaasti: Ota käyttöön vankka virheiden kirjausjärjestelmä virheiden seuraamiseksi, asiaankuuluvien tietojen (pinon jäljitykset, käyttäjäkonteksti jne.) keräämiseksi ja virheenkorjauksen helpottamiseksi. Käytä palveluita kuten Sentry, Bugsnag tai Rollbar tuotantoympäristöissä.
- Toteuta varajärjestelmän käyttöliittymät: Tarjoa merkityksellisiä varajärjestelmän käyttöliittymiä, jotka käsittelevät virheet moitteettomasti ja estävät koko sovelluksen kaatumisen. Varajärjestelmän tulisi ilmoittaa käyttäjälle, mitä tapahtui, ja tarvittaessa ehdottaa toimenpiteitä, joita he voivat tehdä.
- Käytä mukautettuja virheluokkia: Luo mukautettuja virheluokkia edustamaan erityyppisiä virheitä ja lisäämään lisäkontekstia ja tietoa tehokkaampaa virheenkäsittelyä varten.
- Harkitse virherajojen laajuutta: Älä kääri koko sovellusta yhteen virherajaan, sillä se saattaa piilottaa taustalla olevia ongelmia. Aseta sen sijaan virherajat strategisesti komponenttien tai sovelluksen osien ympärille.
- Testaa virheenkäsittely: Kirjoita yksikkötestejä ja integraatiotestejä varmistaaksesi, että virheenkäsittelylogiikkasi toimii odotetusti ja että varajärjestelmän käyttöliittymät näytetään oikein. Testaa skenaarioita, joissa virheitä saattaa esiintyä.
- Valvo ja analysoi virheitä: Valvo säännöllisesti sovelluksesi virhelokeja tunnistaaksesi toistuvia ongelmia, seurataksesi virhetrendejä ja löytääksesi parannuskohteita.
- Pyri tietojen validoimiseen: Validoi ulkoisista lähteistä vastaanotetut tiedot estääksesi virheellisten tietomuotojen aiheuttamia odottamattomia virheitä.
- Käsittele lupauksia ja asynkronisia toimintoja huolellisesti: Varmista, että käsittelet asynkronisissa toiminnoissa ilmenevät virheet käyttämällä `.catch()`-lohkoja tai asianmukaisia virheenkäsittelymekanismeja.
Todellisia esimerkkejä ja kansainvälisiä huomioita
Katsotaanpa käytännön esimerkkejä siitä, miten virherajoja ja virheenkäsittelytyyppimalleja voidaan soveltaa todellisiin skenaarioihin, ottaen huomioon kansainvälistymisen:
Esimerkki: Verkkokauppasovellus (tietojen noutaminen)
Kuvittele verkkokauppasovellus, joka näyttää tuoteluetteloita. Sovellus hakee tuotetietoja backend-rajapinnasta. Virherajaa käytetään API-kutsujen mahdollisten ongelmien käsittelyyn.
interface Product {
id: number;
name: string;
price: number;
currency: string;
// ... other product details
}
class ProductList extends React.Component<{}, { products: Product[] | null; loading: boolean; error: Error | null }> {
state = { products: null, loading: true, error: null };
async componentDidMount() {
try {
const products = await this.fetchProducts();
this.setState({ products, loading: false });
} catch (error: any) {
this.setState({ error, loading: false });
}
}
async fetchProducts(): Promise<Product[]> {
const response = await fetch('/api/products'); // API endpoint
if (!response.ok) {
throw new Error(`Failed to fetch products: ${response.status}`);
}
return await response.json();
}
render() {
const { products, loading, error } = this.state;
if (loading) {
return <div>Loading products...</div>;
}
if (error) {
return (
<div className="error-message">
<p>Sorry, we're having trouble loading the products.</p>
<p>Please try again later.</p>
<p>Error details: {error.message}</p> {/* Log the error message for debugging */}
</div>
);
}
return (
<ul>
{products && products.map(product => (
<li key={product.id}>{product.name} - {product.price} {product.currency}</li>
))}
</ul>
);
}
}
// Error Boundary (React Component)
class ProductListErrorBoundary extends React.Component<{children: React.ReactNode}, {hasError: boolean, error: Error | null}> {
constructor(props: any) {
super(props);
this.state = { hasError: false, error: null };
}
static getDerivedStateFromError(error: Error) {
// Update state so the next render will show the fallback UI.
return { hasError: true, error: error };
}
componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
// You can also log the error to an error reporting service
console.error('Product List Error:', error, errorInfo);
}
render() {
if (this.state.hasError) {
// Render a fallback UI (e.g., error message, retry button)
return (
<div className="product-list-error">
<h2>Oops, something went wrong!</h2>
<p>We are unable to load product information at this time.</p>
<button onClick={() => window.location.reload()} >Retry</button>
</div>
);
}
return this.props.children;
}
}
// Usage
function App() {
return (
<div>
<ProductListErrorBoundary>
<ProductList />
</ProductListErrorBoundary>
</div>
);
}
Tässä esimerkissä:
- `ProductList` hakee tuotetietoja. Se käsittelee lataustilan, onnistuneet tuotetiedot ja virhetilan komponentin sisällä.
- `ProductListErrorBoundary` -komponenttia käytetään käärimään `ProductList` -komponentti virheiden sieppaamiseksi renderöinnin ja API-kutsujen aikana.
- Jos API-pyyntö epäonnistuu, `ProductListErrorBoundary` renderöi käyttäjäystävällisen virheilmoituksen käyttöliittymän kaatumisen sijaan.
- Virheilmoitus tarjoaa "yritä uudelleen" -vaihtoehdon, jonka avulla käyttäjä voi päivittää sivun.
- Tuotetietojen `currency`-kenttä voidaan näyttää oikein käyttämällä kansainvälistymiskirjastoja (esim. Intl JavaScriptissa), jotka tarjoavat valuutan muotoilun käyttäjän paikallisten asetusten mukaisesti.
Esimerkki: Kansainvälinen lomakkeen validointi
Harkitse lomaketta, joka kerää käyttäjätietoja, mukaan lukien osoitetiedot. Asianmukainen validointi on välttämätöntä, erityisesti käsiteltäessä käyttäjiä eri maista, joilla on erilaisia osoitemuotoja.
// Assume a simplified address interface
interface Address {
street: string;
city: string;
postalCode: string;
country: string;
}
class AddressForm extends React.Component<{}, { address: Address; errors: { [key: string]: string } }> {
state = {
address: {
street: '',
city: '',
postalCode: '',
country: 'US', // Default country
},
errors: {},
};
handleChange = (event: React.ChangeEvent<HTMLInputElement | HTMLSelectElement>) => {
const { name, value } = event.target;
this.setState((prevState) => ({
address: {
...prevState.address,
[name]: value,
},
errors: {
...prevState.errors,
[name]: '', // Clear any previous errors for this field
},
}));
};
handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
const { address } = this.state;
const errors = this.validateAddress(address);
if (Object.keys(errors).length > 0) {
this.setState({ errors });
}
else {
// Submit the form (e.g., to an API)
alert('Form submitted!'); // Replace with actual submission logic
}
};
validateAddress = (address: Address) => {
const errors: { [key: string]: string } = {};
// Validation rules based on the selected country
if (!address.street) {
errors.street = 'Street address is required';
}
if (!address.city) {
errors.city = 'City is required';
}
// Example: postal code validation based on the country
switch (address.country) {
case 'US':
if (!/^[0-9]{5}(?:-[0-9]{4})?$/.test(address.postalCode)) {
errors.postalCode = 'Invalid US postal code';
}
break;
case 'CA':
if (!/^[A-Za-z][0-9][A-Za-z][ ]?[0-9][A-Za-z][0-9]$/.test(address.postalCode)) {
errors.postalCode = 'Invalid Canadian postal code';
}
break;
// Add more countries and validation rules
default:
if (!address.postalCode) {
errors.postalCode = 'Postal code is required';
}
break;
}
return errors;
};
render() {
const { address, errors } = this.state;
return (
<form onSubmit={this.handleSubmit}>
<label htmlFor="street">Street:</label>
<input
type="text"
id="street"
name="street"
value={address.street}
onChange={this.handleChange}
/>
{errors.street && <div className="error">{errors.street}</div>}
<label htmlFor="city">City:</label>
<input
type="text"
id="city"
name="city"
value={address.city}
onChange={this.handleChange}
/>
{errors.city && <div className="error">{errors.city}</div>}
<label htmlFor="postalCode">Postal Code:</label>
<input
type="text"
id="postalCode"
name="postalCode"
value={address.postalCode}
onChange={this.handleChange}
/>
{errors.postalCode && <div className="error">{errors.postalCode}</div>}
<label htmlFor="country">Country:</label>
<select
id="country"
name="country"
value={address.country}
onChange={this.handleChange}
>
<option value="US">United States</option>
<option value="CA">Canada</option>
<!-- Add more countries -->
</select>
<button type="submit">Submit</button>
</form>
);
}
}
Tässä esimerkissä:
- `AddressForm`-komponentti hallitsee lomakkeen tietoja ja validointilogiikkaa.
- `validateAddress`-funktio suorittaa validointia valitun maan perusteella.
- Maakohtaisia postinumeron validointisääntöjä sovelletaan (esimerkkeinä USA ja Kanada).
- Sovellus hyödyntää `Intl`-rajapintaa lokaalitietoiseen muotoiluun. Tätä käytettäisiin numeroiden, päivämäärien ja valuuttojen dynaamiseen muotoiluun nykyisen käyttäjän lokaalin mukaisesti.
- Virheilmoitukset voidaan kääntää paremman käyttökokemuksen tarjoamiseksi maailmanlaajuisesti.
- Tämä lähestymistapa antaa käyttäjien täyttää lomakkeen käyttäjäystävällisesti, sijainnistaan riippumatta.
Kansainvälistymisen parhaat käytännöt:
- Käytä lokalisointikirjastoa: Kirjastot kuten i18next, react-intl tai LinguiJS tarjoavat ominaisuuksia tekstin kääntämiseen, päivämäärien, numeroiden ja valuuttojen muotoiluun käyttäjän lokaalin perusteella.
- Tarjoa lokaalin valinta: Anna käyttäjien valita haluamansa kieli ja alue. Tämä voi tapahtua pudotusvalikon, asetusten tai selaimen asetuksiin perustuvan automaattisen tunnistuksen kautta.
- Käsittele päivämäärä-, aika- ja numeromuotoja: Käytä `Intl`-rajapintaa päivämäärien, aikojen, numeroiden ja valuuttojen muotoiluun asianmukaisesti eri lokaaleille.
- Harkitse tekstin suuntaa: Suunnittele käyttöliittymäsi tukemaan sekä vasemmalta oikealle (LTR) että oikealta vasemmalle (RTL) tekstisuuntia. Kirjastoja on olemassa RTL-tuen helpottamiseksi.
- Ota huomioon kulttuuriset erot: Muista kulttuuriset normit suunnitellessasi käyttöliittymääsi ja virheilmoituksiasi. Vältä kielen tai kuvien käyttöä, jotka voivat olla loukkaavia tai sopimattomia tietyissä kulttuureissa.
- Testaa eri lokaaleissa: Testaa sovellustasi perusteellisesti eri lokaaleissa varmistaaksesi, että käännös ja muotoilu toimivat oikein ja että käyttöliittymä näytetään asianmukaisesti.
Johtopäätös
TypeScriptin virherajat ja tehokkaat virheenkäsittelytyyppimallit ovat olennaisia osia luotettavien ja käyttäjäystävällisten sovellusten rakentamisessa. Toteuttamalla näitä käytäntöjä voit estää odottamattomia kaatumisia, parantaa käyttökokemusta ja virtaviivaistaa virheenkorjaus- ja ylläpitoprosesseja. Perus `try-catch`-lohkoista kehittyneempiin `Result`-tyyppeihin ja mukautettuihin virheluokkiin nämä mallit antavat sinulle mahdollisuuden luoda vankkoja sovelluksia, jotka kestävät todellisen maailman haasteet. Hyödyntämällä näitä tekniikoita kirjoitat parempaa TypeScript-koodia ja tarjoat paremman kokemuksen globaaleille käyttäjillesi.
Muista valita virheenkäsittelymallit, jotka parhaiten vastaavat projektisi tarpeita ja sovelluksesi monimutkaisuutta. Keskity aina tarjoamaan selkeitä, informatiivisia virheilmoituksia ja varajärjestelmän käyttöliittymiä, jotka ohjaavat käyttäjiä mahdollisten ongelmien läpi. Noudattamalla näitä ohjeita voit luoda sovelluksia, jotka ovat kestävämpiä, ylläpidettävämpiä ja lopulta menestyksekkäämpiä globaaleilla markkinoilla.
Harkitse näiden mallien ja tekniikoiden kokeilemista projekteissasi ja mukauta niitä sovelluksesi erityisvaatimuksiin. Tämä lähestymistapa parantaa koodin laatua ja tarjoaa positiivisemman kokemuksen kaikille käyttäjille.