Dan D Kim

Let's share stories

Typescript - Any vs Unknown

2020-12-07 Dan D. Kimtypescript

The Problem

any is the most-capable type in Typescript. A lot of us may be guilty of using it just to “get stuff working first”.

const car: any = 'hyundai'

However, it weakens the type safety of your code and take away the benefits of type-checking in the language.

const car: any = 'hyundai'

/**
 * Since car is of type any, all of these potentially
 * erroneous calls will bypass compilation checks.
 */
car.honk()car.modelnew car()car()car `what a world`repair(car)
function repair(car: { status: string}) {
  car.status = 'goodie good'
}

The Solution

As part of the Typescript 3.0 release, a new unknown type was added to the blessed language.

Much like any, any value is assignable to unknown; however, unlike any, you cannot access any properties on values with the type unknown, nor can you call/construct them. Furthermore, values of type unknown can only be assigned to unknown or any.

Going back to the above example, using unknown instead of any will give us compilation errors.

const car: unknown = 'hyundai'
/**
 * All of these potentially erroneous calls will throw
 * compilation errors.
 */
car.honk()
car.model
new car()
car()
car `what a world`
repair(car)

function repair(car: { status: string}) {
  car.status = 'goodie good'
}

With type unknown, we are forced to uphold type safety, and will be updating our code to enforce type checks.

Implement Type Checks

To get a workaround for our simple example, let’s start with declaring a type Car.

type Car {
  status: string
  model: string
  repair(): void
}

We can then implement a type guard.

function isTypeCar (obj: any): obj is Car {
  return !!obj &&
    typeof obj === 'object' &&
    'model' in obj &&
    'status' in obj &&
    'honk' in obj &&
    typeof obj.honk === 'function'

With the type guard, we can now use car as we would like, and be rest-assured that type checks are enforced.

if (isTypeCar(car)) {
  car.honk()
  console.log(car.model)
  repair(car)
}

Trying to use an invalid property or function would throw a compilation error.

if (isTypeCar(car)) {
  car.honk()
  console.log(car.model)
  repair(car)
  car() // throws compilation error}

That’s all. Happy programming!