DEV Community

Cover image for What you need to know about Typescript types
Lucas jin for One Beyond

Posted on • Updated on

What you need to know about Typescript types

When we are talking about types in typescript, what is the first thing that comes to your mind? You may think:

  • number (1,2,3)
  • string ('hello',''world')
  • boolean (true, false)
  • object ({name:'Jon',age:'30'})
  • function ((x,y)=> x + y)
  • undefined
  • null

Yes, these are some possible types in Typescript system. Before you run the code, typescript uses them to check for errors.

A variable can just have one type... wow! stop there! you may start to argue with me now: "typescript has union type and also intersection type which a variable can be assigned to several types! You are wrong Lucas!" Yes, you are right about union and intersection type, but this is just one way to think of the types, and I prefer to think of the types in typescript as a set of possible values. For instance, a number type is a set of all number values. 2, 45, 1000 belongs to it, but 'book', 'student' not. And depends on the strictNullChecks setting, null and undefined may or may not be part of the set. (If the strictNullChecks is turned off, null and undefined are permissible values in every type.)

Type Alias

The smallest type set is an empty set, which is an empty domain, no value can be found in it. It's also known as Never type in typescript, no values are assignable to a never type:

const A:never = 'a' // Error. Type 'string' is not assignable to type 'never'.
Enter fullscreen mode Exit fullscreen mode

The next smallest type set contains a single value. There is only one single value that can be found in this domain, which
corresponds to typescript literal type, also known as unit type :

type A = 'a'
type B = 'b'
type One = 1

const category:A = 'a' // Correct
const category:A = 'b' // Error, Type '"b"' is not assignable to type '"a"'.
Enter fullscreen mode Exit fullscreen mode

And to form two or three values, you can use union unit types, which corresponds to typescript union type:

type AB = 'a' | 'b'
const A: AB = 'a' // Correct
const B: AB = 'b' // Correct
const C: AB = 'c' // Type '"c"' is not assignable to type 'AB'.
Enter fullscreen mode Exit fullscreen mode

The values in these sets of values or domains are finite, it's quite easy to reason with. But most of time the domain we are dealing with is infinite, such as string, number or an interface, yet we still can think of them as a set of values:

type num = 1 | 2 | 3 | 4 | ... 
type str = 'apple' | 'banana' | 'book' | ...
Enter fullscreen mode Exit fullscreen mode

The number type is the set of values of all the numbers in the universe, and the string type is the set of values of all the strings in the universe.

What does assignable mean?

How can this mindset help us understand better the Typescript's type system? I don't know if you ever encountered a situation when Typescript jumps out an error and it says: Type A is not assignable to type B , and I am like: What? the type A definitely can assign to type B. This misunderstanding is because I didn't fully understand what typescript was trying to tell me. Here is a simple example:

type Fruit = 'apple' | 'banana'
const log = (str:Fruit) =>  {
    console.log(str)
}

let myFruit = 'apple'

log(myFruit) // Error. Argument of type 'string' is not assignable to parameter of type 'Fruit'.
Enter fullscreen mode Exit fullscreen mode

First of all, you may ask why a string is not assignable to type 'Fruit' which is also a string, 'apple' or 'banana'. The word 'assignable' appears in many Typescript errors, in the context of set of values, it means either 'member of' or 'subset of'. So now we can translate the error message to Argument of type 'string' is not a member of (subset of) parameter of type 'Fruit'. If you are still asking is string a subset of type 'Fruit' or is type 'Fruit' a subset of string? You should think of types as a set of values. In the domain of string type contains infinite string values, on the other hand the type 'Fruit' only contains two values, 'apple' and 'banana'. So clearly type 'Fruit' is a subset of string, or string is the superset of type 'Fruit'. Now the error message makes sense to us, of course the string is not assignable to type 'Fruit'.

To fix the error is simple, we just change the keyword let to const , so Typescript will know the value 'apple' won't change in the future.

Interface

Now let's take a look at the Typescript interface. Let's say we have two interfaces

interface AB {
  a:string
  b: string
}

interface ABC {
  a:string
  b: string
  c: string
}
Enter fullscreen mode Exit fullscreen mode

Now my question is which interface is a subset of (a member of ) or assignable to another? You may immediately think: "interface AB is a subset of interface ABC, because inside interface ABC contains more values." But it's quite the opposite in this case, the correct answer is interface ABC is a subset of interface AB. That's because Javascript is inherently duck typed. And Typescript models this behavior. It means values with additional properties still belong to a type:

interface Person {
  name:string  
}

const person = {
  name:'aa',
  age:21,
  eyeColor:'blue'
}

const personA:Person = person // Correct
Enter fullscreen mode Exit fullscreen mode

You also can verify it by creating an interface Union type:

interface Person {
  name:string  
}

interface ExtraInfo {
  job: string
  habit:string
  favouriteBook:string
}

type PersonInfo = Person | ExtraInfo

const personaB:PersonInfo = {
  name:'joe',
  job: 'developer',
  habit:'read',
  favouriteBook:'book'
} // Correct
Enter fullscreen mode Exit fullscreen mode

As we know, & operator in Typescript computes the intersection of two types. Interface Person and ExtraInfo don't have common properties, but cause the duck typed behavior, values with additional properties still belong to a type So the interface Union type will include all the properties in each interface. And you may surprisingly find an empty interface {} is the super set of all other interfaces, because it means it includes all the possible values.
Back to our first question, I hope you have a clear idea now why the interface ABC is the subset of interface AB.

Top comments (0)