Preface to the Second Edition
It’s hard to believe it’s been nearly five years since the first edition of Effective TypeScript was published. The book and its companion website have both been well received and have helped countless developers improve their understanding and usage of the language.
I was surprised how quickly I began to get asked whether the book was out-of-date. It only took six months! Given the pace of change in TypeScript in the years leading up to the first edition, this was a real concern of mine. I tried to avoid printing material that would soon be out-of-date. This meant focusing more on timeless topics like language fundamentals and program design, rather than on libraries and frameworks. By and large, the material in Effective TypeScript has held up well.
As TypeScript developed and gained new features, it didn’t invalidate the first edition as much as it created gaps in its coverage. Writing an “effective” item requires more than just knowing how a feature works. It requires experience using that feature: time spent learning which patterns work well and which ones don’t hold up. Conditional types had only recently been added to the language in 2019, so I had little experience with them. They’re covered more extensively in this edition. Template literal types have been the biggest addition to TypeScript in the past five years. They’ve opened whole new worlds of possibilities and are covered in Item 54.
Moreover, thanks to projects like the Type Challenges, TypeScript developers have become much more ambitious in what they do in the type system. Generics and type-level programming were covered only lightly in the first edition. Now they get an entire chapter, Chapter 6.
More than eight years after I first tried TypeScript, I continue to enjoy it and get excited every time I read the latest release notes or see an ambitious new PR from Anders Hejlsberg making the rounds. I also continue to enjoy helping other developers learn TypeScript and improve their usage of it. I hope that comes across in these pages, and I hope that reading this book helps you enjoy working in TypeScript as much as I do!
Wallkill, NY
March 2024
Who This Book Is For
The Effective books are intended to be the “standard second book” on their topic. You’ll get the most out of Effective TypeScript if you have some previous practical experience working with JavaScript and TypeScript. My goal with this book is not to teach you TypeScript or JavaScript but to help you advance from a beginning or intermediate user to an expert. The items in this book do this by helping you build mental models of how TypeScript and its ecosystem work, making you aware of pitfalls and traps to avoid, and by guiding you toward using TypeScript’s many capabilities in the most effective ways possible. Whereas a reference book will explain the five ways that a language lets you do X, an Effective book will tell you which of those five to use and why.
TypeScript has evolved rapidly over the past few years, but my hope is that it has stabilized enough that the content in this book will remain valid for years to come. This book focuses primarily on the language itself, rather than any frameworks or build tools. You won’t find any examples of how to use React or Vue with TypeScript, or how to configure TypeScript to work with webpack or Vite. The advice in this book should be relevant to all TypeScript users.
Why I Wrote This Book
When I first started working at Google, I was given a copy of the third edition of Effective C++ by Scott Meyers (Addison-Wesley Professional). It was unlike any other programming book I’d read. It made no attempt to be accessible to beginners or to be a complete guide to the language. Rather than telling you what the different features of C++ did, it told you how you should and should not use them. It did so through dozens of short, specific items motivated by concrete examples.
The effect of reading all these examples while using the language daily was unmistakable. I’d used C++ before, but for the first time I felt comfortable with it and knew how to think about the choices it presented to me. In later years I would have similar experiences reading Effective Java by Joshua Bloch (Addison-Wesley Professional) and Effective JavaScript by David Herman (Addison-Wesley Professional).
If you’re already comfortable working in a few different programming languages, then diving straight into the odd corners of a new one can be an effective way to challenge your mental models and learn what makes it different. I’ve learned an enormous amount about TypeScript from writing this book. I hope you’ll have the same experience reading it!
How This Book Is Organized
This book is a collection of “items,” each of which is a short technical essay that gives you specific advice about some aspect of TypeScript. The items are grouped thematically into chapters, but feel free to jump around and read whichever ones look most interesting to you.
Each item’s title conveys the key takeaway. These are the things you should remember as you’re using TypeScript, so it’s worth skimming the table of contents to get them in your head. If you’re writing documentation, for example, and have a nagging sense that you shouldn’t be writing type information, then you’ll know to read Item 31: Don’t Repeat Type Information in Documentation.
The text of the item expands on the advice in the title and backs it up with concrete examples and technical arguments. Almost every point made in this book is demonstrated through example code. I tend to read technical books by looking at the examples and skimming the prose, and I assume you do something similar. I hope you’ll read the prose and explanations! But the main points should still come across if you skim the examples.
After reading the item, you should understand why it will help you use TypeScript more effectively. You’ll also know enough to understand if it doesn’t apply to your situation. Scott Meyers, the author of Effective C++, gives a memorable example of this. He met a team of engineers who wrote software that ran on missiles. They knew they could ignore his advice about preventing resource leaks, because their programs would always terminate when the missile hit the target and their hardware blew up. I’m not aware of any missiles with JavaScript runtimes, but the James Webb Space Telescope has one, so you never know!
Finally, each item ends with “Things to Remember.” These are a few bullet points that summarize the item. If you’re skimming through, you can read these to get a sense for what the item is saying and whether you’d like to read more. You should still read the item! But the summary will do in a pinch.
Conventions in TypeScript Code Samples
All code samples are TypeScript except where it’s clear from the context that they are JSON, HTML, or some other language. Much of the experience of using TypeScript involves interacting with your editor, which presents some challenges in print. I’ve adopted a few conventions to make this work.
Most editors surface errors using squiggly underlines. To see the full error message, you hover over the underlined text. To indicate an error in a code sample, I put squiggles in a comment line under the place where the error occurs:
let
str
=
'not a number'
;
let
num
:
number
=
str
;
// ~~~ Type 'string' is not assignable to type 'number'
I occasionally edit the error messages for clarity and brevity, but I never remove an error. If you copy/paste a code sample into your editor, you should get exactly the errors indicated—no more, no less.
To draw attention to the lack of an error, I use // OK
:
let
str
=
'not a number'
;
let
num
:
number
=
str
as
any
;
// OK
You should be able to hover over a symbol in your editor to see what TypeScript considers its type. To indicate this in text, I use a comment with Twoslash syntax (^?
):
let
v
=
{
str
:
'hello'
,
num
:
42
};
// ^? let v: { str: string; num: number; }
The comment indicates what you’d see in your editor if you moused over the symbol above the caret (^
). This matches the convention used on the TypeScript playground. If you copy a code sample over there and drop everything after the ^?
, TypeScript will fill in the rest for you. What you see on the playground (Figure P-1) should precisely match what you see in print.
I will occasionally introduce no-op statements to indicate the type of a variable on a specific line of code:
function
foo
(
value
:
string
|
string
[])
{
if
(
Array
.
isArray
(
value
))
{
value
;
// ^? (parameter) value: string[]
}
else
{
value
;
// ^? (parameter) value: string
}
}
The value;
lines are only there to demonstrate the type in each branch of the conditional. You don’t need to (and shouldn’t) include statements like this in your own code.
Unless otherwise noted or clear from context, code samples are intended to be checked with the --strict
flag. While printed copies of a book don’t change, TypeScript does, and it’s inevitable that some of the types or errors in code samples will be different in the future. Check the Effective TypeScript repo for updated versions of the examples in this book. All samples were verified with literate-ts using TypeScript 5.4.
Typographical Conventions Used in This Book
The following typographical conventions are used in this book:
- Italic
-
Indicates new terms, URLs, email addresses, filenames, and file extensions.
Constant width
-
Used for program listings, as well as within paragraphs to refer to program elements such as variable or function names, databases, data types, environment variables, statements, and keywords.
Constant width bold
-
Shows commands or other text that should be typed literally by the user.
Constant width italic
-
Shows text that should be replaced with user-supplied values or by values determined by context.
Tip
This element signifies a tip or suggestion.
Note
This element signifies a general note.
Warning
This element indicates a warning or caution.
Using Code Examples
Supplemental material (code examples, exercises, etc.) is available for download at https://github.com/danvk/effective-typescript.
This book is here to help you get your job done. In general, if example code is offered with this book, you may use it in your programs and documentation. You do not need to contact us for permission unless you’re reproducing a significant portion of the code. For example, writing a program that uses several chunks of code from this book does not require permission. Selling or distributing examples from O’Reilly books does require permission. Answering a question by citing this book and quoting example code does not require permission. Incorporating a significant amount of example code from this book into your product’s documentation does require permission.
We appreciate, but generally do not require, attribution. An attribution usually includes the title, author, publisher, and ISBN. For example: “Effective TypeScript, 2nd ed., by Dan Vanderkam (O’Reilly). Copyright 2024 Dan Vanderkam, 978-1-492-05374-3.”
If you feel your use of code examples falls outside fair use or the permission given above, feel free to contact us at permissions@oreilly.com.
O’Reilly Online Learning
Note
For more than 40 years, O’Reilly Media has provided technology and business training, knowledge, and insight to help companies succeed.
Our unique network of experts and innovators share their knowledge and expertise through books, articles, and our online learning platform. O’Reilly’s online learning platform gives you on-demand access to live training courses, in-depth learning paths, interactive coding environments, and a vast collection of text and video from O’Reilly and 200+ other publishers. For more information, visit https://oreilly.com.
How to Contact Us
Please address comments and questions concerning this book to the publisher:
- O’Reilly Media, Inc.
- 1005 Gravenstein Highway North
- Sebastopol, CA 95472
- 800-889-8969 (in the United States or Canada)
- 707-827-7019 (international or local)
- 707-829-0104 (fax)
- support@oreilly.com
- https://www.oreilly.com/about/contact.html
We have a web page for this book, where we list errata, examples, and any additional information. You can access this page at https://oreil.ly/effective-typescript-2e.
For news and information about our books and courses, visit http://www.oreilly.com.
Find us on LinkedIn: https://linkedin.com/company/oreilly-media.
Watch us on YouTube: http://youtube.com/oreillymedia.
Acknowledgments
Despite my hopes, writing a second edition did not prove any easier or less time-consuming than the first. In the process, the book has grown from 62 items to 83. In addition to writing 22 new items (one old item was consolidated into another), I’ve reviewed and thoroughly revised all the original material. Some parts, such as Items 45 and 55, are near complete rewrites.
Many new items are based on material that first appeared on the Effective TypeScript blog, though all of these have seen significant revision. Chapter 6 is largely based on my personal experiences building the crosswalk and crudely-typed libraries for Delve at Sidewalk Labs.
Here are the origins of the new items in the second edition:
-
Item 28 is adapted from the blog post “Use Classes and Currying to Create New Inference Sites”.
-
Item 32 arose from code reviews. I didn’t know this was a rule until I saw it broken!
-
Item 36 was inspired by feedback I’ve given on countless code reviews.
-
Item 37 is based on personal experience and Evan Martin’s blog post “Why Not Add an Option for That?”. Cory House’s frequent tweets on this topic gave me courage to include it in the book.
-
Item 38 was inspired by the Alan Perlis quote, which I frequently cite, as well as by Scott Meyers’s rule.
-
Item 39 is based on my team’s experience with the
Jsonify
adapter, which we were excited to adopt and then even more excited to ditch. The experience led to the blog post “The Trouble with Jsonify: Unify Types Instead of Modeling Small Differences”. -
Item 48 is adapted from the blog post “The Seven Sources of Unsoundness in TypeScript” with significant input from Ryan Cavanaugh.
-
Item 50 was inspired by lots of thinking about what types really are, and a Stack Overflow answer explaining dependent types.
-
Item 51 is an adaptation of the blog post “The Golden Rule of Generics”, which is, in turn, an adaptation of advice in the TypeScript handbook.
-
Item 53 was inspired by my work on crosswalk and crudely-typed, and curiosity about all those
[T]
wrappers I was seeing. -
Item 54 was inspired by my own explorations of template literal types after TypeScript 4.1 was released, which culminated in the blog post “TypeScript Splits the Atom!”.
-
Item 56 is the culmination of my long-standing interest in this topic. This was kicked off by Titian Cernicova-Dragomir’s answer to a Stack Overflow question about typing
_.invert
, followed by my own experiences in crosswalk and crudely-typed, which eventually led to the blog post “The Display of Types”. -
Item 57 was inspired by the release notes for TypeScript 4.5, which added tail recursion.
-
Item 58 was inspired by experience connecting TypeScript with databases that eventually led to my TypeScript Congress 2022 talk: “TypeScript and SQL: Six Ways to Bridge the Divide”.
-
Item 59 presents a widespread trick that Jesse Hallett introduced me to while reviewing the first edition. The “pairs” variation comes from a 2021 tweet by Tom Hicks.
-
Item 62 was inspired by an Artsy blog post: “Conditional Types in TypeScript”.
-
Item 63 originated with Ryan Cavanaugh’s feedback on the first edition, which I eventually distilled into a blog post: “Exclusive Or and the Optional never Trick”. Stefan Baumgartner’s enthusiasm for this trick in the TypeScript Cookbook (O’Reilly) encouraged me to include it in the book.
-
Item 71 was inspired by a discussion with Evan Martin on reddit and a frustrating bug that came back to
new Set("string")
. This led to the blog post “In Defense of Interface: Using Declaration Merging to Disable ‘Bad Parts’”. -
Item 74 is a topic that comes up frequently, especially if you don’t have the right mental model of TypeScript.
-
Item 76 was inspired by countless debugging sessions that came back to an incorrect model of your environment.
-
Item 77 was inspired by personal curiosity about this topic, a few Stack Overflow questions, and a Gary Bernhardt talk.
-
Item 78 was inspired by painful personal experience with TypeScript getting slow. It’s based on the TypeScript wiki and the blog post “What’s Typescript Compiling? Use a Treemap to Find Out”.
Thanks to my tech reviewers, Josh Goldberg, Stefan Baumgartner, Ryan Cavanaugh, Boris Cherny, and Titian Cernicova-Dragomir. Your feedback made this book immensely better. Thanks to my coworkers on the Delve experience squad (particularly Stephanie Chew, Luda Zhao, Ha Vu, and Amanda Meurer) for all the code reviews and for accommodating my boundless enthusiasm for TypeScript. Thanks to everyone at O’Reilly who helped make this book happen: Angela Rufino, Ashley Stussy, Amanda Quinn, Clare Laylock, Sonia Saruba. Thanks to Chris Mischaikow for the last-minute proofreading. Spotify’s Jazzy Morning playlist, starting with Arta Porting’s Beautiful Sunrise, provided a soundtrack for writing and editing.
Finally, thanks to Alex for all her support: through a pandemic, online and in-person weddings, a job change, and a big move, I’m glad at least one thing has stayed constant!
Get Effective TypeScript, 2nd Edition now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.