let a = "dark"; // string
const b = "dark"; // "dark"
const obj = { mode: "dark" }; // { mode: string }
const fixed = { mode: "dark" } as const; // { readonly mode: "dark" }
TypeScript reads the value you assign and uses its type, so most local variables need no type annotation. This is called inference.
When the value is a literal like "dark", TypeScript must choose how specific the type should be. Making it general is called widening:
- A
letcan be reassigned later. Solet a = "dark"is widened tostring. - A
constprimitive can never change. Soconst b = "dark"keeps the literal type"dark". - Object properties and array elements can still change, even inside a
constobject. So they are widened too:{ mode: "dark" }becomes{ mode: string }.
as const turns widening off for the whole expression. It does three things:
- Every literal keeps its literal type.
- Object properties become
readonly. - Arrays become readonly tuples (fixed-length arrays where each position has its own type).
It is useful for config objects and lookup tables. It also lets you build a union type from a list of values.
- TypeScript infers a type from the assigned value, so most local variables need no annotation.
- Add annotations at function boundaries, like parameters, not on every local variable.
letwidens a literal like"dark"tostringornumber.- A
constprimitive keeps its literal type, like"dark". - Object properties and array elements are widened, even inside a
constobject. as constkeeps literal types and makes everything readonly. Arrays become readonly tuples.
Read more