TypeScript Type Assertion

Type assertion is a mechanism that tells the compiler, "I know the type of this value better than you do." It allows developers to manually override TypeScript's type inference results, similar to type conversion in other languages, butit only takes effect during the compilation phase and does not generate any runtime code.。


Two Syntax Forms

There are two ways to write type assertions; it is recommended to consistently use theassyntax; the angle-bracket syntax conflicts with tag syntax in JSX files.

Example

// ① Angle-bracket syntax (not recommended, cannot be used in .tsx files)
const str1: any = "hello";
const len1: number = (<string>str1).length;

// ② as syntax (recommended)
const str2: any = "world";
const len2: number = (str2 as string).length;

console.log(len1);  // 5
console.log(len2);  // 5

Output:

5
5

Note:In React's.tsxfiles, the angle-bracket syntax conflicts with JSX tags, so theassyntax must be used.


Common Use Cases

1. Handling any / unknown types

Data obtained from external interfaces, JSON parsing, and other scenarios is usuallyany; assertions can restore type hints.

Example

const response: any = { name: "Alice", age: 25 };

// Assert as a specific type to get type hints
const user = response as { name: string; age: number };

console.log(user.name);  // Alice
console.log(user.age);   // 25

Output:

Alice
25

2. Narrowing Union Types

When you know the specific branch of a union type but the compiler cannot automatically determine it, you can use an assertion to clearly specify the type.

Example

type Shape =
    | { kind: "circle"; radius: number }
    | { kind: "rect"; width: number; height: number };

function getArea(shape: Shape): number {
    if (shape.kind === "circle") {
        return Math.PI * (shape as { kind: "circle"; radius: number }).radius ** 2;
    }
    const rect = shape as { kind: "rect"; width: number; height: number };
    return rect.width * rect.height;
}

console.log(getArea({ kind: "circle", radius: 5 }).toFixed(2));  // 78.54
console.log(getArea({ kind: "rect", width: 4, height: 6 }));     // 24

Output:

78.54
24

Tip:Prefer using type guards (typeof / instanceof/ discriminant properties) to narrow types; only use assertions in scenarios that guards cannot cover.

3. Manipulating DOM Elements

document.querySelectorThe return type isElement | null; only after asserting it as a specific element type can you access its exclusive properties.

Example

// querySelector returns Element | null
const input = document.querySelector("#username") as HTMLInputElement;

// After assertion, you can access HTMLInputElement's exclusive properties
// console.log(input.value);

// Safer approach: check for null first, then assert
const btn = document.querySelector("#submit");
if (btn) {
    (btn as HTMLButtonElement).disabled = true;
}

Non-null Assertion !

Add!after the value to tell the compiler that the value is notnullorundefined; suitable for scenarios where you are sure it is non-null but the compiler cannot infer it.

Example

function printLength(str?: string) {
    // Use ! to assert that str definitely has a value
    console.log(str!.length);
}

// Runs normally
printLength("hello");  // 5

// Runtime error: Cannot read properties of undefined
// printLength();

Output:

5

Warning:The non-null assertion bypasses the compiler's null check; if the actual value isnull / undefined, it will still throw an error at runtime. When conditions allow, prefer using optional chaining?.instead.


Const Assertion as const

as constInfers literals as the narrowest readonly literal types, commonly used for defining enum values, configuration constants, and tuples.

Example

// Normal declaration: inferred as string[], elements are modifiable
const colors1 = ["red", "green", "blue"];
colors1.push("yellow");  // Allowed

// as const: inferred as readonly ["red", "green", "blue"]; both elements and length are immutable
const colors2 = ["red", "green", "blue"] as const;
// colors2.push("yellow"); // Error: cannot push to a readonly array

// Same for objects: all properties become readonly literal types
const config = {
    host: "localhost",
    port: 3000
} as const;
// config.port = 8080; // Error: readonly property cannot be modified

console.log(colors2);         // ['red', 'green', 'blue']
console.log(config.host);     // localhost
console.log(config.port);     // 3000

Output:

['red', 'green', 'blue']
localhost
3000

Assertion Is Not Type Conversion

Type assertion only affects the compiler's type checking and does not generate any conversion code after compilation. Asserting"42"asnumber, at runtime it is still a string.

Example

const strNum: any = "42";

// Asserted as number, but at runtime it is still a string
const wrongNum = strNum as number;
console.log(typeof wrongNum);    // string (not number!)
console.log(wrongNum + 1);       // 421 (string concatenation, not numeric addition)

// Real type conversion requires conversion functions
const realNum = Number(strNum);
console.log(typeof realNum);     // number
console.log(realNum + 1);        // 43

Output:

string
421
number
43

Double Assertion

When there is no overlap between two types, TypeScript will refuse a direct assertion. In this case, you can useunknownas an intermediary, but this is a dangerous operation and should be avoided as much as possible.

Example

const num = 42;

// Direct assertion: number and string have no overlap, the compiler reports an error
// const str = num as string;

// Double assertion: first assert as unknown, then assert as the target type
const str = num as unknown as string;

console.log(str);          // 42
console.log(typeof str);   // number (runtime type unchanged; assertion only takes effect at compile time)

Output:

42
number

Warning:Double assertion completely bypasses TypeScript's type system and can easily cause runtime errors. Only use it in special cases such as inaccurate types in third-party libraries, and note the reason in the code.


Comparison of Assertion Methods

Assertion method Syntax Typical scenario Risk
as assertionvalue as TypeConverting any to a specific type, DOM operationsLow (has overlap check)
Non-null assertionvalue!Confirming non-null/undefinedMedium (skips null check)
Const assertionvalue as constLiteral constants, enum valuesNone
Double assertionvalue as unknown as TForced conversion when types have no overlapHigh (completely bypasses checks)

Summary

  • Syntax selection:Consistently use theassyntax, and avoid angle-bracket syntax in JSX
  • Assertion vs. conversion:Assertion only affects compile-time types and produces no runtime code; real value conversion requires usingNumber()、String()and other similar functions
  • Non-null assertion:Before using!, ensure the value is truly non-null; otherwise it will error at runtime. When conditions allow, prefer using?.
  • Const assertion:as constis a safe and practical assertion, recommended for configuration objects and constant arrays
  • Double assertion:is the last resort; you must comment on the reason when using it

Other Related Content