Skip to content

Instantly share code, notes, and snippets.

View mattpocock's full-sized avatar

Matt Pocock mattpocock

View GitHub Profile

Exercises

Most chapters in the book have practical exercises. These exercises are designed to test your understanding of the material.

You can run the exercises by visiting the GitHub repository for the book, at https://totalts.link/e-repo.

There, you'll find instructions for cloning the repository to your local machine, installing the dependencies, and running the exercises.

Each exercise in the book will have a link to our site, Total TypeScript, where you can find an online version of the exercise. There will also be a handy button to open the exercise in your local editor.

A Note On Node's TypeScript Support

Recently, Node has been moving closer and closer to supporting TypeScript as a first-class citizen.

In Node 23 and 24, you can now use node on the command line to run TypeScript files. This is currently in the experimental stage, and is known colloquially as --experimental-strip-types. In Node 23 or greater, you can run node index.ts. In versions 20-22, a flag is required:

node index.ts # Node 23+
node --experimental-strip-types index.ts # Node 20-22

Setting strict to false makes TypeScript behave in ways which are much less safe.

As an example, strict includes a setting called strictNullChecks. Setting strictNullChecks to false will allow you to assign null to a variable that is supposed to be a string:

let name: string = null; // No error

With strict enabled, TypeScript will, of course, catch this error.

This double-duty functionality can prove quite useful, especially when you have things that feel like types that you want to reuse elsewhere in your code.

We can even create our own enum-like functionality:

export const Direction = {
  Up: "up",
  Down: "down",
  Left: "left",
 Right: "right",

In theory, you can then use those keys to access the values of the object:

keys.forEach((key) => {
  console.log(yetiSeason[key]); // Red squiggly line under key
});

// Hovering over key shows:
// Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ title: string; artist: string; releaseYear: number; }'.

But Flow recommends you use closed objects by default. They think that, especially when working with spread operators, it’s better to err on the side of caution.

However, I think TypeScript's approach makes more sense. Open objects more closely reflect how JavaScript actually works. Given how dynamic JavaScript is, any type system claiming to represent it has to be relatively cautious about how ‘safe’ it can truly be.

Fresh and Stale Objects

So the TypeScript team aimed for a compromise. A dogmatic approach to open objects would be counterproductive. You would be able to add any properties to any object:

type Album = {

This behavior can be frustrating when you misspell the names of an optional parameter. Imagine you misspell timeout as timeOut:

const fetch = (options: { url: string; timeout?: number }) => {
  // Implementation
};

const options = {
  url: "/",
 timeOut: 1000,
@mattpocock
mattpocock / total-typescript-cla.md
Created July 15, 2024 10:43
Total TypeScript CLA

Thank you for your interest in contributing to open source software projects (“Projects”) made available by egghead.io, LLC or its affiliates (“egghead.io”). This Individual Contributor License Agreement (“Agreement”) sets out the terms governing any source code, object code, bug fixes, configuration changes, tools, specifications, documentation, data, materials, feedback, information or other works of authorship that you submit or have submitted, in any form and in any manner, to egghead.io in respect of any of the Projects (collectively “Contributions”). If you have any questions respecting this Agreement, please contact [email protected].

You agree that the following terms apply to all of your past, present and future Contributions. Except for the licenses granted in this Agreement, you retain all of your right, title and interest in and to your Contributions.

Copyright License. You hereby grant, and agree to grant, to egghead.io a non-exclusive, perpetual, irrevocable, worldwide, fully-paid, royalty-fr

Imagine a package.json that looks like this:

{
  "name": "my-package",
  "type": "module",
  "exports": {
    ".": {
      "source": "./src/index.ts",
 "import": "./dist/index.js",
// Name: Trim latest OBS video
import "@johnlindquist/kit";
import { z } from "zod";
import { getActiveEditorFilePath } from "./helpers/vscode";
const { stdout } = await $`ls -t ~/Movies/*.mp4 | head -n 1`;
const inputVideo = stdout.trim();