Skip to main content

understanding-any-vs-unknown

Understanding 'any' vs. 'unknown':

1. The Basics of Flexibility and Safety:

Using any in TypeScript gives you complete freedom but at the cost of safety, while unknown keeps the safety net intact and makes sure you check types before you use them.

2. The 'any' Type:

any is a way to tell TypeScript to back off and let you do your thing. It's like a wildcard, allowing you to work with variables without worrying about types.

let mystery: any = 'hello';
mystery = 123; // No error, because mystery is of type any.

3. The Risks of 'any':

Using any too much is like walking a tightrope without a safety net. It seems fine until something goes wrong, and TypeScript can't save you because it doesn't know what type things are supposed to be.

let risk: any = 'hello';
console.log(risk.trim()); // Works fine.
risk = null;
console.log(risk.trim()); // Runtime error, but TypeScript didn't catch it.

4. The 'unknown' Type:

unknown is like a question mark. TypeScript knows there's something there, but won't let you use it until you've proven what it is with some sort of check.

let puzzle: unknown = 'hello';
// console.log(puzzle.trim()); // Error: Object is of type 'unknown'.

5. Type Assertions with 'unknown':

Before you can use an unknown value, you need to convince TypeScript that you know what you're doing, either by asserting the type you expect or by checking it properly.

let enigma: unknown = 'hello';
console.log((enigma as string).trim()); // Now TypeScript is okay with it because of the type assertion.

6. Type Guarding:

Type guards are like checkpoints. They make sure that only the right types of values get through, which lets you avoid unexpected errors.

function doSomething(value: unknown) {
if (typeof value === 'string') {
console.log(value.trim()); // Safe to call string methods.
}
}

7. Function Return Types:

When a function returns unknown, it's like it's handing you a box that could contain anything. You need to check what's inside before you use it.

function getValue(): unknown {
return 'secret message';
}

const value = getValue();
if (typeof value === 'string') {
console.log(value.trim()); // We've checked the value, so it's safe.
}

These concepts show how TypeScript balances flexibility and safety, giving you the tools to write robust code while maintaining the dynamic nature of JavaScript when needed.

8. Third-party Libraries and 'any':

When you're working with code someone else wrote, and there's no type information, any is a common fallback. But to keep things safe, try to define the types yourself, or use unknown and narrow down as needed.

9. The Impact on Code Maintenance:

Using unknown forces you to think about types, which means your code is more likely to be correct and easier to understand later on. It's like leaving a map for anyone who follows.

10. Compiler Configuration:

The TypeScript compiler can be set up to discourage any. Turning on noImplicitAny means the compiler will ask you to be explicit about types, which is a good way to catch mistakes early.

{
"compilerOptions": {
"noImplicitAny": true
}
}

11. The 'unknown' and TypeScript's Control Flow Analysis:

TypeScript can be really smart about unknown types, figuring out what they are based on how you use them. But it can't do the same tricks with any.

12. Error Handling:

When you catch errors, they're just any by default. But treating them as unknown and checking the type can prevent new errors from sneaking in.

try {
// Some operation that might fail
} catch (error: unknown) {
if (error instanceof Error) {
console.log(error.message);
}
}

13. The 'any' and JSON Parsing:

When you parse JSON, TypeScript just assumes it could be anything. To be safer, say it's unknown and then figure out exactly what type it should be.

const jsonResponse = '{"name":"Alice","age":30}';
const parsed = JSON.parse(jsonResponse) as unknown;
// Now perform type checks to narrow down the 'unknown' type.

14. Using 'unknown' in Generics:

In generic code, if you start with unknown, you're making sure that the code that uses your generic has to be clear about what type it's working with.

function identity<T = unknown>(arg: T): T {
return arg;
}

15. Advanced Type Narrowing:

unknown plays well with complex type-checking techniques, like when you write your own type checks, making your code much more precise and easier to keep correct.

These are advanced techniques that help you write safer and more maintainable TypeScript code, especially as your codebase grows and changes over time.