{"id":16323791,"url":"https://github.com/david-else/modern-typescript-with-examples-cheat-sheet","last_synced_at":"2026-02-06T13:45:55.641Z","repository":{"id":40412532,"uuid":"243063034","full_name":"David-Else/modern-typescript-with-examples-cheat-sheet","owner":"David-Else","description":"Fully printable summary of modern TypeScript language features with extensive examples to help you learn","archived":false,"fork":false,"pushed_at":"2023-07-19T11:11:09.000Z","size":62,"stargazers_count":913,"open_issues_count":0,"forks_count":42,"subscribers_count":23,"default_branch":"master","last_synced_at":"2025-04-29T19:35:26.410Z","etag":null,"topics":["cheatsheet","typescript"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/David-Else.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2020-02-25T17:49:11.000Z","updated_at":"2025-04-26T09:01:47.000Z","dependencies_parsed_at":"2024-01-08T08:05:54.084Z","dependency_job_id":null,"html_url":"https://github.com/David-Else/modern-typescript-with-examples-cheat-sheet","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/David-Else/modern-typescript-with-examples-cheat-sheet","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/David-Else%2Fmodern-typescript-with-examples-cheat-sheet","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/David-Else%2Fmodern-typescript-with-examples-cheat-sheet/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/David-Else%2Fmodern-typescript-with-examples-cheat-sheet/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/David-Else%2Fmodern-typescript-with-examples-cheat-sheet/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/David-Else","download_url":"https://codeload.github.com/David-Else/modern-typescript-with-examples-cheat-sheet/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/David-Else%2Fmodern-typescript-with-examples-cheat-sheet/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266761522,"owners_count":23980300,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-23T02:00:09.312Z","response_time":66,"last_error":null,"robots_txt_status":null,"robots_txt_updated_at":null,"robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cheatsheet","typescript"],"created_at":"2024-10-10T22:55:41.127Z","updated_at":"2026-02-06T13:45:50.611Z","avatar_url":"https://github.com/David-Else.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003carticle class=\"markdown-body\"\u003e\n\n- [**Modern TypeScript with Examples Cheat Sheet**](#modern-typescript-with-examples-cheat-sheet)\n- [Typing Objects](#typing-objects)\n  - [`Object` Versus `object`](#object-versus-object)\n  - [Interface Signatures Overview](#interface-signatures-overview)\n    - [Index Signature](#index-signature)\n    - [Call Signature](#call-signature)\n    - [Construct Signature](#construct-signature)\n  - [Type Literal Syntax](#type-literal-syntax)\n  - [Excess Properties (⛔ Inconsistency)](#excess-properties--inconsistency)\n- [Mapped Types - Getting Types from Data](#mapped-types---getting-types-from-data)\n  - [`typeof` / `keyof` Examples](#typeof--keyof-examples)\n  - [`keyof` with Generics and Interfaces Example](#keyof-with-generics-and-interfaces-example)\n- [Immutability](#immutability)\n  - [`readonly` Properties](#readonly-properties)\n  - [`readonly` Class Properties](#readonly-class-properties)\n  - [`readonly` Array / Tuple](#readonly-array--tuple)\n  - [`const` Assertions](#const-assertions)\n- [Strict Mode](#strict-mode)\n  - [Non-Nullable Types `--strictNullChecks`](#non-nullable-types---strictnullchecks)\n  - [Strict Bind Call Apply `--strictBindCallApply`](#strict-bind-call-apply---strictbindcallapply)\n  - [Strict Class Property Initialization `--strictPropertyInitialization`](#strict-class-property-initialization---strictpropertyinitialization)\n- [Types](#types)\n  - [`never`](#never)\n  - [`unknown`](#unknown)\n    - [Reading `JSON` from `localStorage` using `unknown` Example](#reading-json-from-localstorage-using-unknown-example)\n- [Generics](#generics)\n  - [With and Without Type Argument Inference](#with-and-without-type-argument-inference)\n  - [Using More Than One Type Argument](#using-more-than-one-type-argument)\n  - [Higher Order Function with `Parameters\u003cT\u003e` and `ReturnType\u003cT\u003e`](#higher-order-function-with-parameterst-and-returntypet)\n  - [Advanced Factory using `ConstructorParameters\u003cT\u003e` and `InstanceType\u003cT\u003e`](#advanced-factory-using-constructorparameterst-and-instancetypet)\n- [Discriminated Unions](#discriminated-unions)\n  - [Exhaustive Pattern Matching Using `never`](#exhaustive-pattern-matching-using-never)\n- [Optional Chaining](#optional-chaining)\n  - [`?.` returns `undefined` when hitting a `null` or `undefined`](#-returns-undefined-when-hitting-a-null-or-undefined)\n- [Nullish Coalescing](#nullish-coalescing)\n  - [`??` “fall Backs” to a Default Value When Dealing with `null` or `undefined`](#-fall-backs-to-a-default-value-when-dealing-with-null-or-undefined)\n- [Assertion Functions](#assertion-functions)\n  - [A Standard JavaScript `Assert()` Doesn’t Work for Type Checking](#a-standard-javascript-assert-doesnt-work-for-type-checking)\n  - [Using `if` and `typeof` Everywhere is Bloat](#using-if-and-typeof-everywhere-is-bloat)\n  - [Assertion Function Style 1 - Check for a Condition](#assertion-function-style-1---check-for-a-condition)\n  - [Assertion Function Style 2 - Tell TypeScript That a Specific Variable or Property Has a Different Type](#assertion-function-style-2---tell-typescript-that-a-specific-variable-or-property-has-a-different-type)\n\n# **Modern TypeScript with Examples Cheat Sheet**\n\n# Typing Objects\n\n## `Object` Versus `object`\n\n`Object` is the type of all instances of class `Object`.\n\n- It describes functionality that is common to all JavaScript objects\n- It includes primitive values\n\n\u003c!-- end list --\u003e\n\n```ts\nconst obj1 = {};\nobj1 instanceof Object; // true\nobj1.toString === Object.prototype.toString; // true\n\nfunction fn(x: Object) {}\nfn(\"foo\"); // OK\n```\n\n`object` is the type of all non-primitive values.\n\n```ts\nfunction fn(x: object) {}\nfn(\"foo\"); // Error: \"foo\" is a primitive\n```\n\n## Interface Signatures Overview\n\n```ts\ninterface ExampleInterface {\n  myProperty: boolean; // Property signature\n  myMethod(x: string): void; // Method signature, 'x' for documentation only\n  [prop: string]: any; // Index signature\n  (x: number): string; // Call signature\n  new (x: string): ExampleInstance; // Construct signature\n\n  readonly modifierOne: string; // readonly modifier\n  modifierTwo?: string; // optional modifier\n}\n```\n\n\u003cdiv style=\"page-break-after: always;\"\u003e\n\n\u003c/div\u003e\n\n### Index Signature\n\nHelps to describe Arrays or objects that are used as dictionaries.\n\n- If there are both an index signature and property and/or method signatures in\n  an interface, then the type of the index property value must also be a\n  supertype of the type of the property value and/or method\n\n\u003c!-- end list --\u003e\n\n```ts\ninterface I1 {\n  [key: string]: boolean;\n\n  // 'number' is not assignable to string index type 'boolean'\n  myProp: number;\n\n  // '() =\u003e string' is not assignable to string index type 'boolean'\n  myMethod(): string;\n}\n\ninterface I2 {\n  [key: string]: number;\n  myProp: number; // OK\n}\n```\n\n### Call Signature\n\nEnables interfaces to describe functions, `this` is the optional calling context\nof the function in this example:\n\n```ts\ninterface ClickListener {\n  (this: Window, e: MouseEvent): void;\n}\n\nconst myListener: ClickListener = e =\u003e {\n  console.log(\"mouse clicked!\", e);\n};\n\naddEventListener(\"click\", myListener);\n```\n\n\u003cdiv style=\"page-break-after: always;\"\u003e\n\n\u003c/div\u003e\n\n### Construct Signature\n\nEnables describing classes and constructor functions. A class has two types:\n\n- The type of the static side\n- The type of the instance side\n\nThe constructor sits in the static side, when a class implements an interface,\nonly the instance side of the class is checked.\n\n```ts\ninterface ClockInterface {\n  tick(): void;\n}\ninterface ClockConstructor {\n  new (hour: number, minute: number): ClockInterface;\n}\n\n// Using Class Expression\nconst ClockA: ClockConstructor = class Clock implements ClockInterface {\n  constructor(h: number, m: number) {}\n  tick() {}\n};\n\nconst clockClassExpression = new ClockA(18, 11);\n\n// Using Class Declaration with a Constructor Function\nclass ClockB implements ClockInterface {\n  constructor(h: number, m: number) {}\n  tick() {}\n}\n\nfunction createClock(\n  ctor: ClockConstructor,\n  hour: number,\n  minute: number\n): ClockInterface {\n  return new ctor(hour, minute);\n}\n\nconst clockClassDeclaration = createClock(ClockB, 12, 17);\n```\n\n\u003cdiv style=\"page-break-after: always;\"\u003e\n\n\u003c/div\u003e\n\n## Type Literal Syntax\n\nTypically used in the signature of a higher-order function.\n\n```ts\ntype MyFunctionType = (name: string) =\u003e number;\n```\n\n## Excess Properties (⛔ Inconsistency)\n\n- Engineers **can’t** just think of interfaces as “objects that have exactly a\n  set of properties” or “objects that have at least a set of properties”.\n  In-line object arguments receive an additional level of validation that\n  doesn’t apply when they’re passed as variables.\n\n- TypeScript is a **structurally** typed language. To create a `Dog` you don’t\n  need to explicitly extend the `Dog` interface, any object with a `breed`\n  property that is of type `string` can be used as a `Dog`:\n\n\u003c!-- end list --\u003e\n\n```ts\ninterface Dog {\n  breed: string;\n}\n\nfunction printDog(dog: Dog) {\n  console.log(\"Dog: \" + dog.breed);\n}\n\nconst ginger = {\n  breed: \"Airedale\",\n  age: 3\n};\n\nprintDog(ginger); // excess properties are OK!\n\nprintDog({\n  breed: \"Airedale\",\n  age: 3\n});\n// Excess properties are NOT OK!!\n// Argument of type '{ breed: string; age: number; }' is not assignable...\n```\n\n\u003cdiv style=\"page-break-after: always;\"\u003e\n\n\u003c/div\u003e\n\n# Mapped Types - Getting Types from Data\n\n## `typeof` / `keyof` Examples\n\n```ts\nconst data = {\n  value: 123,\n  text: \"text\",\n  subData: {\n    value: false\n  }\n};\ntype Data = typeof data;\n// type Data = {\n// value: number;\n// text: string;\n// subData: {\n//   value: boolean;\n// }\n```\n\n```ts\nconst data = [\"text 1\", \"text 2\"] as const;\ntype Data = typeof data[number]; // \"text 1\" | \"text 2\"\n```\n\n```ts\nconst locales = [\n  {\n    locale: \"se\",\n    language: \"Swedish\"\n  },\n  {\n    locale: \"en\",\n    language: \"English\"\n  }\n] as const;\ntype Locale = typeof locales[number][\"locale\"]; // \"se\" | \"en\"\n```\n\n```ts\nconst currencySymbols = {\n  GBP: \"£\",\n  USD: \"$\",\n  EUR: \"€\"\n};\ntype CurrencySymbol = keyof typeof currencySymbols; // \"GBP\" | \"USD\" | \"EUR\"\n```\n\n\u003cdiv style=\"page-break-after: always;\"\u003e\n\n\u003c/div\u003e\n\n## `keyof` with Generics and Interfaces Example\n\n```ts\ninterface HasPhoneNumber {\n  name: string;\n  phone: number;\n}\n\ninterface HasEmail {\n  name: string;\n  email: string;\n}\n\ninterface CommunicationMethods {\n  email: HasEmail;\n  phone: HasPhoneNumber;\n  fax: { fax: number };\n}\n\nfunction contact\u003cK extends keyof CommunicationMethods\u003e(\n  method: K,\n  contact: CommunicationMethods[K] // turning key into value - a mapped type\n) {\n  //...\n}\ncontact(\"email\", { name: \"foo\", email: \"mike@example.com\" });\ncontact(\"phone\", { name: \"foo\", phone: 3213332222 });\ncontact(\"fax\", { fax: 1231 });\n\n// // we can get all values by mapping through all keys\ntype AllCommKeys = keyof CommunicationMethods;\ntype AllCommValues = CommunicationMethods[keyof CommunicationMethods];\n```\n\n\u003cdiv style=\"page-break-after: always;\"\u003e\n\n\u003c/div\u003e\n\n# Immutability\n\n## `readonly` Properties\n\nProperties marked with `readonly` can only be assigned to during initialization\nor from within a constructor of the same class.\n\n```ts\ntype Point = {\n  readonly x: number;\n  readonly y: number;\n};\n\nconst origin: Point = { x: 0, y: 0 }; // OK\norigin.x = 100; // Error\n\nfunction moveX(p: Point, offset: number): Point {\n  p.x += offset; // Error\n  return p;\n}\n\nfunction moveX(p: Point, offset: number): Point {\n  // OK\n  return {\n    x: p.x + offset,\n    y: p.y\n  };\n}\n```\n\n## `readonly` Class Properties\n\nGettable area property is implicitly read-only because there’s no setter:\n\n```ts\nclass Circle {\n  readonly radius: number;\n\n  constructor(radius: number) {\n    this.radius = radius;\n  }\n\n  get area() {\n    return Math.PI * this.radius ** 2;\n  }\n}\n```\n\n\u003cdiv style=\"page-break-after: always;\"\u003e\n\n\u003c/div\u003e\n\n## `readonly` Array / Tuple\n\n```ts\nconst array: readonly string[];\nconst tuple: readonly [string, string];\n```\n\n## `const` Assertions\n\n- `number` becomes number literal\n\n\u003c!-- end list --\u003e\n\n```ts\n// Type '10'\nlet x = 10 as const;\n```\n\n- array literals become `readonly` tuples\n\n\u003c!-- end list --\u003e\n\n```ts\n// Type 'readonly [10, 20]'\nlet y = [10, 20] as const;\n```\n\n- object literals get `readonly` properties\n- no literal types in that expression should be widened (e.g. no going from\n  `\"hello\"` to `string`)\n\n\u003c!-- end list --\u003e\n\n```ts\n// Type '{ readonly text: \"hello\" }'\nlet z = { text: \"hello\" } as const;\n```\n\n- ⛔ `const` contexts **don’t** immediately convert an expression to be fully\n  immutable.\n\n\u003c!-- end list --\u003e\n\n```ts\nlet arr = [1, 2, 3, 4];\n\nlet foo = {\n  name: \"foo\",\n  contents: arr\n} as const;\n\nfoo.name = \"bar\"; // Error\nfoo.contents = []; // Error\n\nfoo.contents.push(5); // OK\n```\n\n\u003cdiv style=\"page-break-after: always;\"\u003e\n\n\u003c/div\u003e\n\n# Strict Mode\n\n```json\n  strict: true /* Enable all strict type-checking options. */\n```\n\nis equivalent to enabling all of the strict mode family options:\n\n```json\n  noImplicitAny: true /* Raise error on expressions and declarations with an implied 'any' type */,\n  strictNullChecks: true /* Enable strict null checks */,\n  strictFunctionTypes: true /* Enable strict checking of function types */,\n  strictBindCallApply: true /* Enable strict 'bind', 'call', and 'apply' methods on functions */,\n  strictPropertyInitialization: true /* Enable strict checking of property initialization in classes */,\n  noImplicitThis: true /* Raise error on 'this' expressions with an implied 'any' type */,\n  alwaysStrict: true /* Parse in strict mode and emit \"use strict\" for each source file */\n```\n\nYou can then turn off individual strict mode family checks as needed.\n\n## Non-Nullable Types `--strictNullChecks`\n\nIn strict null checking mode, `null` and `undefined` are no longer assignable to\nevery type.\n\n```ts\nlet name: string;\nname = \"Marius\"; // OK\nname = null; // Error\nname = undefined; // Error\n```\n\n```ts\nlet name: string | null;\nname = \"Marius\"; // OK\nname = null; // OK\nname = undefined; // Error\n```\n\nOptional parameter `?` automatically adds `| undefined`\n\n```ts\ntype User = {\n  firstName: string;\n  lastName?: string; // same as `string | undefined`\n};\n```\n\n- In JavaScript, every function parameter is optional, when left off their value\n  is `undefined`.\n- We can get this functionality in TypeScript by adding a `?` to the end of\n  parameters we want to be optional. This is different from adding `| undefined`\n  which requires the parameter to be explicitly passed as `undefined`\n\n\u003c!-- end list --\u003e\n\n\u003cdiv style=\"page-break-after: always;\"\u003e\n\n\u003c/div\u003e\n\n```ts\nfunction fn1(x: number | undefined): void {\n  x;\n}\n\nfunction fn2(x?: number): void {\n  x;\n}\n\nfn1(); // Error\nfn2(); // OK\nfn1(undefined); // OK\nfn2(undefined); // OK\n```\n\nType guard needed to check if Object is possibly `null`:\n\n```ts\nfunction getLength(s: string | null) {\n  // Error: Object is possibly 'null'.\n  return s.length;\n}\n```\n\n```ts\nfunction getLength(s: string | null) {\n  if (s === null) {\n    return 0;\n  }\n  return s.length;\n}\n\n// JS's truthiness semantics support type guards in conditional expressions\nfunction getLength(s: string | null) {\n  return s ? s.length : 0;\n}\n```\n\n```ts\nfunction doSomething(callback?: () =\u003e void) {\n  // Error: Object is possibly 'undefined'.\n  callback();\n}\n```\n\n```ts\nfunction doSomething(callback?: () =\u003e void) {\n  if (typeof callback === \"function\") {\n    callback();\n  }\n}\n```\n\n\u003cdiv style=\"page-break-after: always;\"\u003e\n\n\u003c/div\u003e\n\n## Strict Bind Call Apply `--strictBindCallApply`\n\n\u003e The `call()` method calls a function with a given `this` value and arguments\n\u003e provided individually, while `apply()` accepts a single array of arguments.\n\u003e The `bind()` method creates a new function.\n\nWhen set, TypeScript will check that the built-in methods of functions `call`,\n`bind`, and `apply` are invoked with correct argument for the underlying\nfunction:\n\n```ts\nfunction fn(x: string) {\n  return parseInt(x);\n}\n\nconst n1 = fn.call(undefined, \"10\"); // OK\nconst n2 = fn.call(undefined, false); // `false` is not assignable to parameter of type `string`\n```\n\n## Strict Class Property Initialization `--strictPropertyInitialization`\n\nVerify that each instance property declared in a class either:\n\n- Has an explicit initializer, or\n- Is definitely assigned to in the constructor\n\n\u003c!-- end list --\u003e\n\n```ts\n// Error\nclass User {\n  // 'username' has no initializer \u0026 not definitely assigned in constructor\n  username: string;\n}\n\n// OK\nclass User {\n  username = \"n/a\";\n}\n\nconst user = new User();\nconst username = user.username.toLowerCase();\n\n// OK\nclass User {\n  constructor(public username: string) {}\n}\n\nconst user = new User(\"mariusschulz\");\nconst username = user.username.toLowerCase();\n```\n\n\u003cdiv style=\"page-break-after: always;\"\u003e\n\n\u003c/div\u003e\n\n- Has a type that includes undefined\n\n\u003c!-- end list --\u003e\n\n```ts\nclass User {\n  username: string | undefined;\n}\n\nconst user = new User();\n\n// Whenever we want to use the username property as a string, we first have\n// to make sure that it actually holds a string, not the value undefined\nconst username =\n  typeof user.username === \"string\" ? user.username.toLowerCase() : \"n/a\";\n```\n\n# Types\n\n## `never`\n\n`never` represents the type of values that never occur. It is used in the\nfollowing two places:\n\n- As the return type of functions that never return\n- As the type of variables under type guards that are never true\n\n`never` can be used in control flow analysis:\n\n```ts\nfunction controlFlowAnalysisWithNever(value: string | number) {\n  if (typeof value === \"string\") {\n    value; // Type string\n  } else if (typeof value === \"number\") {\n    value; // Type number\n  } else {\n    value; // Type never\n  }\n}\n```\n\n\u003cdiv style=\"page-break-after: always;\"\u003e\n\n\u003c/div\u003e\n\n## `unknown`\n\n`unknown` is the type-safe counterpart of the `any` type: we have to do some\nform of checking before performing most operations on values of type `unknown`.\n\n### Reading `JSON` from `localStorage` using `unknown` Example\n\n```ts\ntype Result =\n  | { success: true; value: unknown }\n  | { success: false; error: Error };\n\nfunction tryDeserializeLocalStorageItem(key: string): Result {\n  const item = localStorage.getItem(key);\n\n  if (item === null) {\n    // The item does not exist, thus return an error result\n    return {\n      success: false,\n      error: new Error(`Item with key \"${key}\" does not exist`)\n    };\n  }\n\n  let value: unknown;\n\n  try {\n    value = JSON.parse(item);\n  } catch (error) {\n    // The item is not valid JSON, thus return an error result\n    return {\n      success: false,\n      error\n    };\n  }\n\n  // Everything's fine, thus return a success result\n  return {\n    success: true,\n    value\n  };\n}\n```\n\n\u003cdiv style=\"page-break-after: always;\"\u003e\n\n\u003c/div\u003e\n\n# Generics\n\n## With and Without Type Argument Inference\n\n```ts\nfunction identity\u003cT\u003e(arg: T): T {\n  return arg;\n}\n\nlet output = identity\u003cstring\u003e(\"myString\"); // Type of output is 'string'\nlet output = identity(\"myString\"); // The compiler sets the value of `T`\n```\n\n## Using More Than One Type Argument\n\n```ts\nfunction makePair\u003cF, S\u003e() {\n  let pair: { first: F; second: S };\n\n  function getPair() {\n    return pair;\n  }\n\n  function setPair(x: F, y: S) {\n    pair = {\n      first: x,\n      second: y\n    };\n  }\n  return { getPair, setPair };\n}\nconst { getPair, setPair } = makePair\u003cnumber, string\u003e(); // Creates a pair\nsetPair(1, \"y\"); // Must pass (number, string)\n```\n\n\u003cdiv style=\"page-break-after: always;\"\u003e\n\n\u003c/div\u003e\n\n## Higher Order Function with `Parameters\u003cT\u003e` and `ReturnType\u003cT\u003e`\n\n```ts\nfunction logDuration\u003cT extends (...args: any[]) =\u003e any\u003e(func: T) {\n  const funcName = func.name;\n\n  // Return a new function that tracks how long the original took\n  return (...args: Parameters\u003cT\u003e): ReturnType\u003cT\u003e =\u003e {\n    console.time(funcName);\n    const results = func(...args);\n    console.timeEnd(funcName);\n    return results;\n  };\n}\n\nfunction addNumbers(a: number, b: number): number {\n  return a + b;\n}\n// Hover over is `addNumbersWithLogging: (a: number, b: number) =\u003e number`\nconst addNumbersWithLogging = logDuration(addNumbers);\n\naddNumbersWithLogging(5, 3);\n```\n\n## Advanced Factory using `ConstructorParameters\u003cT\u003e` and `InstanceType\u003cT\u003e`\n\n```ts\nclass Hero {\n  constructor(public point: [number, number]) {}\n}\n\nconst entities = [];\n\nconst entityFactory = \u003c\n  T extends {\n    new (...args: any[]): any;\n  }\n\u003e(\n  classToCreate: T,\n  numberOf: number,\n  ...args: ConstructorParameters\u003cT\u003e\n): InstanceType\u003cT\u003e[] =\u003e\n  [...Array(numberOf)].map(() =\u003e new classToCreate(...args));\n\nentities.push(...entityFactory(Hero, 10, [12, 10]));\n```\n\n\u003cdiv style=\"page-break-after: always;\"\u003e\n\n\u003c/div\u003e\n\n# Discriminated Unions\n\nA data structure used to hold a value that could take on several different, but\nfixed, types.\n\n## Exhaustive Pattern Matching Using `never`\n\n```ts\ninterface Square {\n  kind: \"square\";\n  size: number;\n}\ninterface Rectangle {\n  kind: \"rectangle\";\n  width: number;\n  height: number;\n}\ninterface Circle {\n  kind: \"circle\";\n  radius: number;\n}\ninterface Triangle {\n  kind: \"triangle\";\n  whatever: number;\n}\n\ntype Shape = Square | Rectangle | Circle | Triangle;\n\nfunction assertNever(x: never): never {\n  throw new Error(\"Unexpected object: \" + x);\n}\n\nfunction area(s: Shape) {\n  switch (s.kind) {\n    case \"square\":\n      return s.size * s.size;\n    case \"rectangle\":\n      return s.height * s.width;\n    case \"circle\":\n      return Math.PI * s.radius ** 2;\n    default:\n      return assertNever(s); // Error\n    // Argument of type 'Triangle' not assignable to param of type 'never'\n  }\n}\n```\n\n\u003cdiv style=\"page-break-after: always;\"\u003e\n\n\u003c/div\u003e\n\n# Optional Chaining\n\n## `?.` returns `undefined` when hitting a `null` or `undefined`\n\nAlbum where the artist, and the artists biography might not be present in the\ndata.\n\n```ts\ntype AlbumAPIResponse = {\n  title: string;\n  artist?: {\n    name: string;\n    bio?: string;\n    previousAlbums?: string[];\n  };\n};\n\n// Instead of:\nconst maybeArtistBio = album.artist \u0026\u0026 album.artist.bio;\n\n// ?. acts differently than \u0026\u0026 on \"falsy\" values: empty string, 0, NaN, false\nconst artistBio = album?.artist?.bio;\n\n// optional chaining also works with the [] operators when accessing elements\nconst maybeArtistBioElement = album?.[\"artist\"]?.[\"bio\"];\nconst maybeFirstPreviousAlbum = album?.artist?.previousAlbums?.[0];\n```\n\nOptional chaining on an optional function:\n\n```ts\ninterface OptionalFunction {\n  bar?: () =\u003e number;\n}\n\nconst foo: OptionalFunction = {};\nconst bat = foo.bar?.(); // number | undefined\n```\n\n\u003cdiv style=\"page-break-after: always;\"\u003e\n\n\u003c/div\u003e\n\n# Nullish Coalescing\n\n## `??` “fall Backs” to a Default Value When Dealing with `null` or `undefined`\n\nValue `foo` will be used when it’s “present”; but when it’s `null` or\n`undefined`, calculate `bar()` in its place.\n\n```ts\nlet x = foo ?? bar();\n// instead of\nlet x = foo !== null \u0026\u0026 foo !== undefined ? foo : bar();\n```\n\nIt can replace uses of `||` when trying to use a default value, and avoids bugs.\nWhen `localStorage.volume` is set to `0`, the page will set the volume to `0.5`\nwhich is unintended. `??` avoids some unintended behaviour from `0`, `NaN` and\n`\"\"` being treated as falsy values.\n\n```ts\nfunction initializeAudio() {\n  const volume = localStorage.volume || 0.5; // Potential bug\n}\n```\n\n# Assertion Functions\n\nAssertions in JavaScript are often used to guard against **improper** types\nbeing passed in.\n\n## A Standard JavaScript `Assert()` Doesn’t Work for Type Checking\n\n```ts\nfunction yell(str) {\n  assert(typeof str === \"string\");\n\n  return str.toUppercase(); // Oops! We misspelled 'toUpperCase'\n}\n```\n\n## Using `if` and `typeof` Everywhere is Bloat\n\n```ts\nfunction yell(str) {\n  if (typeof str !== \"string\") {\n    throw new TypeError(\"str should have been a string.\");\n  }\n  // Error caught!\n  return str.toUppercase();\n}\n```\n\n\u003cdiv style=\"page-break-after: always;\"\u003e\n\n\u003c/div\u003e\n\n## Assertion Function Style 1 - Check for a Condition\n\n```ts\nfunction assert(condition: any, msg?: string): asserts condition {\n  if (!condition) {\n    throw new AssertionError(msg);\n  }\n}\n\nfunction yell(str) {\n  assert(typeof str === \"string\");\n\n  return str.toUppercase();\n  //         ~~~~~~~~~~~\n  // error: Property 'toUppercase' does not exist on type 'string'.\n  //        Did you mean 'toUpperCase'?\n}\n```\n\n## Assertion Function Style 2 - Tell TypeScript That a Specific Variable or Property Has a Different Type\n\nVery similar to writing type predicate signatures.\n\n```ts\nfunction assertIsString(val: any): asserts val is string {\n  if (typeof val !== \"string\") {\n    throw new AssertionError(\"Not a string!\");\n  }\n}\n\nfunction yell(str: any) {\n  assertIsString(str);\n\n  // Now TypeScript knows that 'str' is a 'string'.\n\n  return str.toUppercase();\n  //         ~~~~~~~~~~~\n  // error: Property 'toUppercase' does not exist on type 'string'.\n  //        Did you mean 'toUpperCase'?\n}\n```\n\n#### Thanks to the following sites and people for providing many of the fantastic examples:\n\n[typescriptlang.org](https://www.typescriptlang.org/docs/home.html)\n\n[Marius Schulz - Blog](https://mariusschulz.com/)\n\n[Mike North - TypeScript 3 Fundamentals v2](https://frontendmasters.com/courses/typescript-v2/)\n\n[Shu Uesugi - TypeScript for Beginner Programmers](https://ts.chibicode.com/)\n\n[Dr. Axel Rauschmayer - 2ality](https://2ality.com/index.html)\n\n\u003c/article\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdavid-else%2Fmodern-typescript-with-examples-cheat-sheet","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdavid-else%2Fmodern-typescript-with-examples-cheat-sheet","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdavid-else%2Fmodern-typescript-with-examples-cheat-sheet/lists"}