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
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
// 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
| { 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
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
// 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 is
null/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
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
// 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
// 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 assertion | value as Type | Converting any to a specific type, DOM operations | Low (has overlap check) |
| Non-null assertion | value! | Confirming non-null/undefined | Medium (skips null check) |
| Const assertion | value as const | Literal constants, enum values | None |
| Double assertion | value as unknown as T | Forced conversion when types have no overlap | High (completely bypasses checks) |
Summary
- Syntax selection:Consistently use the
assyntax, 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 using
Number()、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