Applied
TypeScript
Applied TypeScript
Course repository: https://github.com/MoonHighway/applied-typescript
Required: Node.js >= v18.0.0
Recommended: Visual Studio Code (with GitHub Copilot disabled)
Setup
If you only have a README in your cloned copy of the repository, run:
git pull
Install dependencies by running:
npm install
Agenda
-
Section 1: Composing Types: Part I
- Generic types, Conditional types
-
Section 1: Composing Types: Part II
-
keyof
type operator, Mapped types, Template literal types
-
-
Section 2: Improving Type Safety
- Discriminated unions, Type predicates, Assertion signatures, Branded types,
satisfies
operator
- Discriminated unions, Type predicates, Assertion signatures, Branded types,
Composing Types: Part I
Basic ways of composing types
-
Intersection types
-
Extending interfaces
-
Union types
-
Indexed access types
Basic ways of composing types
Intersection types
{ name: string; } & { age: number; }
Basic ways of composing types
Extending interfaces
interface User {
name: string;
}
interface SuperAdmin extends User {
enabled: boolean;
}
Basic ways of composing types
Union types
string | number | boolean
null | { value: number; }
Basic ways of composing types
Indexed access types
type User = {
name: string;
age: number;
}
type Age = User["age"];
// type Age = string;
Generic types
type Country<LanguagesType> = {
name: string;
languages: LanguagesType;
};
Type variable
Type parameter
Conditional types
type BoxIsShape = Box extends Shape ? boolean : unknown;
Conditional type constraint
True
branch
Box
is assignable
to Shape
False
branch
Composing Types: Part II
keyof
type operator
Produce a string or numeric literal union of the keys of an object type
interface User {
name: string;
age: number;
}
type UserKeys = keyof User;
// type UserKeys = "name" | "age";
Mapped types
Iterate through properties of an object type to create a new object type
type CountryData = {
name: string;
languages: string[];
population: number;
};
type Descriptions<Type> = {
[Key in keyof Type]: string;
};
Template literal types
Enforce specific string formats or expand string literal unions
type Greeting = `Welcome ${string}!`;
const greeting: Greeting = "Welcome home!";
Same syntax as template
literal strings in JavaScript
Improving Type Safety
Narrowing: Type guards
if (typeof population === "number") {
if (location instanceof City) {
Automatically recognised by TypeScript and used to narrow the type of a value
Narrowing: User-defined type guards
function valueIsString(value: any): value is string {
Type predicates - return true if value is of type
Assertion signatures - throw error if value is not of type
function assertIsString(
value: unknown
): asserts value is string {
Narrowing: Discriminated unions
type Product = {
name: string;
price: number;
};
type Service = {
name: string;
price: number;
};
type CatalogItem = Product | Service;
const catalog: CatalogItem[] = [...];
Narrowing: Discriminated unions
discriminate /dĭ-skrĭm′ə-nāt″/
intransitive verb
1. To make a clear distinction; distinguish.
"discriminate among the options available."
2. To perceive or notice the distinguishing features of; recognize as distinct.
"unable to discriminate colors."
Source: The American Heritage® Dictionary of the English Language, 5th Edition
Narrowing: Discriminated unions
type Product = {
type: "product";
name: string;
price: number;
};
type Service = {
type: "service";
name: string;
price: number;
};
type CatalogItem = Product | Service;
const catalog: CatalogItem[] = [...];
Discriminant property
Discriminant property
Branded types
declare const __brand: unique symbol;
type Brand<BaseType, BrandedName extends string> = BaseType & {
[__brand]: BrandedName;
};
// ----
type Cat = {
name: string;
color: string;
};
type BrandedCat = Brand<Cat, "Cat">;
Emulate nominal types by creating structurally unique types
A structurally unique type
TypeScript magic ✨
The satisfies
operator
const configA = {
logging: true,
metricsKey: "app_metrics"
};
const configB: Record<string, boolean | string> = {
logging: true,
metricsKey: "app_metrics"
};
const configC = {
logging: true,
metricsKey: "app_metrics"
} satisfies Record<string, boolean | string>;
Ensure that an expression matches a type, but retain the specific inferred type
Applied TypeScript
By Moon Highway
Applied TypeScript
- 82