Type Guards and Differentiating Types

Union types are useful for modeling situations when values can overlap in the types can take on. What happens when we need to know specifically whether we have a Fish ? A common idiom in JavaScript to differentiate between two possible values is to check for the presence of a member. As we mentioned, you can only access members that are guaranteed to be in all the constituents of a union type.

User-Defined Type Guards

It just so happens that TypeScript has something called a type guard . A type guard is some expression that performs a runtime check that guarantees the type in some scope.

Using type predicates

Using the in operator

typeof type guards

instanceof type guards

The right side of the instanceof needs to be a constructor function, and TypeScript will narrow down to:
  1. the type of the function's prototype property if its type is not any .
  1. the union of types returned by that type's construct signatures.
in that order.

Nullable types

TypeScript has two special types, null and undefined, that have the values null and undefined respectively.
By default, the type checker considers null and undefined assignable to anything. Effectively, null and undefined are valid values of every type. That means it’s not possible to stop them from being assigned to any type, even when you would like to prevent it. The inventor of null, Tony Hoare, calls this his “billion dollar mistake”.
The --strictNullChecks flag fixes this: when you declare a variable, it doesn’t automatically include null or undefined. You can include them explicitly using a union type:

!: identifier!

Interfaces vs. Type Aliaes

As we mentioned, type aliases can act sort of like interfaces; however, there are some subtle differences.
Almost all features of an interface are available in type, the key distinction is that a type cannot be re-opened to add new properties vs an interface which is always extendable.
Because an interface more closely maps how JavaScript objects work by being open to extension, we recommend using an interface over a type alias when possible. On the other hand, if you can't express some shape with an interface and you need to use a union or tuple type, type aliases are usually the way to go.

Polymorphic this types

Mapped types

A common task is to take an existing type and make each of its properties optional:
To define another type which only makes properties optional except some specific properties.
Readonly, Partial and Pick are homomorphic whereas Record is not. One clue that Record is not homomorphic is that it doesn't take an input type to copy properties from:
Non-homomorphic types are essentially creating new properties, so they can't copy property modifiers from anywhere.

Conditional Types

A conditional type selects one of two possible types based on a condition expressed as a type relationship test:
The type above means when T is assignable to U the type is X, otherwise the type is Y.

Distributive conditional types

Conditional types in which the checked type is naked type parameter are called distributive conditional types . Distributive conditional types are automatically distributed over union types during instantiation. For example, an instantiation of T extends U ? X : Y with the type argument A | B | C for T is resolved a (A extends U ? X : Y) | (B extends U ? X : Y) | (C extends U ? X : Y).

Type inference in conditional types

With in the extends clause of a conditional type, it is not possible to have infer declarations that introduce a type variable to be inferred. Such inferred type variables may be referenced in the true branch of the conditional type. It is possible to have multiple infer locations for the same type variable.
When inferring from a type with multiple call signatures (such as the type of an overloaded function), inferences are made from last signature (which, presumably, is the most permissive catch-all case). It is not possible to perform overload resolution based on a list of argument types.
badge