You sure know that any
in TypeScript is bad and should be avoided. But what should you replace it with?
When the type is unknown throughout the application: If the type is unknown in the entire application, such as when receiving data from an untrusted third-party API, the unknown
type is your best choice. It's the type-safe counterpart of any
and informs TypeScript that the type is unknown until you validate it at runtime. You can validate the type using methods like Array.isArray()
or the typeof
operator:
function foo(value: unknown) {
if (Array.isArray(value)) {
console.log("Number of items: " + value.length);
} else if (typeof value === "string") {
console.log(value.toLowerCase());
}
}
When the type is unknown in a specific context: Sometimes, your type might be unknown in one part of the application (where you don't care about the type) but known in another part. If you try to replace any
with unknown
in this case, you will likely encounter errors.
const addValidationFn = (fn: ((value: unknown) => boolean)) => { };
addValidationFn((value: number) => { });
In this case, TypeScript is correct. Inside addValidationFn
, you could call the provided function with any value because you've specified that the type is unknown, and any value is assignable to unknown
. Therefore, providing a function that expects a number is not valid.
In such scenarios, you should use generics:
const addValidationFn = <V,>(fn: ((value: V) => boolean)) => { };
addValidationFn((value: number) => { });
Generics allow you to capture the type information while maintaining type safety. In the above example, V
is a placeholder for any type, and it will be determined when addValidationFn
is called.