Ts Assertion
Type Assertion (Type Assertion) is a mechanism that tells the compiler "I know the type of this value better than you". It allows developers to manually override TypeScript's type inference results, similar to type casting in other languages, but **it only takes effect at compile time and does not generate any runtime code**.
* * *
## Two Syntax Forms
There are two ways to write type assertions. It is recommended to consistently use the `as` syntax, as 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 =(str1).length;
// β‘ as syntax (recommended)
const str2: any ="world";
const len2: number =(str2 as string).length;
console.log(len1);// 5
console.log(len2);// 5
**Result:**
55
> **Note:** In React's `.tsx` files, the angle bracket syntax conflicts with JSX tags, so the `as` syntax must be used.
* * *
## Common Usage Scenarios
### 1. Handling any / unknown types
Data obtained from external interfaces, JSON parsing, and similar scenarios is usually `any`. Assertions can restore type hints.
## Example
const response: any ={ name:"Alice", age:25};
// Assert as specific type to get type hints
const user = response as { name: string; age: number };
console.log(user.name);// Alice
console.log(user.age);// 25
**Result:**
Alice25
### 2. Narrowing union types
When you know the specific branch of a union type but the compiler cannot automatically determine it, you can use assertions to clarify 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
**Result:**
78.5424
> **Tip:** Prefer using type guards (`typeof` / `instanceof` / discriminant properties) to narrow types. Only use assertions when guards cannot cover the scenario.
### 3. Operating DOM elements
`document.querySelector` returns `Element | null`. You need to assert it as a specific element type before accessing 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 before asserting
const btn = document.querySelector("#submit");
if(btn){
(btn as HTMLButtonElement).disabled=true;
}
* * *
## Non-null assertion !
Adding `!` after a value tells the compiler that the value is not `null` or `undefined`. This is suitable for scenarios where you can ensure non-nullness 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();
**Result:**
5
> **Warning:** Non-null assertions bypass the compiler's null checks. If the actual value is `null` / `undefined`, a runtime error will still be thrown. Prefer using optional chaining `?.` when conditions allow.
* * *
## Const assertion as const
`as const` infers literals as the narrowest possible readonly literal types. It is commonly used for defining enum values, configuration constants, and tuples.
## Example
// Regular declaration: inferred as string[], elements can be modified
const colors1 =["red","green","blue"];
colors1.push("yellow");// Allowed
// as const: inferred as readonly ["red", "green", "blue"], elements and length cannot be changed
const colors2 =["red","green","blue"] as const;
// colors2.push("yellow"); // Error: Cannot push to readonly array
// Same for objects: all properties become readonly literal types
const config ={
host:"localhost",
port:3000
} as const;
// config.port = 8080; // Error: Cannot modify readonly property
console.log(colors2);// ['red', 'green', 'blue']
console.log(config.host);// localhost
console.log(config.port);// 3000
**Result:**
['red', 'green', 'blue'] localhost 3000
* * *
## Assertion is not type conversion
Type assertions only affect the compiler's type checking and do not generate any conversion code after compilation. Asserting `"42"` as `number` means it is still a string at runtime.
## Example
const strNum: any ="42";
// Asserted as number, but still string at runtime
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
**Result:**
string421 number 43
* * *
## Double assertion
When two types have no overlap, TypeScript will reject direct assertions. In this case, you can use `unknown` as an intermediary, but this is a dangerous operation and should be avoided when possible.
## Example
const num =42;
// Direct assertion: number and string have no overlap, compiler error
// const str = num as string;
// Double assertion: first assert as unknown, then assert as target type
const str = num as unknown as string;
console.log(str);// 42
console.log(typeof str);// number (runtime type unchanged, assertion only effective at compile time)
**Result:**
42 number
> **Warning:** Double assertions completely bypass TypeScript's type system and can easily cause runtime errors. Only use when dealing with inaccurate third-party library types and other special cases, and document the reason in your code.
* * *
## Assertion Methods Comparison
| Assertion Method | Syntax | Typical Scenarios | Risk |
| --- | --- | --- | --- |
| as assertion | `value as Type` | any to specific type, DOM operations | Low (has overlap check) |
| Non-null assertion | `value!` | Confirm non-null/non-undefined | Medium (skips null check) |
| Const assertion | `value as const` | Literal constants, enum values | None |
| Double assertion | `value as unknown as T` | Force conversion when types don't overlap | High (completely bypasses checks) |
* * *
## Summary
* **Syntax choice:** Consistently use `as` syntax, avoid angle bracket syntax in JSX
* **Assertion vs Conversion:** Assertions only affect compile-time types and do not generate runtime code. Real value conversion requires functions like `Number()`, `String()`, etc.
* **Non-null assertion:** Ensure the value is truly non-null before using `!`, otherwise runtime errors will occur. Prefer `?.` when conditions allow
* **Const assertion:** `as const` is a safe and practical assertion, recommended for configuration objects and constant arrays
* **Double assertion:** Last resort only, must include comments explaining the reason when used
* * *
YouTip