value as Type is a type assertion: it tells TypeScript to treat value as Type. People call it a cast, but it is only an instruction to the compiler. It is erased from the JavaScript output, converts nothing and checks nothing at run time.
This is the typical use: you know more about a value than the compiler can (here, the shape of some JSON), and you say so. If you are wrong, nothing warns you. The next sections show what that means and when a runtime check is the better choice.
as and the Angle-Bracket Syntax
There are two spellings of the same assertion:
const someValue: unknown = "hello";
const a = someValue as string; // as syntax
const b = <string>someValue; // angle-bracket syntax, same meaning
The angle-bracket form is not allowed in .tsx files, where <string> would read as a JSX tag. Use as everywhere and the question never comes up. Assertions bind loosely, so wrap them in parentheses when you continue the expression: (value as string).length.
Assertions Do Not Convert Values
This is the part that causes real bugs. An assertion changes what the compiler believes about a value, not the value itself:
The compiler believes asserted is a number, so asserted + 1 type-checks as arithmetic. At run time it is still the string "42" and JavaScript concatenates. To change a value's type, convert it: Number(x), String(x), Boolean(x), BigInt(x), new Date(x). The string to number page compares the conversion functions.
| You want to | Write | Runtime effect |
|---|---|---|
| Tell the compiler a type you know | x as T | none |
| Turn a string into a number | Number(x), parseInt(x, 10) | converts |
| Turn anything into a string | String(x), `${x}` | converts |
| Check the type first | a type guard, typeof, instanceof | checks |
What the Compiler Allows
as is not unlimited. TypeScript allows x as T when one type is assignable to the other: widening ("a" as string, dog as Animal) and narrowing (animal as Dog, unknown as User) are both fine. When the types do not overlap at all, it refuses:
The compiler reports index.ts(3,11): error TS2352: Conversion of type 'string' to type 'number' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first. The message itself names the escape hatch: input as unknown as number. That double assertion compiles, and it is exactly as wrong at run time as the example above. When you feel the need for it, the right fix is usually a conversion (Number(input)) or a different type.
The overlap rule is loose for objects. An object literal that has some of the properties is accepted, which is how as quietly lets incomplete objects through:
An annotation (const draft: User = { name: "Ada" }) or satisfies User would report the missing email (TS2741). Use as on an object literal only when you really intend to fill it in later, and prefer building the complete object.
as const Is Different
as const looks like an assertion but does the opposite of loosening: it makes a literal as narrow as possible. Strings stay literal types, arrays become readonly tuples, and object properties become readonly.
It is safe, because it describes the literal exactly rather than claiming something the compiler cannot see. (The sizes as readonly string[] inside isSize is a widening assertion, also safe: it lets includes accept any string.) See literal types for more.
When a Type Guard Is the Better Tool
as is a claim; a type guard is a check. At a boundary where data comes from outside your code (JSON, fetch, localStorage, user input, a message), the claim can be false, and an assertion turns a clear error at the boundary into a confusing one somewhere else.
A rough guide to the tools that look alike:
| Tool | Checks at compile time | Checks at run time | Use when |
|---|---|---|---|
Annotation const x: T = ... | yes, fully | no | you build the value yourself |
satisfies T | yes, fully, keeps the inferred type | no | object literals, config |
as T | only "do the types overlap" | no | you know more than the compiler |
x! | removes null / undefined only | no | you know a value is set |
Type guard x is T | the guard's body is ordinary code | yes | data from outside |
Two good uses of as remain: narrowing something the compiler cannot follow (a Map entry you set two lines earlier, a value from an untyped library), and test code that builds partial fixtures. Keep them small and close to the place where you know the claim is true.
Frequently Asked Questions
What does as do in TypeScript?
value as Type is a type assertion: it tells the compiler to treat value as Type from here on. It is removed from the compiled JavaScript, so it performs no conversion and no runtime check. If the assertion is wrong, the program fails later, wherever the wrong type is used.
How do I cast a type in TypeScript?
TypeScript has no runtime casts. Use as (or the older <Type>value) to change the static type when you know more than the compiler. To actually convert a value, call a function: Number("42"), String(42), Boolean(x), new Date(text).
What does "as unknown as" mean in TypeScript?
A double assertion. TypeScript refuses x as T when the two types do not overlap at all (error TS2352), and going through unknown first bypasses that check, because anything can be asserted to and from unknown. It switches off type checking for that value entirely, so reserve it for tests and for code where you have verified the type another way.
What is the difference between as and angle brackets in TypeScript?
None in meaning: <string>value and value as string are the same assertion. The angle-bracket form cannot be used in .tsx files because it clashes with JSX, so as is the form everyone uses.
What is the difference between as and satisfies?
as overrides the inferred type and checks very little (missing properties are allowed). satisfies checks the value against a type, reporting missing or extra properties, and keeps the precise inferred type. Prefer satisfies for object literals and as only when you really know more than the compiler.