Understanding the Difference Between `void` and `never` in TypeScript
Understanding the Difference Between void and never in TypeScript When working with TypeScript, we may encounter various utility types that help …
Two important tools in the TypeScript type system are type inference and type assertion. While they sound similar, they serve different purposes and are used in different scenarios.
In this blog post, I’ll break down what type inference and type assertion are, how they work, when to use them, and common pitfalls to avoid.
Type inference is the process by which TypeScript automatically determines the type of a variable, parameter, or return value based on its usage or value. This means you don’t always have to explicitly declare a type.
let message = "Hello, world!";
// TypeScript infers that message variable is of type string
function add(a: number, b: number) {
return a + b;
}
// The function's return type is inferred as number
If the compiler has enough information, it will automatically assign the correct type. This makes your code more concise and readable.
TypeScript performs inference in several scenarios:
const numbers = [1, 2, 3]; // inferred as number[]
const first = numbers[0]; // inferred as number
Type assertion is a way to tell TypeScript “I know better than you what the type is.” It’s like a type cast but only for TypeScript’s type system—no actual casting happens at runtime.
const value = someUnknown as string; // preferred
const value = <string>someUnknown; // works but not recommended in JSX
const input = document.querySelector("#username") as HTMLInputElement;
input.value = "TypeScript";
Here, querySelector
returns Element | null
, which doesn’t have a value
property. But if you know it’s an HTMLInputElement
, you can assert it, and TypeScript will allow you to access value
.
Type assertions do not change the runtime behavior. They are purely a compile-time construct.
let num = "123" as unknown as number;
console.log(num + 1); // outputs "1231", not 124
You asserted string
to unknown
, then to number
, but it’s still a string at runtime.
unknown
or any
Feature | Type Inference | Type Assertion |
---|---|---|
Who decides the type? | TypeScript compiler | You, the developer |
Syntax | Implicit (let a = 5 ) |
Explicit (value as Type ) |
Use case | Safe, common-case types | Edge cases, complex structures |
Risk of error | Low | Higher if misused |
Changes runtime behavior? | No | No |
Sometimes, inference and assertion go hand in hand.
const data = JSON.parse('{"name": "Alice"}') as { name: string };
Here, JSON.parse()
returns any
, so no inference is possible. You use an assertion to tell the compiler what to expect.
Avoid unnecessary type annotations if TypeScript can infer them correctly.
// ✅ Good
const count = 42;
// ❌ Redundant
const count: number = 42;
Use type assertions only when you’re confident the type is correct.
// ✅ Reasonable
const canvas = document.getElementById("myCanvas") as HTMLCanvasElement;
// ❌ Dangerous (input could be null)
const input = document.querySelector("input") as HTMLInputElement;
input.value = "hello"; // runtime error if input is null
Better approach:
const input = document.querySelector("input");
if (input instanceof HTMLInputElement) {
input.value = "hello";
}
any
and unknown
When dealing with any
or unknown
, it’s tempting to use assertions, but be sure you understand the risks.
function handle(data: any) {
const user = data as { name: string }; // easy to get wrong
}
Instead, consider validating the shape of the data or using type guards.
const age = "30" as number; // No error, but it's still a string
You’ve told TypeScript it’s a number, but at runtime it’s a string. Be cautious with cross-assertions like this.
null
or undefined
const el = document.querySelector("#id") as HTMLElement;
el.innerText = "hello"; // May throw if el is null
Use null checks or non-null assertions (!
) carefully:
const el = document.querySelector("#id")!;
el.innerText = "hello"; // Safe if you're 100% sure it's not null
Understanding the distinction between type inference and type assertion is essential for writing robust TypeScript code.
Use type assertions sparingly and responsibly, and lean on inference and proper typing to make your code more predictable and safe.
By mastering these tools, you’ll write better, cleaner, and more maintainable TypeScript.
Understanding the Difference Between void and never in TypeScript When working with TypeScript, we may encounter various utility types that help …
In version 4.0 TypeScript fixed a ‘bug’ in a try/catch block, where the error was of type any. The any type allowed, well, …