Hoppa till innehållet

TypeScript

JavaScript med typer som kontrolleras innan det körs

Vad det är

Microsoft står bakom TypeScript, ett programspråk som lägger till typannoteringar i JavaScript och levereras med en kompilator, tsc, som kontrollerar dem. Namnet förkortas ofta TS, och filerna slutar på .ts, eller på .tsx när de innehåller JSX-markering. All syntax i JavaScript är giltig TypeScript, och därför kallas språket en övermängd (superset) av JavaScript. Kompilatorn är öppen källkod under Apache License 2.0.

Typerna lever bara så länge kontrollen pågår. När kompilatorn har kontrollerat ett program raderar den varje annotering, och det som kommer ut är vanlig JavaScript utan typinformation och utan något extra bibliotek vid körning. TypeScript ändrar aldrig hur koden beter sig när den körs. Det enda faktumet förklarar både värdet och gränserna: typkontrollen kan resonera om allt som står i källkoden och om ingenting som kommer in medan programmet kör.

Typsystemet är strukturellt. Två typer är kompatibla när deras form stämmer, oavsett vad de heter, och det passar vanan i JavaScript att skicka runt vanliga objekt. C# och Java jämför i stället deklarerade namn. En stor del av typerna härleds, så annoteringarna sitter mest på funktionssignaturer och exporterade värden. Systemet är också med avsikt osunt (unsound) på några ställen. any stänger av kontrollen för ett värde, och en typförsäkran skriven med as säger åt kompilatorn att lita på programmerarens ord om en typ. Båda försvinner ur utdata tillsammans med allt annat.

Det finns tre vanliga sätt att köra språket. tsc kontrollerar ett projekt och genererar JavaScript. Paketerare (bundlers) som esbuild skalar bort typerna utan att kontrollera dem och lämnar kontrollen åt en separat körning av tsc --noEmit. Node.js kör sedan v23.6.0 och v22.18.0 .ts-filer direkt genom att ersätta typsyntaxen med blanksteg, även det utan typkontroll, och godtar bara syntax som går att radera på det sättet. TypeScript 7.0, som tillkännagavs i juli 2026, är en portering av kompilatorn till Go, och teamet uppger att den vanligtvis är 8–12 gånger snabbare vid fullständiga byggen.

Varför det spelar roll

Frågan ett team besvarar är om ett byggsteg och en typkontroll gör sig förtjänta av sin plats genom att fånga fel innan koden körs. I en kodbas som flera personer ändrar varje vecka gör de oftast det. Byter du namn på ett fält visas varje ställe som använde det, editorn kompletterar och förklarar kod utifrån typerna, och signaturen för en modul blir ett kontrakt som anroparna inte kan bryta i tysthet. Kostnaden är en kontroll i varje pipeline, en konfigurationsfil med många alternativ och typdefinitioner som måste hålla jämna steg med biblioteken de beskriver.

Striktheten är den inställning som betyder mest. Flaggan strict slår på en hel familj av kontroller, bl.a. strictNullChecks och noImplicitAny, och handboken beskriver resultatet som en ratt snarare än en strömbrytare. Sedan TypeScript 6.0 är flaggan på som standard, så ett nytt projekt börjar strikt. Ett äldre kan fortfarande sätta den till false, och att slå på den i efterhand innebär att gå igenom varje fil den berör. Två nyttiga kontroller ligger utanför familjen och måste slås på var för sig: noUncheckedIndexedAccess och exactOptionalPropertyTypes.

Raderingen sätter gränsen. Ett program som läser JSON från en nätverksförfrågan, en fil, en kö eller ett formulär har bara programmerarens ord för hur de data ser ut, eftersom typerna är borta när data kommer in. Gränserna behöver därför validering vid körning, helst genererad från samma schema som typerna, så att kontrollen och typen inte kan säga emot varandra. TypeScript gör insidan av ett program konsekvent och lämnar kanterna åt koden.

Typkontrollen matar också andra verktyg. En linter som typescript-eslint kan be kompilatorn om typinformation, så att en regel kan flagga ett promise som ingen väntar in eller ett värde av typen any som sprider sig genom en modul. Så gör ett team sina egna konventioner till fel i stället för till kommentarer i granskningen.

Så ser det ut i praktiken

I projekten som visas på den här webbplatsen hålls TypeScript ärligt av genererad kod och av verktyg snarare än av konvention. Tre sidor visar hur.

På en plattform skrivs TypeScript-klienten för frontenden aldrig för hand. Den genereras från API:ets egen beskrivning, som Huma tar fram ur Go-typerna, som i sin tur följer databasschemat och dess funktioner. Klienten är på 44 076 rader, och 61 mock-hanterare som genereras bredvid den låter frontendens tester köras mot det verkliga kontraktet i stället för mot en handskriven fixture. Varje led har sitt eget skydd. En kontraktskontroll i CI jämför vad frontenden skickar med vad API:et förväntar sig och stoppar bygget när de skiljer sig åt, med en schemasond under som undersöker de verkliga strukturerna. Den täcker valfria fält i anropets body, där ”saknas” och ”null” lätt blandas ihop, och enum-värden i query-parametrar. Ett fält som ändras på ena sidan fäller nu ett bygge minuter efter ändringen, i stället för att dyka upp som en 422 i webbläsaren när avvikelsen redan har släppts. Sidan nämner också priset: ett genereringssteg mitt i allt.

En annan sida sätter en och samma ribba för sex språk, och TypeScript är ett av dem. Varje diagnostikmeddelande som ESLint rapporterar är ett fel, det finns ingen varningsnivå att gömma sig i, och undertryckningar direkt i koden är förbjudna, så ett fynd måste åtgärdas i stället för att tystas. Hookar för pre-commit och pre-push kör linters och tester, och gränser för längden på funktioner och filer håller modulerna läsbara.

De lintverktyg som följer med ett språk stannar före ett projekts egna regler, så femton egna ESLint-regler håller fast vid repots etablerade mönster i TypeScript. Reglerna ingår i en vaktmotor där 268 av totalt 274 kontrollskript anropas från commit-hookarna, och eftersom ett fel i en vakt skulle släppa igenom allt utan att någon märker det prövas vakterna själva av 146 tester. En regel gäller tester snarare än typer: en commit med prefixet fix: måste innehålla ett test som fallerar utan rättelsen. Tiden i kodgranskningen flyttades från mekanik till design, och sidan säger rakt ut vad det kostar: det går långsamt att committa.

Var det går fel

De flesta fel med TypeScript kommer av att man litar på typerna längre än kompilatorn kan se.

Ett fält som är typat som sträng visar sig vara undefined vid körning. Data kom utifrån programmet och fick en typ i stället för att kontrolleras. DOM-biblioteket typar res.json() som ett promise av any, så kompilatorn godtar vad koden än gör med resultatet, och en typförsäkran gör förtroendet uttryckligt utan att göra det säkert:

const res = await fetch("/api/user");
const user = (await res.json()) as User; // trusted, never checked
user.email.toLowerCase(); // TypeError if email is missing

Behandla data utifrån som unknown, validera dem vid gränsen med ett schema som körs, och generera typen från det schemat så att de två håller jämna steg. En typmedveten lintregel kan sedan flagga varje any som slinker igenom.

Kod med typfel når produktion ändå. tsc skriver fortfarande JavaScript när den rapporterar fel, eftersom noEmitOnError som standard är false, och paketerare och Node.js skalar bort typerna utan att kontrollera dem alls. Kör tsc --noEmit som ett obligatoriskt steg i CI och i pre-commit-hooken, och låt bygget fallera på dess slutkod.

En indexuppslagning ger undefined, fast typen uteslöt det. Ett element i en array, eller en nyckel som läses via en indexsignatur, typas som alltid närvarande, även förbi arrayens slut. Slå på noUncheckedIndexedAccess, som lägger till undefined i de läsningarna och tvingar koden att hantera det. Kombinera den med exactOptionalPropertyTypes, som skiljer en egenskap som saknas från en som är satt till undefined.

En fil som kompilerar med tsc stannar när Node.js kör den. Att skala bort typer tar bara bort syntax som saknar betydelse vid körning. Enums och namespaces som innehåller värden får Node.js att avbryta med ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX, och en typ som importeras utan nyckelordet type behandlas som en import av ett värde, som fallerar vid körning. Slå på erasableSyntaxOnly och verbatimModuleSyntax så att kompilatorn rapporterar båda innan Node.js gör det, skriv import type för typer och ersätt enums med objektliteraler markerade as const.

Läs mer

  • TypeScript Documentation — handboken, referenssidorna och versionsanteckningarna, underhållna av TypeScript-teamet.
  • The Basics — handbokens kapitel om statisk kontroll, utdata trots fel, raderade typer och strikthet.
  • TSConfig Reference: strict — varje kompilatoralternativ med sitt standardvärde, bl.a. de kontroller som flaggan strict slår på.
  • Type Compatibility — strukturell subtypning och de ställen där typsystemet med avsikt är osunt.
  • Node.js: Modules: TypeScript — hur typerna skalas bort, den syntax som avvisas och de kompilatorinställningar som Node.js rekommenderar.
  • Linting with Type Information — hur typescript-eslint ger lintregler tillgång till typkontrollen.

Ordlista