Dan D Kim

Let's share stories

Intermediate Typescript Questions - Typed Functions

2021-12-14 Dan D. Kimtypescript

In this post, we will code out a type-safe function.


Hello, this is the second (intermediate level) of my Typescript interview series. I also wrote a post of beginner level questions here. There is also a post of advanced level questions here.


Question Context

Given the following object:

const house = {
  isForSale: true,
  neighborhood: 'Red Maple',
  squareFootage: 123
}

We want to change the following function getValue():

function getValue(s) {
  return house[s]
}

Such that the following requirements are satisfied:

const onSale = getValue('isForSale')          // onSale should be of type boolean
const neighborhood = getValue('neighborhood') // neighborhood should be of type string
const sqft = getValue('area')                 // should throw type error
const bedRoomsOnFloor = getValue(1)           // should throw type error

⚠️ For all of the following questions, let’s assume we are working on the getValue() function. If a question asks you how to modify the input or output type, it’s asking in regards to the getValue() function above.

Q1 How can specify the input type to be a string?

Warm up question!

Meet the following requirements:

const onSale = getValue('isForSale') // valid
const bedRoomsOnFloor = getValue(1) // should throw error
Answer

Simply set the input s type to string.

function getValue(s: string) {  return house[s]
}

Too easy

Q2 How can we specify the input type to be a string that is one of the existing keys in House?

Such that the following is met:

const onSale = getValue('isForSale') // valid
const neighborhood = getValue('neighborhood') // valid
const sqft = getValue('squareFootage') // valid
const sqft2 = getValue('area') // should throw type error
Answer

Use the typeof and keyof operators.

type House = typeof house
function getValue(s: keyof House) {  return house[s]
}

typeof takes a variable and returns the type definition

keyof takes a type and returns the keys of the type

Q3 How can we explicitly specify the output type to one of the values inside House?

Such that the output type of getValue() is restricted to boolean, string, and number.

Answer Use the `keyof` operator.
function getValue(s: keyof House): House[keyof House] {  return house[s]
}

This can be automatically taken care of by Type Inference, making it redundant in practice.

Q4 How can we specify the output type to be the type of the value for a given key?

So far here is our code:

const house = {
  isForSale: true,
  neighborhood: 'Red Maple',
  squareFootage: 123
}

type House = typeof house

function getValue(s: keyof House): House[keyof House] {
  return house[s]
}

If we want to retrieve the value for isForSale, then the typing is one of string, number, or boolean.

const onSale = getValue('isForSale') // string | number | boolean

But we know that the typing of house['isForSale'] is always going to be a boolean.

const house = {
  isForSale: true, // always a boolean  neighborhood: 'Red Maple',
  squareFootage: 123
}

How can we make sure the typings are paired to their proper key-value pairs, such that the following is met?

const onSale = getValue('isForSale') // boolean
const neighborhood = getValue('neighborhood') // string
Answer

Use generics.

function getValue<K extends keyof House>(s: K): House[K] {  return house[s]
}

const onSale = getValue('isForSale') // boolean
const neighborhood = getValue('neighborhood') // string

If you are unfamiliar with generics, checkout my ezpz guide about generics


Great! Now we have a getValue() function that is type safe.

Looking for more? Checkout my this post for more intermediate questions.

Until next time.