TypeScript's Unknown data type
Tags: typescript, javascript, webdev
Published: 2021-04-28 17:10:50

There are data types in TypeScript that are better known than others. Today I would like to introduce a less known data type: `unknown`.

## The `unknown` data type

The `unknown` type exists since TypeScript 3.0 (the current version is 4.2) and is a [top type](https://en.wikipedia.org/wiki/Top_type).

Similar to the `any` type, a **variable** of type `unknown` accepts values of any type. 

The difference is that a **value** of type `any` can be assigned to variables of all types and a **value** of type `unknown` can only be assigned to variables of the type `any` or `unknown`.

```ts
/**
 * New variable of type unknown
 **/
let test: unknown;

/**
 * Assigning a value to an unknown variable
 **/
test = 'hello world';       // Works!
test = 5;                   // Works!
test = false;               // Works!
test = () => false          // Works!
test = new Audio();         // Works!

/**
 * Using an unknown variable
 **/
let myString: string = test;    // Error: Type 'unknown' is not assignable to type 'string'
let myBool: boolean = test;     // Error: Type 'unknown' is not assignable to type 'booelan'
const test2: unknown = test;    // Works!
const test3: any = test;        // Works!

test.foo(); // Error: Object is of type 'unknown'
new test(); // Error: Object is of type 'unknown'
```

## When to use `unknown`?

`unknown` forces type checking and is safer than `any`. That's why its use should always be favored over `any`.

Here is an example with `JSON.parse()`, which always returns a value of type `any`.

In the following situation the code will compile without noticing that there is a **huge error**. The JSON string is not of type `IPerson` and should not be assignable to the variable `phoebe`.

```ts
interface IPerson {name: string, age: number}

const jsonString = '{"alias": "rose", "color": "red"}';

const person = JSON.parse(jsonString); // This returns any
const phoebe: IPerson = person; // This should throw a type error, but doesn't...
```

To make our code safer and catch the type error, we can use `unknown` in combination with a custom Type Guard.

```ts
interface IPerson {name: string, age: number}

const jsonString = '{"name": "rose", "age": 25}';

const person: unknown = JSON.parse(jsonString); // This returns any.
const notPerson: IPerson = person; // Error Type 'unknown' is not assignable to type 'IPerson'.

/** 
 * Create a custom Type Guard to make sure that
 * the parsed data is of type Person.
 */
const isPerson = (data: any): data is IPerson => {
    return typeof data.name == 'string' && typeof data.age == 'number'
}

/**
 * Use Type Guard.
 */
if(isPerson(person)){
    console.log('This is a person!');
    // With the Type Guard the assignement of the 
    // variable as type Person works.
    const phoebe: IPerson = person;
} else {
    throw Error('Parsed string is not a Person.')
}
```

{% link basilebong/custom-type-guards-in-typescript-dg8 %}

---

Follow me on [dev.to](https://dev.to/basilebong) and [twitter](https://twitter.com/basilebong/)!

{% user basilebong %}

---

## Credits

- [The unknown Type in TypeScript by Marius Schulz](https://mariusschulz.com/blog/the-unknown-type-in-typescript)
- [When to use TypeScript unknown vs any by Ben Ilegbodu](https://www.benmvp.com/blog/when-use-typescript-unknown-versus-any/)