Typescript is a statically typed superset of JavaScript that adds optional type annotations, enabling better tooling and better prevention for runtime errors. Its type-checking system is structural, meaning it checks types based on their shape (not just names). At its core, TypeScript aims to balance flexibility and safety, allowing dynamic JavaScript code while catching common mistakes before runtime.
Flexible Types: any and unknown
any: It is disabling the type checks. It can hold any value, and you can perform any operation on it, but it removes type safety.
let valueAny: any = "Hello";
unknown: It also accepts any values, like any but strict usage, until you perform type checks. It provides flexibility without giving up safety.
let valueAny: any = "Hello";
Practical Examples
Using any:
Now we have a basic understanding of both variables, and as we have read, any disables type checking, which may cause us issues while runtime lets discuss with scenarios where we can understand deeply.
function fetchDataAny(name: any): any {
return name;
}
const data1 = fetchDataAny("Sudhir");
console.log(data1.toUpperCase());
In this example, TypeScript will not generate any error at compile time but crashes at runtime because toUpperCase() is called on a number, like in below example.
function fetchDataAny(name: any): any {
return name;
}
const data1 = fetchDataAny(20);
console.log(data1.toUpperCase());
If we pass a number instead of a string, the application will crash at run time. If an application is large, then it is difficult to trace and debug for the developer.
Using any:
Now we have a basic understanding of both variables, and as we have read, any disables type checking, which may cause us issues while runtime lets discuss with scenarios where we can understand deeply.
function fetchDataAny(name: any): any {
return name;
}
const data1 = fetchDataAny("Sudhir");
console.log(data1.toUpperCase());
In this example, TypeScript will not generate any error at compile time but crashes at runtime because toUpperCase() is called on a number, like in below example.
function fetchDataAny(name: any): any {
return name;
}
const data1 = fetchDataAny(20);
console.log(data1.toUpperCase());
If we pass a number instead of a string, the application will crash at run time. If an application is large, then it is difficult to trace and debug for the developer.
Using unknown:
With unknown, TypeScript enforces a type check before usage. If a non-string value is passed, the error is caught at runtime in a controlled way; in many cases, like linters or compilers, it will even highlight the issue beforehand. This makes your codebase more robust and easier to maintain.
function fetchDataUnknown(name: unknown): { name: string } {
if (typeof name !== "string") {
throw new Error("Invalid argument: 'name' must be a string.");
}
return { name };
}
const data2 = fetchDataUnknown("Sudhir");
console.log(data2.name.toUpperCase());
The above example helps prevent runtime errors by enforcing type checks before using the value. If a number is passed instead of a string, the function will throw a clear runtime error: 'Invalid argument: 'name' must be a string.
Conclusion
The unknown type is preferred over any when you want to accept any value but still ensure type safety before using it. While any removes all type restrictions, potentially introducing hidden bugs, unknown forces explicit type validation, helping prevent runtime crashes and making your code safer and more predictable.
Happy Coding 🙂
Top comments (0)