sandra-larsson
Educator Fullstack Developer Javascript at Chas Academy
FJS26 · V49 · ONSDAG
När ett värde kan vara en av flera typer, och TypeScript måste få veta vilken.
Chas Academy · Onsdag 2 december 2026
UNIONS
type Id = string | number;
const showId = (id: Id) => `Id: ${id}`;
showId('kaffe'); // ok
showId(42); // ok
showId(true);
// Argument of type 'boolean' is not
// assignable to parameter of type 'Id'.let note: string | null = null;
LITERAL TYPES
type Size = 'small' | 'medium' | 'large'; const size: Size = 'medium'; const huge: Size = 'huge'; // Type '"huge"' is not assignable // to type 'Size'.
Skriv ett citattecken efter const size: Size = så föreslår VS Code de tre värdena. Ett stavfel blir ett typfel, inte en bugg.
LITERAL TYPES
type OrderFlags = {
isPaid: boolean;
isShipped: boolean;
isCancelled: boolean;
};
// skickad, obetald och avbruten?type OrderStatus = | 'new' | 'paid' | 'shipped' | 'cancelled';
En kontroll i koden smalnar av typen.
NARROWING
const format = (amount: string | number) => amount.toFixed(2); // Property 'toFixed' does not exist // on type 'string'.
const format = (amount: string | number) => {
if (typeof amount === 'number') {
return `${amount.toFixed(2)} kr`; // number
}
return amount; // string
};NARROWING
För primitiver: 'string', 'number', 'boolean', 'object'.
if (name) tar bort null och undefined. Men också '' och 0, så se upp.
if ('temperature' in item): finns egenskapen i objektet?
För klasser: if (error instanceof Error). Samma klasser som i v46.
DISCRIMINATED UNIONS
Tre sätt att betala, med olika data. Fältet kind finns i alla, med ett eget värde.
type Card = { kind: 'card'; last4: string };
type Swish = { kind: 'swish'; phone: string };
type Invoice = {
kind: 'invoice';
email: string;
dueDays: number;
};
type Payment = Card | Swish | Invoice;kind är en literal type i varje del. Kontrollerar du kind vet TypeScript exakt vilken del det är, och vilka fält som finns.
DISCRIMINATED UNIONS
const describePayment = (payment: Payment): string => {
switch (payment.kind) {
case 'card':
return `Kort ${payment.last4}`; // Card
case 'swish':
return `Swish ${payment.phone}`; // Swish
case 'invoice':
return `Faktura ${payment.email}`; // Invoice
default:
return assertNever(payment);
}
};DISCRIMINATED UNIONS
const assertNever = (value: never): never => {
throw new Error(
`Ohanterat fall: ${JSON.stringify(value)}`,
);
};type GiftCard = { kind: 'giftcard'; code: string };
type Payment = Card | Swish | Invoice | GiftCard;
// i default:
// Argument of type 'GiftCard' is not
// assignable to parameter of type 'never'.En discriminated union gör omöjliga lägen omöjliga att skriva, och assertNever ser till att alla möjliga lägen hanteras.
INTERSECTIONS
type Product = { name: string; price: number };
type WithId = { id: string };
type WithTimestamps = {
createdAt: Date;
updatedAt: Date;
};
type SavedProduct =
Product & WithId & WithTimestamps;A | B: ett värde som är antingen A eller B. A & B: ett värde som har allt från både A och B. Med interface blir det extends.
Data utifrån, som TypeScript inte vet något om.
UNKNOWN
const lines = JSON.parse(saved); // any lines[1].quantity.toFixed(0); // inget typfel // TypeError när koden körs
const data: unknown = JSON.parse(saved); data[0]; // 'data' is of type 'unknown'.
TYPE GUARDS
type CartLine = {
productId: string;
quantity: number;
};
const isCartLine = (
value: unknown,
): value is CartLine =>
typeof value === 'object' &&
value !== null &&
'productId' in value &&
typeof value.productId === 'string' &&
'quantity' in value &&
typeof value.quantity === 'number';const valid: CartLine[] =
Array.isArray(data)
? data.filter(isCartLine)
: [];as säger till TypeScript att lita på dig. En type guard kontrollerar på riktigt.
EFTER PASSET
By sandra-larsson