Exploring the difference between "any" and "unknown" in TypeScript
Tags: typescript, programming, beginners, webdev
Published: 2023-08-21 13:29:02

## 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

```

## 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
}

```

## 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

- [Everyday Types](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html)
 
😀😄 Hope this article helped you to understand more about difference between `any` vs `unknown`. Happy Coding! 👌👌🧑‍💻