FJS26 · V49 · ONSDAG

Unions, narrowing
och type guards

När ett värde kan vara en av flera typer, och TypeScript måste få veta vilken.

Chas Academy · Onsdag 2 december 2026


Idag

01Unions och literal types02Narrowing03Discriminated unions04Intersections05unknown och type guards06Efter passet
UNIONS, NARROWING OCH TYPE GUARDS2 / 22
01

Unions och
literal types

UNIONS


Det ena eller det andra

Union med |

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'.

Ni har redan sett en

let note: string | null = null;
UNIONS, NARROWING OCH TYPE GUARDS4 / 22

LITERAL TYPES


Bara vissa exakta värden

Koden

type Size = 'small' | 'medium' | 'large';

const size: Size = 'medium';
const huge: Size = 'huge';
// Type '"huge"' is not assignable
// to type 'Size'.

Editorn vet

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.

UNIONS, NARROWING OCH TYPE GUARDS5 / 22

LITERAL TYPES


Ett läge i stället för flera booleans

Tre booleans: 8 kombinationer

type OrderFlags = {
  isPaid: boolean;
  isShipped: boolean;
  isCancelled: boolean;
};
// skickad, obetald och avbruten?

Ett läge: bara de som finns

type OrderStatus =
  | 'new'
  | 'paid'
  | 'shipped'
  | 'cancelled';
UNIONS, NARROWING OCH TYPE GUARDS6 / 22
02

Narrowing

En kontroll i koden smalnar av typen.

NARROWING


typeof

Utan kontroll

const format = (amount: string | number) =>
  amount.toFixed(2);
// Property 'toFixed' does not exist
// on type 'string'.

Med kontroll

const format = (amount: string | number) => {
  if (typeof amount === 'number') {
    return `${amount.toFixed(2)} kr`; // number
  }
  return amount; // string
};
UNIONS, NARROWING OCH TYPE GUARDS8 / 22

NARROWING


Fyra sätt att smalna av

typeof

För primitiver: 'string', 'number', 'boolean', 'object'.

Truthiness

if (name) tar bort null och undefined. Men också '' och 0, så se upp.

in

if ('temperature' in item): finns egenskapen i objektet?

instanceof

För klasser: if (error instanceof Error). Samma klasser som i v46.

UNIONS, NARROWING OCH TYPE GUARDS9 / 22
03

Discriminated
unions

DISCRIMINATED UNIONS


Kaféets betalsätt

Tre sätt att betala, med olika data. Fältet kind finns i alla, med ett eget värde.

Typerna

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;

Diskriminanten

kind är en literal type i varje del. Kontrollerar du kind vet TypeScript exakt vilken del det är, och vilka fält som finns.

UNIONS, NARROWING OCH TYPE GUARDS11 / 22

DISCRIMINATED UNIONS


switch på kind

describePayment

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);
  }
};
UNIONS, NARROWING OCH TYPE GUARDS12 / 22

DISCRIMINATED UNIONS


assertNever: glöm inget fall

Funktionen

const assertNever = (value: never): never => {
  throw new Error(
    `Ohanterat fall: ${JSON.stringify(value)}`,
  );
};

Lägg till presentkort

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'.
UNIONS, NARROWING OCH TYPE GUARDS13 / 22
”

En discriminated union gör omöjliga lägen omöjliga att skriva, och assertNever ser till att alla möjliga lägen hanteras.

04

Intersections

INTERSECTIONS


Det ena och det andra

&

type Product = { name: string; price: number };
type WithId = { id: string };
type WithTimestamps = {
  createdAt: Date;
  updatedAt: Date;
};

type SavedProduct =
  Product & WithId & WithTimestamps;

Union eller intersection?

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.

UNIONS, NARROWING OCH TYPE GUARDS16 / 22
05

unknown och
type guards

Data utifrån, som TypeScript inte vet något om.

UNKNOWN


any mot unknown

any: allt är tillåtet

const lines = JSON.parse(saved); // any
lines[1].quantity.toFixed(0);
// inget typfel
// TypeError när koden körs

unknown: inget är tillåtet

const data: unknown = JSON.parse(saved);
data[0];
// 'data' is of type 'unknown'.
UNIONS, NARROWING OCH TYPE GUARDS18 / 22

TYPE GUARDS


En egen type guard

value is CartLine

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';

Användningen

const valid: CartLine[] =
  Array.isArray(data)
    ? data.filter(isCartLine)
    : [];
UNIONS, NARROWING OCH TYPE GUARDS19 / 22
”

as säger till TypeScript att lita på dig. En type guard kontrollerar på riktigt.

06

Efter passet

EFTER PASSET


Öva, och inför i morgon

  • Code-along: gör klart del 1–5.
  • Läs: Narrowing i TypeScript-handboken.
  • Övningar: codington.io/typescript.
  • I morgon, workshop: ni flyttar ett JavaScript-projekt till TypeScript, och den individuella uppgiften släpps.
UNIONS, NARROWING OCH TYPE GUARDS22 / 22

Unions, narrowing och type guards

By sandra-larsson

Unions, narrowing och type guards

  • 2