DEV Community

Isuru Maldeniya
Isuru Maldeniya

Posted on

Exploring the difference between "any" and "unknown" in TypeScript

Introduction

TypeScript, a widely adopted statically typed superset of JavaScript, elevates the level of type checking and overall code robustness within your projects. Amidst TypeScript's arsenal of type constructs, the "any" and "unknown" types emerge as versatile tools, offering pathways to navigate the complexities of uncertain or dynamically evolving data. Though these types might share a surface resemblance, delving deeper unravels their unique behaviors and distinct applications. This article ventures into the intricate realm of TypeScript's "any" and "unknown" types, shedding light on their disparities and furnishing invaluable guidance on the opportune application of each.

Understanding the basics

TypeScript introduces static typing to JavaScript so that we can easily identify errors within our code in compiler time rather than in runtime. Types have proven ability to enhance code quality and understandability.
However, there are instances where the nature of the data is either unknown or resistant to type constrictions. This is where the "any" and "unknown" types come into play. Both types can be thought of as escape hatches or safety valves that allow developers to circumvent strict type-checking when necessary.

The any type

The any type allows values of any type to be assigned to it, essentially disabling type checking for that particular value or variable. It provides maximum flexibility but sacrifices type safety. The compiler won't give any errors or warnings if you perform incompatible operations or access properties that may not exist.

let value: any;

value = 5; // No error, as any type allows any value
console.log(value.toFixed()); // No error, but may cause a runtime error if the value is not a number

value = "Hello";
console.log(value.length); // No error, but may cause a runtime error if the value does not have a length property

value = { foo: "bar" };
console.log(value.baz); // No error, but may cause a runtime error if the `baz` property doesn't exist

Enter fullscreen mode Exit fullscreen mode

When to use any

  • JavaScript migration: when transitioning the JavaScript code base to a TypeScript code base you can use any, allowing you to maintain compatibility while gradually introducing stricter type later.

  • Third-Party Libraries: When incorporating third-party JavaScript libraries lacking TypeScript type definitions, using the "any" type can be a practical solution. It allows you to interact with these libraries without extensive type annotations, albeit at the cost of some degree of type safety.

  • Heterogeneous Data: Working with data structures that contain elements of different types, like arrays that hold various data objects, can be simplified using the any type. This can be especially helpful when dealing with APIs that produce mixed data without a clear structure.

Drawback of using any

  • Type safety scarifies: when using any, it completely bypasses the powerful type system in TypeScript negating the benefit of static typing. This can lead to runtime errors and difficulties in identifying errors during development.

  • Refactoring Challenges: As projects evolve, code needs to be refactored and extended. However, codebases heavily reliant on any types can hinder this process, as type information is lost, making it harder to ensure code correctness during changes.

The unknown type

The unknown type is a type-safe counterpart of any. It represents values that are of an unknown type at compile time. Unlike any, you cannot perform arbitrary operations or access properties on values of type unknown without proper type checking or assertions. It enforces developers to perform type checks before using the value.

let value: unknown;

value = 5;
// console.log(value.toFixed()); // Error: Object is of type 'unknown'

if (typeof value === "number") {
  console.log(value.toFixed()); // No error, type check ensures it's a number
}

value = "Hello";
// console.log(value.length); // Error: Object is of type 'unknown'

if (typeof value === "string") {
  console.log(value.length); // No error, type check ensures it's a string
}

value = { foo: "bar" };
// console.log(value.baz); // Error: Object is of type 'unknown'

if (typeof value === "object" && value !== null) {
  console.log(value.baz); // No error, type check ensures it's an object and `baz` may not exist
}

Enter fullscreen mode Exit fullscreen mode

When to use unknown

  • Accessing external data sources: when interacting with external APIs or data sources the nature of incoming data may be uncertain. In these scenarios, we can use unknown to validate incoming data before proceeding to reduce runtime errors.

  • Type checking enforcement: The unknown is an enforcer of robust type checking. It ensures that before proceeding you always do a type validation which diminishes the risk of unexpected behavior.

Type safety and refactoring

The difference between any and unknown becomes more evident when considering code evolution and maintenance. Consistency using any can lead to a brittle codebase. During refactoring due to loss of type information when using any can lead to unexpected errors emerging, making the process of code modification extremally hard.
On the other hand, the unknown allows us to write refactor-friendly code. Its requirement for explicit type validation forces developers to consider type implications as they evolve the codebase. As a result, when you refactor code using "unknown," TypeScript guides you through the changes needed to maintain type safety, ensuring that your modifications align with the expected data types.

Best practices

To sum up the usage between any and unknown,

  • Use any if type information is inaccessible or incompatible, and ensure that clear strategies are in place to mitigate its downsides.

  • Use unknown when using external data sources, enforcing type checking, and enhancing code stability during refactoring.

In conclusion by leveraging the capabilities of "unknown" and using "any" judiciously, developers can strike a balance between flexibility and type safety, leading to more robust and adaptable TypeScript codebases.

Additional resources

😀😄 Hope this article helped you to understand more about difference between any vs unknown. Happy Coding! 👌👌🧑‍💻

Top comments (0)