This piece of code might look completely confusing to you.


type Name = string

type GoodName = VeryGoodName | "fred"

type VeryGoodName = "matt"

const isGoodName = (name: GoodName) => {}

isGoodName("matt")

export type Result = Name extends GoodName ? true : false


Name extends GoodName, if it does, return true, if it doesn't, return false. What, okay, and you'd expect name,

Now you'd think this would return true right? Name is a string, VeryGoodName is the string "matt" and GoodName is a union between VeryGoodName and "fred". All strings.

So it'd make sense for Name extends GoodName to be true, but it's not. It's actually false. That's interesting!

To understand this, we need to understand assignability.


class Animal {

isAnimal() {

return true

}

}

class Dog extends Anigal {

isDog() {

return true

}

}

class Labrador extends Dog {

isLabrador() {

return true

}

}


Here we have kind of like the traditional object oriented classes thing. And we can take our 'thing' for a walk. We can say that we can take any dog for a walk, but Animal is not assignable to dog.


const takeForWalk = (dog: Dog) => {}

takeForWalk(new Animal()) // error


We can take our Labrador for a walk. That's absolutely fine. We can take our Dog for a walk, but we can't take our Animal for a walk. The reason for that even though a Dog is an Animal, an Animal is a wider version of that.

Whereas a Labrador is a narrower version of a Dog. So you can take your Labrador for a walk because it's a narrow version of a Dog. It's still a Dog, right?.

And so we can look back on our Result type and see that what we are really checking here with the extends is if Name is a narrower version of GoodName. And it's not.


type Name = string

type GoodName = VeryGoodName | "fred"

type VeryGoodName = "matt"

const isGoodName = (name: GoodName) => {}

isGoodName("matt")

export type Result = Name extends GoodName ? true : false // false


And so we can acually swap them and it will be true since GoodName is the narrower version of Name.


export type Result = GoodName extends Name ? true : false // true


VeryGoodName is also a narrower version of name, and it's also a narrower version of GoodName, because it's part of that union too.


export type Result1 = VeryGoodName extends Name ? true : false // true

export type Result2 = VeryGoodName extends GoodName ? true : false // true


That should give you a good idea about what assignability means, and about what this extends keyword is doing in this conditional check.