Do you really know TypeScript? (1): Thinking in sets

I know many people, including myself, whose first experience with TypeScript was to write annotations in some variables and to add as any until the transpiler stopped complaining.
But at some point you realize that you really should dig a little deeper into TypeScript and finally understand those errors.
It's true that you can technically build the same websites/systems with and without TypeScript, but its benefits are huge:
  • Catch errors at compile time instead of at runtime
  • Autocomplete ("it was user.phone or user.phoneNumber?" 🤔)
  • Language services (enabling some IDE's refactors for example)
  • Better domain modelling
  • Using TypeScript is not only investing in the code's maintainability, it is also investing in the developer's productivity.
    Okay, you are (or were already) convinced that TypeScript is worth learning, what is this series for?
    In this series I will go through many aspects of the language that were not obvious to me even after having already done some projects with it.
    You will stop wrestling with TypeScript 🤼‍♀️
    Seeing types as sets of values
    // what can we assign to it?
    
    const foo: Bar = ???
    We can assign any value that belongs to a subtype of Bar.
    One cool thing of this system is that you can use set operators (among others) to create new types.
    For example the union operator: number | string is the set of all numbers and strings.
    Structural typing
    To know if a value belongs or not to a type, TypeScript only focuses on the shape that it has.
    class Person {
        name: string
    }
    
    // We didn't use the "new" keyword
    const person: Person = {
       name: 'Jame'
    }
    That wouldn't be possible in nominal type systems.
    Let's see a little harder example:
    type File = {
        name: string
        extension: string
    }
    
    type Folder = {
        name: string
        color: string
    }
    
    type DesktopItem = File | Folder
    DesktopItem contains all the objects that either have the properties (name and type) of File or Folder.
    const item: DesktopItem = couldBeFileOrFolder
    
    // should work, right?
    givenItem.extension
    It doesn't work because only File has that property and the specific type of item could be Folder.
    When we declare the union of two types the result is a type that has the intersection of the properties. In this case objects with a property name of type string, because it is the only property that they have in common.
    It's also true the other way around: The intersection of two types results in a type that has the union of the properties.
    keyof (A&B) = (keyof A) | (keyof B)
    keyof (A|B) = (keyof A) & (keyof B)
    The empty set and the universal set
    If we can think of types as sets of values, what types are the empty set and the universal set?
    never is the empty set and unknown is the universal set.
    These are both very special and we'll talk about them soon.
    Things to remember
  • Types are sets of values
  • One value of type Y is assignable to a type X if Y is a subtype of X.
  • Type compatibility in TypeScript is determined by structural typing.
  • Resources to go deeper

    31

    This website collects cookies to deliver better user experience

    Do you really know TypeScript? (1): Thinking in sets