Effective TypeScript Book Cover

TypeScript is a typed superset of JavaScript with the potential to solve many of the headaches for which JavaScript is famous. But TypeScript has a learning curve of its own, and understanding how to use it effectively can take time.

Effective TypeScript guides you through 62 specific ways to improve your use of TypeScript, following the format popularized by Effective C++ and Effective Java. You’ll advance from a beginning or intermediate user familiar with the basics to an advanced user who knows how to use the language well.

Already have the Book? Visit the GitHub project to see all of the code snippets from the book in one place. You can also report any errors you've found.

If you're interested in a TypeScript book talk at your company, please reach out via Twitter or email.

Buy the Book Buy the eBook

Praise for Effective TypeScript

Effective TypeScript explores the most common questions we see when working with TypeScript and provides practical, results-oriented advice. Regardless of your level of TypeScript experience, you can learn something from this book.

Ryan Cavanaugh, Engineering Lead for TypeScript at Microsoft

This book is packed with practical recipes and must be kept on the desk of every TypeScript eveloper. Even if you think you know TypeScript already, get this book and you won't regret it.

Yakov Fain, Java Champion

I have been working with TypeScript for two years, and with Flow for five. And it happens that I provided technical feedback for this book. It was a joy read. The items in the book provide specific, actionable advice that will help to deepen your understanding of TypeScript, and Dan's explanations are clear and concise. There is a lot of useful information, but my favorite part is Chapter 4, Type Design. Even as an experienced hotshot I learned a number of new things. And the advice sticks with me in my day-to-day work. For example I make an effort to apply types to entire function expressions, and in some cases I do so by using specialized React event handler types that this book pointed me to. Plus Dan convinced me to switch my @type dependencies to devDependencies.

Jesse Hallett, Senior Software Engineer, Originate, Inc.

The book hit me in exactly the right spot. I'm an experienced developer and I've worked with JS on and off for many years, but my structured TS education is limited to the official tutorial. I was able to figure out most of it along the way (TS is intuitive if you have good JS knowledge and realize how it works, Google and SO helped a lot too), but this approach also left me with a lot of gaps in my knowledge, many of which I don't even realize I have. This book excels at plugging such gaps.

Now I have to go and refactor some of my code in the light of what I've learned.

Matěj Zábský

Read more reviews on Goodreads and Amazon.

Recent Blog Posts

See All Posts.

Using infer to unpack nested types

TypeScript's infer keyword can infer quite a bit more than you might expect. It's extremely effective at extracting types from the sort of nested structures that you might get from codegen or an API specification. Continue reading »

Overload on the type of this to specialize generics (The Lost Item)

I cut one item from Effective TypeScript during the final stages of editing. Four years later, it's time for it to see the light of day! It's a trick for specializing generic types for certain subtypes of their type parameters. This post shows how it works, why it's indispensible for wrapper types, and also explains why I cut it from the book. Continue reading »

The Saga of the Closure Compiler, and Why TypeScript Won

This post looks at the Closure Compiler, Google's tool from the mid-2000s for adding types to JavaScript. It looks at how its focus on minification led to very different design choices than TypeScript, and how this and a few other factors led to TypeScript becoming the ubiquitous solution for JavaScript + types. The Closure Compiler represents an alternative path that JavaScript could have taken, and it gives us perspective on TypeScript as it exists today. Continue reading »

TypeScript and SQL: Six Ways to Bridge the Divide

If you develop server code with TypeScript, you'll inevitably come up against the question of how to interact with your database. There's lots of type information in your database (the structure of the tables) and it's not immediately clear how to share that type information between the DB and TypeScript. This post and its accompanying video present six ways to solve this problem and offer some advice gleaned from years of experience combining Postgres and TypeScript. Continue reading »

Recommendation Update: ✂️ Use knip to detect dead code and types

TL;DR: Use ts-prune is in maintenance mode. Use knip to find dead code instead. It's great!

Continue reading »

Notes on TypeScript 5.1

Every three months we get a new TypeScript release and TypeScript 5.1 landed on June 1, 2023. This release has a few interesting new features, but by far the most noticeable changes are performance improvements and error message ergonomics. Let's take a look!

Continue reading »

Item 30: Don’t Repeat Type Information in Documentation

Chapter 4 of Effective TypeScript covers type design: the process of crafting your types to accurately model your domain. This item has always been a favorite of mine because of how immediately actionable it is. When you review code, be on the lookout for violations!

What’s wrong with this code?

/**
* Returns a string with the foreground color.
* Takes zero or one arguments. With no arguments, returns the
* standard foreground color. With one argument, returns the foreground color
* for a particular page.
*/
function getForegroundColor(page?: string) {
return page === 'login' ? {r: 127, g: 127, b: 127} : {r: 0, g: 0, b: 0};
}

The code and the comment disagree! Without more context it’s hard to say which is right, but something is clearly amiss. As a professor of mine used to say, "when your code and your comments disagree, they’re both wrong!"

Continue reading »

A first look at Deno through the Advent of Code 2022

Every year I do the Advent of Code in a different programming language. If you aren't familiar, it's an online coding competition with a new two-part problem every day from December 1st to the 25th. Thousands of programmers participate and share their solutions. It's a great way to learn a language and bond over coding. In 2019 I used Python, in 2020 I used Rust and in 2021 I used Go. I also post an increasingly-belated writeup of my experience and impressions of the language so, at the end of April, here's 2022! (As a partial excuse, I have been writing on a very different blog!)

This past December I chose TypeScript, specifically Deno, which brands itself as "a new way to TypeScript". While TypeScript certainly isn't a new language for me, Deno is a new way to use it. I was also curious how JavaScript/TypeScript would do on AoC-style coding competitions and, frankly, I hadn't been doing much coding of late and was keen to have an excuse to use my favorite language more.

This post is broken into three parts: thoughts on Deno, thoughts on TypeScript/JavaScript for coding competitions, and my thoughts on this year's Advent of Code.

Continue reading »

Notes on TypeScript 5.0 beta

TypeScript developers are a lucky bunch: for us, Christmas comes four times a year when the TypeScript team releases a new beta version. This is our opportunity to try out the latest features. TypeScript 5.0 beta came out on January 26, 2023. Let's take a look at what's new!

Continue reading »

All I Want for Christmas Is… These Seven TypeScript Improvements

It's Christmastime and I've been happily working through this year's Advent of Code in Deno (look forward to a blog post in the new year). What with all the presents, it's a good time to think about what we'd most like to see from TypeScript in the new year. Here are my top seven feature requests for 2023. Yes, that's a lot, but really I'd be thrilled with just one or two. Pretty please? Continue reading »

Older Posts

2021-01-09

For new TypeScript content every ~3 weeks, including new examples, sample items, videos and book updates, choose one of these ways to stay in touch:

Subscribe to the Newsletter Follow @danvdk RSS

Table of Contents

In an Effective-style book, the title of each item is a specific piece of advice. This means that the Table of Contents forms a summary of all the advice in the book. If any item piques your curiosity and you want to learn more, order a copy.

Chapter 1: Getting to Know TypeScript

Before we dive into the details, this chapter helps you understand the big picture of TypeScript. What is it and how should you think about it? How does it relate to JavaScript? Are its types nullable or are they not? What's this about any? And ducks?

  1. Understand the Relationship Between TypeScript and JavaScript
  2. Know Which TypeScript Options You’re Using
  3. Understand That Code Generation Is Independent of Types
  4. Get Comfortable with Structural Typing
  5. Limit Use of the any Type

Chapter 2: TypeScript’s Type System

This chapter walks you through the nuts and bolts of TypeScript's type system: how to think about it, how to use it, choices you'll need to make, and features you should avoid. TypeScript's type system is surprisingly powerful and able to express things you might not expect a type system to be able to. The items in this chapter will give you a solid foundation to build upon as you write TypeScript and read the rest of this book.

  1. Use Your Editor to Interrogate and Explore the Type System
  2. Think of Types as Sets of Values
  3. Know How to Tell Whether a Symbol Is in the Type Space or Value Space
  4. Prefer Type Declarations to Type Assertions
  5. Avoid Object Wrapper Types (String, Number, Boolean, Symbol, BigInt)
  6. Recognize the Limits of Excess Property Checking
  7. Apply Types to Entire Function Expressions When Possible
  8. Know the Differences Between type and interface
  9. Use Type Operations and Generics to Avoid Repeating Yourself
  10. Use Index Signatures for Dynamic Data
  11. Prefer Arrays, Tuples, and ArrayLike to number Index Signatures
  12. Use readonly to Avoid Errors Associated with Mutation
  13. Use Mapped Types to Keep Values in Sync

Chapter 3: Type Inference

This chapter shows you some of the problems that can arise with type inference and how to fix them. After reading it, you should have a good understanding of how TypeScript infers types, when you still need to write type declarations, and when it's a good idea to write type declarations even when a type can be inferred.

  1. Avoid Cluttering Your Code with Inferable Types
  2. Use Different Variables for Different Types
  3. Understand Type Widening
  4. Understand Type Narrowing
  5. Create Objects All at Once
  6. Be Consistent in Your Use of Aliases
  7. Use async Functions Instead of Callbacks for Asynchronous Code
  8. Understand How Context Is Used in Type Inference
  9. Use Functional Constructs and Libraries to Help Types Flow

Chapter 4: Type Design

Code is difficult to understand if you can't see the data or data types on which it operates. This is one of the great advantages of a type system: by writing out types, you make them visible to readers of your code. And this makes your code understandable. Other chapters cover the nuts and bolts of TypeScript types: using them, inferring them, and writing declarations with them. This chapter discusses the design of the types themselves. The examples in this chapter are all written with TypeScript in mind, but most of the ideas are more broadly applicable.

  1. Prefer Types That Always Represent Valid States
  2. Be Liberal in What You Accept and Strict in What You Produce
  3. Don’t Repeat Type Information in Documentation
  4. Push Null Values to the Perimeter of Your Types
  5. Prefer Unions of Interfaces to Interfaces of Unions
  6. Prefer More Precise Alternatives to String Types
  7. Prefer Incomplete Types to Inaccurate Types
  8. Generate Types from APIs and Specs, Not Data
  9. Name Types Using the Language of Your Problem Domain
  10. Consider “Brands” for Nominal Typing

Chapter 5: Working with any

Type systems were traditionally binary affairs: either a language had a fully static type system or a fully dynamic one. TypeScript blurs the line, because its type system is optional and gradual. You can add types to parts of your program but not others. This is essential for migrating existing JavaScript codebases to TypeScript bit by bit. Key to this is the any type, which effectively disables type checking for parts of your code. It is both powerful and prone to abuse. Learning to use any wisely is essential for writing effective TypeScript. This chapter walks you through how to limit the downsides of any while still retaining its benefits.

  1. Use the Narrowest Possible Scope for any Types
  2. Prefer More Precise Variants of any to Plain any
  3. Hide Unsafe Type Assertions in Well-Typed Functions
  4. Understand Evolving any
  5. Use unknown Instead of any for Values with an Unknown Type
  6. Prefer Type-Safe Approaches to Monkey Patching
  7. Track Your Type Coverage to Prevent Regressions in Type Safety

Chapter 6: Types Declarations and @types

Dependency management can be confusing in any language, and TypeScript is no exception. This chapter will help you build a mental model for how dependencies work in TypeScript and show you how to work through some of the issues that can come up with them. It will also help you craft your own type declaration files to publish and share with others. By writing great type declarations, you can help not just your own project but the entire TypeScript community.

  1. Put TypeScript and @types in devDependencies
  2. Understand the Three Versions Involved in Type Declarations
  3. Export All Types That Appear in Public APIs
  4. Use TSDoc for API Comments
  5. Provide a Type for this in Callbacks
  6. Prefer Conditional Types to Overloaded Declarations
  7. Mirror Types to Sever Dependencies
  8. Be Aware of the Pitfalls of Testing Types

Chapter 7: Writing and Running Your Code

This chapter is a bit of a grab bag: it covers some issues that come up in writing code (not types) as well as issues you may run into when you run your code.

  1. Prefer ECMAScript Features to TypeScript Features
  2. Know How to Iterate Over Objects
  3. Understand the DOM hierarchy
  4. Don’t Rely on Private to Hide Information
  5. Use Source Maps to Debug TypeScript

Chapter 8. Migrating to TypeScript

You've heard that TypeScript is great. You also know from painful experience that maintaining your 15-year-old, 100,000-line JavaScript library isn't. If only it could become a TypeScript library! This chapter offers some advice about migrating your JavaScript project to TypeScript without losing your sanity and abandoning the effort.

  1. Write Modern JavaScript
  2. Use @ts-check and JSDoc to Experiment with TypeScript
  3. Use allowJs to Mix TypeScript and JavaScript
  4. Convert Module by Module Up Your Dependency Graph
  5. Don’t Consider Migration Complete Until You Enable noImplicitAny

About the Author

Dan Vanderkam

Dan Vanderkam is a principal software engineer at Sidewalk Labs, where he's built engineering teams and processes for all of its products and spinouts, all of which use TypeScript. He previously worked on open source genome visualizations at Mt. Sinai's Icahn School of Medicine and on Google search features used by billions of people (search for sunset nyc or population of france). He has a long history of working on open source projects, including the popular dygraphs library and source-map-explorer, a tool for visualizing JavaScript code size. He is also a co-founder of the NYC TypeScript Meetup.

When he's not programming, Dan enjoys climbing rocks and playing bridge. He writes on Medium and at danvk.org. He earned his bachelor's in computer science from Rice University in Houston, Texas, and lives in Brooklyn, New York.

Follow @danvdk Visit danvk.org