YouTip LogoYouTip

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 * * *
← Ts SymbolTs Enum β†’