sandra-larsson
Educator Fullstack Developer Javascript at Chas Academy
FJS26 · V50 · ONSDAG
DOM:en, fetch och unknown. Kontrollera en gång, vid gränsen.
Chas Academy · Onsdag 9 december 2026
Typerna finns bara medan du skriver koden. Det som kommer utifrån har TypeScript aldrig sett.
VAD KOMMER UTIFRÅN?
Element som kanske inte finns, eller är något annat än du tror.
Formulär: value är alltid en sträng, även i ett nummerfält.
fetch: ett API kan ändras, svara med fel, eller skicka något annat.
localStorage och URL:en: vem som helst kan ha skrivit något där.
DOM
const status = document.querySelector('#status');
// Element | null
status.textContent = 'Hej';
// Fel: 'status' is possibly 'null'if (!status) {
throw new Error('Hittade inte #status');
}
status.textContent = 'Hej'; // okDOM
document.querySelector('ul');
// HTMLUListElement | null
document.querySelector('#name');
// Element | null
// Är det en input? TypeScript
// kan inte veta.const name = document
.querySelector('#name');
if (!(name instanceof HTMLInputElement)) {
throw new Error('Saknar #name');
}
name.value; // okDOM
Du lovar TypeScript vad det är. Har någon gjort om fältet till en select märker du det först när koden kraschar.
const name = document
.querySelector<HTMLInputElement>('#name');Kontrollerar när koden körs, och TypeScript narrowar efter kontrollen. Ett fel blir ett tydligt felmeddelande i stället för undefined längre fram.
DOM
form.addEventListener('submit', (event) => {
// event: SubmitEvent
event.preventDefault();
});priceInput.value; // '29' priceInput.valueAsNumber; // 29
Övning
Gör del 1 i src/1-dom.ts. Hämta #status, menyn och formulärets fält, kontrollera dem med null-koll och instanceof, och lägg till en produkt i menyn när formuläret skickas.
15 min
Du kan hämta element från DOM:en utan as, och TypeScript vet vilken typ varje element har.
UNKNOWN
const data = await response.json(); // data: any data.produkter.map(...); // inget fel nu, krasch sedan
const data: unknown = await response.json(); data.map(...); // Fel: 'data' is of type 'unknown'
TYPE GUARDS
const isRecord = (value: unknown) : value is Record<string, unknown> => typeof value === 'object' && value !== null;
const isProduct = (value: unknown) : value is Product => isRecord(value) && typeof value.id === 'string' && typeof value.name === 'string' && typeof value.price === 'number' && isCategory(value.category);
TYPE GUARDS
if (isProduct(data)) {
data.price; // number
}if (!Array.isArray(data)) {
throw new Error('Inte en lista');
}
const products = data.filter(isProduct);
// Product[]Kontrollera på ett ställe.
GRÄNSEN
GRÄNSEN
const fetchJson = async (url: string)
: Promise<unknown> => {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`Fel ${response.status}`);
}
return response.json();
};
const parseProducts = (data: unknown)
: Product[] => { /* ... */ };try {
const products = parseProducts(
await fetchJson('./products.json'),
);
showMenu(products);
} catch (error) {
showStatus(
error instanceof Error
? error.message
: 'Något gick fel',
);
}Samma kontroll, med ett schema.
ZOD
import { z } from 'zod';
const ProductSchema = z.object({
id: z.string(),
name: z.string(),
price: z.number(),
category: z.enum(['dryck', 'bröd', 'mat']),
});
type Product = z.infer<typeof ProductSchema>;const result = z.array(ProductSchema)
.safeParse(data);
if (result.success) {
result.data; // Product[]
} else {
z.prettifyError(result.error);
}ZOD
✖ Invalid input: expected number, received string → at [1].price ✖ Invalid input: expected string, received undefined → at [2].name ✖ Invalid option: expected one of "dryck"|"bröd"|"mat" → at [3].category
Guarden säger bara false. Zod säger vilken post och vilket fält. Det är guld när ett API har ändrats.
ZOD
Inga beroenden, och du ser exakt vad som kontrolleras. Blir lång när datan är stor, och typen och kontrollen kan glida isär.
Kort, bra felmeddelanden, och typen kommer ur schemat. Men det är ett beroende till: i code-alongen gick bundlen från 2 kB till 86 kB.
Båda gör samma sak: tar unknown och ger typad data, vid gränsen. Förstå guarden först, så förstår du vad Zod gör åt dig.
EFTER PASSET
npm run check.as eller any som borde vara en kontroll?By sandra-larsson