This post will be a quick overview of three interesting types in Typescript: any, unknown, and never with the aim of quickly explaining what they are, and when to use them. It is part of the Introduction to Advance Types in TypeScript series.

To start with, it is a good mental model to view Types from the perspective of set theory. This idea is fully explored in Union and Intersection Types in TypeScript, but for a quick summary, the idea is simple. When types are created, see it as similar to defining a Set. And what do sets contain? they contain objects. The next thing is to see values as objects that belongs to a set. A value defined to be part of a set, would not be allowed in a different set which it does not belong in or overlap with.

For example, the type string is the set of all possible strings, which is an infinite amount, while the type boolean is the set of all possible boolean values, which in this case is finite and is just true and false. That is the simple idea.

Now let's explore any, unknown and never types in TypeScript

### any

```
let value: any;
let boolValue: boolean = true
let numValue: number = 43
let strValue: string = "Hello world"
value = boolValue
value = numValue
value = strValue
```

```
let value: any;
let boolValue: boolean = true
value = boolValue
value.charCodeAt(0)
```

### unknown

```
let value: unknown;
let boolValue: boolean = true
let numValue: number = 43
let strValue: string = "Hello world"
value = boolValue
value = numValue
value = strValue
```

The main difference between unknown and any is that, with unknown, the compiler now no longer allows any method calls. Any attempt to do so will lead to a compilation error. For example this:```
let value: unknown;
let boolValue: boolean = true
value = boolValue
// compile error
value.charCodeAt(0)
```

```
let value: unknown;
let boolValue: boolean = true
value = boolValue
if (typeof value === "string") {
value.charCodeAt(0)
}
```

### never

*Top type*, never is the Bottom type. What does this mean? Well if the Top type is a type that can contain values of all the types, the Bottom type is a type (read sets) that does not contain any value of any type. Essentially Bottom type is an empty set.

```
function neverReturns(): never {
while(true) {
console.log(Date.now())
}
}
```

How to type this function? it won't return any value. Hence why the type never can be ascribed to it. ```
let value: number | boolean = 1
function process(value: number | boolean) {
if (typeof value === "number") {
// TODO operate on value as number
} else {
// TODO operate on value as boolean
}
}
```

The problem with this, is that in the future if the union type for value is extended to include another type, this new type won't be accounted for in the process function. Hence if a value of boolean is passed to the function, it will only blow up at runtime, and there is no way the compiler can warn us of this. To fix this, we can use never type. The trick is to include a branch that takes the passed-in value and assigns it to another value of type never. This should never happen, if it does, it means there is a value that is not being handled in the branches. An attempt to now assign such a value to type never will lead to compile error. This is how we can use the never to get some more type-safety. This process is called exhaustive type checking, as it is a mechanism that allows us the guarantee at compile time that all possible types in a union type are accounted for.
## 2 comments:

> unknown is used to model situation where an operation can never return a value.

I believe this should be 'never' instead of 'unknown'

Indeed. Thanks for spotting this. I have updated the post

Post a Comment