Deriving Types From Types
How Types Are Deriving from Types in TypeScript?
One of the most powerful aspects of TypeScript is the system of creating types from other types (aka expressing types in terms of other types). The system includes:
-
generics,
-
produced literal key union types,
-
mapped types,
-
conditional types,
-
template literal types, and
-
index accessed types.
Generics
A generic is a type or an interface that is parametrized with one or more type parameters (aka type variables).
In TypeScript, it is possible to create a generic type alias or a generic interface but not a generic enum, nor generic namespace.
Generic Type Aliases
A generic type alias is a type alias that is parametrized with one or more type parameters.
Generic Interfaces
A generic interface is an interface that is parametrized with one or more type parameters.
Generic Function Signatures
Generic function signatures are function signatures parametrized with one or more type parameters.
The below function allows a value to be pushed to an array only when the array already includes a value of the type as the value attempted to be pushed.
In the above example, the type of arr
was inferred from the function call. But when an empty array would be pushed it would allow values of any type to be pushed. For cases such as this and for cases in which the compiler fails to infer types as intended it is possible to explicitly pass type to a generic function.
The pushToArray
function type can also be declared using arrow function type signatures, type aliases, and interfaces.
Generic Classes
In addition to creating generic type aliases, generic interfaces, and generic function signatures, TypeScript allows for creating generic classes.
In the above example, a respective type is being passed to the Horse
class at instance initialization syntactic indication (pre-runtime). It can also be done at class extension.
One of the crucial things to remember about generic classes is that generic type parameters can only parametrize instance members and not static members.
Generic Constraints
It is possible to constraint the structural shape of types acceptable by function variable type parameters using the extends
keyword.
Produced Literal Key Union Types
It is possible to create a new type being the literal union of keys of another type using the keyof
operator.
Using the keyof
operator on a type that has a string index signature produces the string | number
union type.
Using the keyof
operator on a type that has a number for an index signature produces the number
type.
Mapped Types
What is a mapped type?
A mapped type is a structural type created through mapping over a union of keys of another structural type. Such a union is often created using the keyof
operator. Mapped types are created using the index signature syntax.
Changing Property Types
A mapped type can be used to change a structural type property types.
Changing Property Keys
A mapped type can be used to change (remap) keys of a structural type using the as
operator combined with template literal types or other strategies.
It is possible to change both property keys and property types simultaneously.
It is also possible to change the mutability and optionality modifiers through using the readonly
and ?
operators appended with -
or the default +
.
Removing Selected Properties
A mapped type can be used to remove (filter out) selected properties through producing never
type for a given property during mapping.
Conditional Types
A conditional type is a type which depends on an assignability condition between two types. A conditional type condition mimics the JavaScript ternary operator and uses the extends
keyword: type Foo = Bar extends Baz ? Qux : Quux
.
In the above example, as CaptainHook
is assignable to Captain
the type Hookable
is CaptainHook
.
Conditional types can be used with generics.
Template Literal Types
Template literal types are types utilizing string literal types and interpolation to create new string literal types.
The power of template literal types is their ability to create union types through a combination of interpolation and string literal types.
Further, when more than one string literal type is interpolated in one template literal string they create a cartesian product of all possible combinations.
As presented in earlier chapters template literal types can be used with generics.
Indexed Access Types
An indexed access type is a type created from a property of another type of structural nature.
The index access type syntax uses the square bracket notation to access the relevant property of another type.