These are my notes from the Type Transformations course by Matt Pocock on Total TypeScript.
Basic Inference and Utility types
ReturnType
allows us to obtain the return type of a functionParameters
allows us to obtain the input parameters of a functionAwaited
allows us to extract the return type of a promise- Remember to always prefix a
value
withtypeof
if we want to extract the type - We can access the keys of an object type with the
keyof
keyword. Example:
Exclude
lets us remove a key from a type.Extract
lets us get a key from a type.
Unions and Indexing
- Discriminated union and unions
- The difference between the two is that with the discriminated union, we have a “common” denominator (a key, for example) with which we can discriminate what exact type we have. For example:
- We can extract specific members of a union with the type helper
Extract
or remove some withExclude
- We can extract the type of a specific key with indexed access. This also works for discriminated unions where we access all possible keys.
- If we want to infer the object values as literal type, for example on a enum object, we can use
as const
to convert it into its literal value. Another alternative isObject.freeze
, that works on the runtime and type level, but does not work on more than the root level. - We can pass a union as a indexed access of a type. For example:
Template Literals
- We can use template strings to match with wildcard-like strings.
- We can use template strings into utility types like
Extract
- We can also use them to express all the possible permutations of union types like so:
- String type helpers
Lowercase<>
Uppercase<>
Capitalize<>
Custom Type Helpers
- We can pass to a type “generic” types to configure their outputs.
- We can add default values to generics as so
- The empty object value has a specific use in TypeScript, and will represent anything that is not
null
orundefined
.- This can be applied for example on the Maybe type where we want to exclude
null
andundefined
→type Maybe<T extends {}> = T | null | undefined;
- This can be applied for example on the Maybe type where we want to exclude
- Nice Helper: `type NonEmptyArray
= [T, …Array ]; - Conditional types take a form that looks a little like conditional expressions (
condition ? trueExpression : falseExpression
) in JavaScript:SomeType extends OtherType ? TrueType : FalseType;
The
infer
inT extends { data: infer TData }
says “Whatever is passed in to thedata
key, infer its type”. Then, theinfer
declaresTData
for the true branch. If we try and access TData in the ‘false’ branch, we won’t be able to. In other words, theTData
variable is only defined for one branch.
- We can also infer the generics of a type like so:
- Another example of infering with template literals
- We can also infer on extending of union types like in this example where we can have multiple parser shapes
Mapped Types
- We can map a union to an object using the
in
when defining the key
- We can transform the mapped key to another type
- Selective Remapping with Conditional Types and Template Literals
- There is a useful pattern when transforming unions that is to express it as a intermediary form and then map over again. Example