Dan D Kim

Let's share stories

Beginner Typescript Questions - Basics of Types

2021-11-29 Dan D. Kimtypescript

In this post, we will go through some basic Typescript type questions.


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


Tutorial on Primitive Types

Read in case you need a little refresher / intro.

Skip if you are familiar with types.

Let’s start with something simple. ✌️

Say we want to declare a type for Cars 🚗

Let’s start with the any type

type Car = any

Let’s create some examples.

// Valid
const thisCar: Car = 'hyundai'
const thatCar: Car = 'ford'

// Valid but weird
const myCar: Car = 123

💥 Immediately we see a problem with any allowing unexpected values to represent our type Car.

Let’s narrow it down to string.

type Car = string
// Valid
const thisCar: Car = 'hyundai'
const thatCar: Car = 'ford'

// Invalidconst myCar: Car = 123

Previous case is covered, but hold on…

// Valid but weird
const hisCar: Car = 'foo'

We still have a problem with unexpected values being valid for our type Car. 😡

How about we narrow down our type even further?

type Car = 'hyunda' | 'ford'

In Typescript, primitive values can be used as types.

// Now invalid 👍
const hisCar: Car = 'foo'

Now we have achieved our goal. Our type Car is set to accept a limited discrete set of values.

type Car = 'hyunda' | 'ford' | 'honda' | 'toyota' | 'bmw' ... // assume a long list

Question Context

For the following questions, we are given the following type definition:

type Car = {
  brand: string,
  model: string,
  type: string,
  year: number
}

Q1: How can we declare a variable brand that is of type Car.brand?

Answer
let brand: Car['brand']

Q2: Building up the previous answer above, is the following code valid?

const Brand = 'brand'
let brand: Car[Brand]
Answer

No. A compilation error will be thrown. A type must be passed as a valid index to the [] brackets.

type Brand = 'brand'let brand: Car[Brand]

Q3: Given the Car type, let’s say we wanted to create a variable that was the union of brand and model.

let manufactureInfo: Car['brand'] | Car['model']

How can we simplify the code above such that we only need to type Car once on the same line?

Answer
let manufactureInfo: Car['brand' | 'model']

Q4: How can we declare a type named carProps that contains all the keys of the Car’s properties as types?

Answer

Use the keyof operator.

type carProps = keyof Car

// type carProps = "brand" | "model" | "type" | "year"

Q5: How can we declare a type named carPropTypes that contains all the type-values of the Car’s properties?

Answer
type carPropTypes = Car[keyof Car]

// type carPropTypes = string | number

Q6: Building on the answer above, define a generic type named TPropTypes that takes in a generic type T and forms the type-values of the keys in a generic type T

Imagine if we had many different types.

type carPropTypes = Car[keyof Car]
type companyPropTypes = Company[keyof Company]
type countryPropTypes = Country[keyof Country]
...

Define a generic type that could be re-used to cut down our repetitive code.

Answer
type TPropTypes<T> = T[keyof T]

// ** Usage **
// type carPropTypes = TPropTypes<Car>
// type companyPropTypes = TPropTypes<Company>

type ValueOf<T> is a much more popular naming convention.

If you are unfamiliar with generics, I would refer you to my Typescript Generics post


That’s all. Hope you learned something.

Ready for the next level? Checkout my post about intermediate questions here.

Happy programming!