5 ms·
The difference between `any` and `unknown` is that `any` is an escape hatch from the type system. `any` can be used anywhere and will satisfy any type constrain
by maxfurman 4y ago
The difference between `any` and `unknown` is that `any` is an escape hatch from the type system. `any` can be used anywhere and will satisfy any type constraint. `any` is how the developer says to the type system "trust me, I know what I'm doing, don't worry about this particular value." Unknown, on the other hand, is for untyped code from an imported JS library, JSON data received from the network that may or may not match the API spec, etc. Code that does have a type, but that type needs to be confirmed at runtime and can be narrowed through type guards.
- thoughtspile 4y agoI think "unknown" is more than that! Basically it's a way to say you don't care about the type, as in Record<string, unknown> or P extends Promise<unknown>
- jax_the_dog 4y agoHow is unknown better than any in this case? If you do not care about the data type, wouldn’t you say that “any” data type is acceptable? If you say “unknown” that means that there is possibly some data type that would break your function.
- madeofpalk 4y agoThe problem with using any where you don't care about the type is that someone can come along and make unchecked assumptions about what type it actually is. Unknown is spicier as it'll prevent developers from assuming it's a string or object or something.
- jax_the_dog 4y agoThat makes some sense to me. I’m not a TypeScript dev so I apologize for the stupid question. Is there any functional difference between the two? I.e. is there a case where using Unknown instead of Any will result in some sort of “compile” time error opposed to a runtime?
- thoughtspile 4y agoAlmost every case where you use the value results in an error with unknown, but not with any: let danger: any; // These all compile: danger(), 9 / danger, danger.access, danger.map(x => x \* 2) let safe: unknown; // These all explode in TS: safe(), 9 / safe, safe.access, safe.map(x => x \* 2)
- madeofpalk 4y agoYes - trying to access a property or method on something typed as unknown will (almost?) always result in a compile time error because it's unknown whether the value has that property or not. https://www.typescriptlang.org/play?#code/GYVwdgxgLglg9mABAdwE4EMAOBhBBnOAGwFMAZOAcwEEwBPACigAsYwKAVOcigLkXToBKRAG8AUIkQR8RYgDpClegCIAsrUQB1YgCNEVTJmUAaRM1YculOVDgBVQ8VTZ0eYvUGCxAXzFjQkLAIKBg4MiTcdmAA1mBwyGCMLGyc3HzgsfFgwuKS0mAEJApKahraegZGpuYpVhQ29o7Oru6ePn4B0PBIaFi4BbKRMXEJAELEUFBOSRaplOnDWTkSiDDAiIy0mMRw6zWW3IgAvCeIynhQqBbKy5J54fKKFCrqWrr6hiZmyQfWtg7bZpuDxeSTeRDEQhuUQre4DIpPF5ld6VL77OYUUGIXzeIA https://www.typescriptlang.org/play?#code/GYVwdgxgLglg9mABAd...
- thoughtspile 4y agoalways, because "unknown" includes null / undefined, which don't allow property access at all.
- WorldMaker 4y agoYes. `any` really does turn off all type checking. You see that offhand mentioned in this article talking about some of the paradoxes of `any`. `unknown` is still type checked and is arguably "merciless" type-checked that to do much of anything with an `unknown` you have to check for a more specific type first or the compiler returns an error that what you are doing isn't known to be valid for `unknown`. Some of that happens "automatically" at this point in the large number of ways that types can now be narrowed implicitly in Typescript (type guards [library functions], type asserts, the `typeof` runtime operator, the `in` runtime operator [as of recently], etc), so it can feel like `unknown`/`any` are the same up to a point, that point being where the runtime type is trivially known based on if statements and library functions around your use of the type. (Fun fact: `any` predates most type narrowing and `unknown` by several major Typescript versions. So `any` beyond just being the final "escape hatch" from type checking is also something of a legacy tool.)
- thoughtspile 4y agoSaying a value is "unknown" means making no assumptions about the value. It might be a null, a number, a function, you don't care because you aren't going to do anything with this value. If you call() it, or read.some.property, TS complains because you're making assumptions about the object that TS did not ensure.
- edgyquant 4y agoBut you have to care about the type with unknown? For instance calling this on an unknown obj.value Will return a type error that value doesn’t exist on unknown. While calling it on an ant is valid typing
- thoughtspile 4y agoHere, you expect obj to have a property called "value", so I'd say you do care about the type of obj. A valid type would be obj: { value: blah }
- _greim_ 4y ago> But you have to care about the type with unknown? It's better to say `unknown` is a promise that you won't care about the type. When you write `obj.value`, you're caring about the type. TypeScript sees that and says "hey, you promised you wouldn't care about this type." > While calling it on an ant is valid typing It's still invalid, same as if you'd used `unknown`. It just suppresses the type error. The presence of `any` in a codebase is a very real risk. The only reason it exists is to allow incremental porting from JavaScript to TypeScript.
- sirmarksalot 4y agoThis is technically correct, but I suspect it's pretty rare that you would choose "unknown" over a generic parameter. Even if you're writing an algorithm that doesn't care about the data type, it's still probably going to be used by application code that does care, and you'll want to support that need by passing the type through, otherwise the application will be forced to downcast.
- thoughtspile 4y agoI often use it to infer one generic parameter: type Output<Fn> = Fn extends ((a: unknown) => infer Out) ? Out : never;
- piyh 4y agoI went through my code base and found one use of `any` that was worth keeping around, the rest could be changed to `unknown` and better code resulted from it.
- theonething 4y ago> I know what I'm doing `any` can also be an indicator of the exact opposite.
- mrbombastic 4y agoIt certainly is for me :)
- joshfee 4y ago`any` should really be called `every` to match the semantics, it says "this value is an instance of every type, and therefore you can do anything with it". And you might read that and thing "but that's crazy, its not possible for a value to be an instance of everything!" and you'd be right - the `any` type in TS is in fact crazy and you should not use it.
- consilient 4y agoThe intersection of all typescript types is `never`. `any` is approximately equivalent to `unknown` in contravariant positions and `never` in covariant ones.
- dclowd9901 4y agoThat’s a convenient way of thinking about it. A more logically correct way of thinking about it is: “any” can be any possible type “unknown” is a specific stand-in type. It does not represent all types but is a subset of all types, which allows you to narrow its definition from nothing. Unknown in practice is closer to a generic in terms of usage and semantics than “any”. It’s like a generic generic except it’s not useful until you direct it. It basically lets you kick the can down the road in your code of having to make a type decision, which is very useful for writing composable and uncoupled code.