# Table of Contents
- [README | TypeScript Deep Dive](#readme-typescript-deep-dive)
- [Getting Started | TypeScript Deep Dive](#getting-started-typescript-deep-dive)
- [Why TypeScript | TypeScript Deep Dive](#why-typescript-typescript-deep-dive)
- [JavaScript | TypeScript Deep Dive](#javascript-typescript-deep-dive)
- [Equality | TypeScript Deep Dive](#equality-typescript-deep-dive)
- [Null vs. Undefined | TypeScript Deep Dive](#null-vs-undefined-typescript-deep-dive)
- [References | TypeScript Deep Dive](#references-typescript-deep-dive)
- [this | TypeScript Deep Dive](#this-typescript-deep-dive)
- [Closure | TypeScript Deep Dive](#closure-typescript-deep-dive)
- [Number | TypeScript Deep Dive](#number-typescript-deep-dive)
- [Truthy | TypeScript Deep Dive](#truthy-typescript-deep-dive)
- [Future JavaScript Now | TypeScript Deep Dive](#future-javascript-now-typescript-deep-dive)
- [Rest Parameters | TypeScript Deep Dive](#rest-parameters-typescript-deep-dive)
- [Classes Emit | TypeScript Deep Dive](#classes-emit-typescript-deep-dive)
- [Classes | TypeScript Deep Dive](#classes-typescript-deep-dive)
- [const | TypeScript Deep Dive](#const-typescript-deep-dive)
- [Arrow Functions | TypeScript Deep Dive](#arrow-functions-typescript-deep-dive)
- [let | TypeScript Deep Dive](#let-typescript-deep-dive)
- [Destructuring | TypeScript Deep Dive](#destructuring-typescript-deep-dive)
- [for...of | TypeScript Deep Dive](#for-of-typescript-deep-dive)
- [Project | TypeScript Deep Dive](#project-typescript-deep-dive)
- [Spread Operator | TypeScript Deep Dive](#spread-operator-typescript-deep-dive)
- [Template Strings | TypeScript Deep Dive](#template-strings-typescript-deep-dive)
- [Async Await | TypeScript Deep Dive](#async-await-typescript-deep-dive)
- [Node.js QuickStart | TypeScript Deep Dive](#node-js-quickstart-typescript-deep-dive)
- [Which Files? | TypeScript Deep Dive](#which-files-typescript-deep-dive)
- [Iterators | TypeScript Deep Dive](#iterators-typescript-deep-dive)
- [Library QuickStart | TypeScript Deep Dive](#library-quickstart-typescript-deep-dive)
- [Modules | TypeScript Deep Dive](#modules-typescript-deep-dive)
- [tsconfig.json | TypeScript Deep Dive](#tsconfig-json-typescript-deep-dive)
- [Browser QuickStart | TypeScript Deep Dive](#browser-quickstart-typescript-deep-dive)
- [Dynamic Import Expressions | TypeScript Deep Dive](#dynamic-import-expressions-typescript-deep-dive)
- [Promise | TypeScript Deep Dive](#promise-typescript-deep-dive)
- [Generators | TypeScript Deep Dive](#generators-typescript-deep-dive)
- [JSX | TypeScript Deep Dive](#jsx-typescript-deep-dive)
- [Options | TypeScript Deep Dive](#options-typescript-deep-dive)
- [Errors in TypeScript | TypeScript Deep Dive](#errors-in-typescript-typescript-deep-dive)
- [noImplicitAny | TypeScript Deep Dive](#noimplicitany-typescript-deep-dive)
- [Testing | TypeScript Deep Dive](#testing-typescript-deep-dive)
- [strictNullChecks | TypeScript Deep Dive](#strictnullchecks-typescript-deep-dive)
- [React | TypeScript Deep Dive](#react-typescript-deep-dive)
- [NPM | TypeScript Deep Dive](#npm-typescript-deep-dive)
- [Husky | TypeScript Deep Dive](#husky-typescript-deep-dive)
- [Tools | TypeScript Deep Dive](#tools-typescript-deep-dive)
- [Prettier | TypeScript Deep Dive](#prettier-typescript-deep-dive)
- [Non React JSX | TypeScript Deep Dive](#non-react-jsx-typescript-deep-dive)
- [@types | TypeScript Deep Dive](#-types-typescript-deep-dive)
- [Interpreting Errors | TypeScript Deep Dive](#interpreting-errors-typescript-deep-dive)
- [Ambient Declarations | TypeScript Deep Dive](#ambient-declarations-typescript-deep-dive)
- [Compilation Context | TypeScript Deep Dive](#compilation-context-typescript-deep-dive)
- [Common Errors | TypeScript Deep Dive](#common-errors-typescript-deep-dive)
- [Interfaces | TypeScript Deep Dive](#interfaces-typescript-deep-dive)
- [Callable | TypeScript Deep Dive](#callable-typescript-deep-dive)
- [Namespaces | TypeScript Deep Dive](#namespaces-typescript-deep-dive)
- [global.d.ts | TypeScript Deep Dive](#global-d-ts-typescript-deep-dive)
- [Declaration Spaces | TypeScript Deep Dive](#declaration-spaces-typescript-deep-dive)
- [JS Migration Guide | TypeScript Deep Dive](#js-migration-guide-typescript-deep-dive)
- [Functions | TypeScript Deep Dive](#functions-typescript-deep-dive)
- [Type Assertion | TypeScript Deep Dive](#type-assertion-typescript-deep-dive)
- [Freshness | TypeScript Deep Dive](#freshness-typescript-deep-dive)
- [Generics | TypeScript Deep Dive](#generics-typescript-deep-dive)
- [Literal Types | TypeScript Deep Dive](#literal-types-typescript-deep-dive)
- [TypeScript's Type System | TypeScript Deep Dive](#typescript-s-type-system-typescript-deep-dive)
- [Moving Types | TypeScript Deep Dive](#moving-types-typescript-deep-dive)
- [Readonly | TypeScript Deep Dive](#readonly-typescript-deep-dive)
- [Never Type | TypeScript Deep Dive](#never-type-typescript-deep-dive)
- [Type Inference | TypeScript Deep Dive](#type-inference-typescript-deep-dive)
- [Type Guard | TypeScript Deep Dive](#type-guard-typescript-deep-dive)
- [Enums | TypeScript Deep Dive](#enums-typescript-deep-dive)
- [TypeScript Compiler Internals | TypeScript Deep Dive](#typescript-compiler-internals-typescript-deep-dive)
- [Scanner | TypeScript Deep Dive](#scanner-typescript-deep-dive)
- [Mixins | TypeScript Deep Dive](#mixins-typescript-deep-dive)
- [TIP: SyntaxKind enum | TypeScript Deep Dive](#tip-syntaxkind-enum-typescript-deep-dive)
- [Parser | TypeScript Deep Dive](#parser-typescript-deep-dive)
- [Cypress | TypeScript Deep Dive](#cypress-typescript-deep-dive)
- [Exception Handling | TypeScript Deep Dive](#exception-handling-typescript-deep-dive)
- [Trivia | TypeScript Deep Dive](#trivia-typescript-deep-dive)
- [StyleGuide | TypeScript Deep Dive](#styleguide-typescript-deep-dive)
- [Currying | TypeScript Deep Dive](#currying-typescript-deep-dive)
- [TIPs | TypeScript Deep Dive](#tips-typescript-deep-dive)
- [Index Signatures | TypeScript Deep Dive](#index-signatures-typescript-deep-dive)
- [Checker | TypeScript Deep Dive](#checker-typescript-deep-dive)
- [Stateful Functions | TypeScript Deep Dive](#stateful-functions-typescript-deep-dive)
- [Changelog | TypeScript Deep Dive](#changelog-typescript-deep-dive)
- [String Based Enums | TypeScript Deep Dive](#string-based-enums-typescript-deep-dive)
- [Discriminated Unions | TypeScript Deep Dive](#discriminated-unions-typescript-deep-dive)
- [File Module Details | TypeScript Deep Dive](#file-module-details-typescript-deep-dive)
- [ESLint | TypeScript Deep Dive](#eslint-typescript-deep-dive)
- [lib.d.ts | TypeScript Deep Dive](#lib-d-ts-typescript-deep-dive)
- [singleton pattern | TypeScript Deep Dive](#singleton-pattern-typescript-deep-dive)
- [JQuery tips | TypeScript Deep Dive](#jquery-tips-typescript-deep-dive)
- [Type Compatibility | TypeScript Deep Dive](#type-compatibility-typescript-deep-dive)
- [Type Instantiation | TypeScript Deep Dive](#type-instantiation-typescript-deep-dive)
- [Function parameters | TypeScript Deep Dive](#function-parameters-typescript-deep-dive)
- [Lazy Object Literal Initialization | TypeScript Deep Dive](#lazy-object-literal-initialization-typescript-deep-dive)
- [Create Arrays | TypeScript Deep Dive](#create-arrays-typescript-deep-dive)
- [Avoid Export Default | TypeScript Deep Dive](#avoid-export-default-typescript-deep-dive)
- [Classes are Useful | TypeScript Deep Dive](#classes-are-useful-typescript-deep-dive)
- [Barrel | TypeScript Deep Dive](#barrel-typescript-deep-dive)
- [Program | TypeScript Deep Dive](#program-typescript-deep-dive)
- [Jest | TypeScript Deep Dive](#jest-typescript-deep-dive)
- [Checker Error Reporting | TypeScript Deep Dive](#checker-error-reporting-typescript-deep-dive)
- [Typesafe Event Emitter | TypeScript Deep Dive](#typesafe-event-emitter-typescript-deep-dive)
- [Checker Diagnostics | TypeScript Deep Dive](#checker-diagnostics-typescript-deep-dive)
- [Nominal Typing | TypeScript Deep Dive](#nominal-typing-typescript-deep-dive)
- [Emitter | TypeScript Deep Dive](#emitter-typescript-deep-dive)
- [AST | TypeScript Deep Dive](#ast-typescript-deep-dive)
- [Parser Functions | TypeScript Deep Dive](#parser-functions-typescript-deep-dive)
- [Declaration Files | TypeScript Deep Dive](#declaration-files-typescript-deep-dive)
- [TIP: Visit Children | TypeScript Deep Dive](#tip-visit-children-typescript-deep-dive)
- [Emitter SourceMaps | TypeScript Deep Dive](#emitter-sourcemaps-typescript-deep-dive)
- [Contributing | TypeScript Deep Dive](#contributing-typescript-deep-dive)
- [Variables | TypeScript Deep Dive](#variables-typescript-deep-dive)
- [Binder Error Reporting | TypeScript Deep Dive](#binder-error-reporting-typescript-deep-dive)
- [Binder Declarations | TypeScript Deep Dive](#binder-declarations-typescript-deep-dive)
- [Binder Functions | TypeScript Deep Dive](#binder-functions-typescript-deep-dive)
- [Binder | TypeScript Deep Dive](#binder-typescript-deep-dive)
- [Binder Container | TypeScript Deep Dive](#binder-container-typescript-deep-dive)
- [Binder SymbolTable | TypeScript Deep Dive](#binder-symboltable-typescript-deep-dive)
- [static constructors | TypeScript Deep Dive](#static-constructors-typescript-deep-dive)
- [Limit Property Setters | TypeScript Deep Dive](#limit-property-setters-typescript-deep-dive)
- [Build Toggles | TypeScript Deep Dive](#build-toggles-typescript-deep-dive)
- [Emitter Functions | TypeScript Deep Dive](#emitter-functions-typescript-deep-dive)
- [outFile caution | TypeScript Deep Dive](#outfile-caution-typescript-deep-dive)
---
# README | TypeScript Deep Dive
[](https://www.youtube.com/@basarat)
[](https://basarat.gitbook.io/typescript#typescript-deep-dive)
TypeScript Deep Dive
----------------------------------------------------------------------------------------
Learn Professional TypeScript. I've been looking at the issues that turn up commonly when people start using TypeScript. This is based on the lessons from [Stack Overflow](http://stackoverflow.com/tags/typescript/topusers)
/ [DefinitelyTyped](https://github.com/DefinitelyTyped/)
and general engagement with the [TypeScript community](https://github.com/TypeStrong/)
. You can [follow for updates](https://twitter.com/basarat)
and [don't forget to โ on GitHub](https://github.com/basarat/typescript-book)
๐น
###
[](https://basarat.gitbook.io/typescript#reviews)
Reviews
* Thanks for the wonderful book. Learned a lot from it. ([link](https://www.gitbook.com/book/basarat/typescript/discussions/21#comment-1468279131934)
)
* Its probably the Best TypeScript book out there. Good Job ([link](https://twitter.com/thelondonjs/status/756419561570852864)
)
* Love how precise and clear the examples and explanations are! ([link](https://twitter.com/joe_mighty/status/758290957280346112)
)
* For the low, low price of free, you get pages of pure awesomeness. Chock full of source code examples and clear, concise explanations, TypeScript Deep Dive will help you learn TypeScript development. ([link](https://www.nativescript.org/blog/details/free-book-typescript-deep-dive)
)
* Just a big thank you! **Best TypeScript 2 detailed explanation!** ([link](https://www.gitbook.com/book/basarat/typescript/discussions/38)
)
* This gitbook got my project going pronto. Fluent easy read 5 stars. ([link](https://twitter.com/thebabellion/status/779888195559235584)
)
* I recommend the online #typescript book by @basarat you'll love it.([link](https://twitter.com/markpieszak/status/788099306590969860)
)
* I've always found this by @basarat really helpful. ([link](https://twitter.com/Brocco/status/789887640656945152)
)
* We must highlight TypeScript Deep Dive, an open source book.([link](https://www.siliconrepublic.com/enterprise/typescript-programming-javascript)
)
* Great online resource for learning. ([link](https://twitter.com/rdfuhr/status/790193307708076035)
)
* Thank you for putting this book together, and for all your hard work within the TypeScript community. ([link](https://github.com/basarat/typescript-book/pull/183#issuecomment-257799713)
)
* TypeScript Deep Dive is one of the best technical texts I've read in a while. ([link](https://twitter.com/borekb/status/794287092272599040)
)
* Thanks @basarat for the TypeScript Deep Dive Book. Help me a lot with my first TypeScript project. ([link](https://twitter.com/betolinck/status/797901548562960384)
)
* Thanks to @basarat for this great #typescript learning resource. ([link](https://twitter.com/markuse1501/status/799116176815230976)
)
* Guyz excellent book on Typescript(@typescriptlang) by @basarat ([link](https://twitter.com/deeinlove/status/813245965507260417)
)
* Leaning on the legendary @basarat's "TypeScript Deep Dive" book heavily at the moment ([link](https://twitter.com/sitapati/status/814379404956532737)
)
* numTimesPointedPeopleToBasaratsTypeScriptBook++; ([link](https://twitter.com/brocco/status/814227741696462848)
)
* A book not only for typescript, a good one for deeper JavaScript knowledge as well. [link](https://www.gitbook.com/book/basarat/typescript/discussions/59)
* In my new job, we're using @typescriptlang, which I am new to. This is insanely helpful huge thanks, @basarat! [link](https://twitter.com/netchkin/status/855339390566096896)
* Thank you for writing TypeScript Deep Dive. I have learned so much. [link](https://twitter.com/buctwbzs/status/857198618704355328?refsrc=email&s=11)
* Loving @basarat's @typescriptlang online book basarat.gitbooks.io/typescript/# loaded with great recipes! [link](https://twitter.com/ericliprandi/status/857608837309677568)
* Microsoft doc is great already, but if want to "dig deeper" into TypeScript I find this book of great value [link](https://twitter.com/caludio/status/876729910550831104)
* Thanks, this is a great book ๐ค๐ค [link](https://twitter.com/jjwonmin/status/885666375548547073)
* Deep dive to typescript is awesome in so many levels. i find it very insightful. Thanks [link](https://twitter.com/orenmizr/status/891083492787970053)
* @basarat's intro to @typescriptlang is still one of the best going (if not THE best) [link](https://twitter.com/stevealee/status/953953255968698368)
* This is sweet! So many #typescript goodies! [link](https://twitter.com/pauliescanlon/status/989898852474998784)
###
[](https://basarat.gitbook.io/typescript#get-started)
Get Started
If you are here to read the book online [get started](https://basarat.gitbook.io/typescript/getting-started)
.
###
[](https://basarat.gitbook.io/typescript#translations)
Translations
Book is completely free so you can copy paste whatever you want without requiring permission. If you have a translation you want me to link here. [Send a PR](https://github.com/basarat/typescript-book/edit/master/README.md)
.
* [Filipino](https://github.com/themarshann/typescript-book-fil)
* [Italian](https://github.com/TizioFittizio/typescript-book)
* [Chinese](https://github.com/jkchao/typescript-book-chinese)
* [Russian](https://github.com/etroynov/typescript-book)
* [Portuguese](https://github.com/overlineink/typescript-book)
* [Japanese](https://github.com/yohamta/typescript-book)
* [Spanish](https://github.com/melissarofman/typescript-book)
* [Korean](https://github.com/radlohead/typescript-book)
* [French](https://github.com/HachemiH/typescript-book)
* [Polish](https://github.com/mbiesiad/typescript-book/tree/pl_PL)
* [Thai](https://github.com/futurouz/typescript-book)
* [Bengali](https://github.com/Acesif/typescript-book)
* [Ukrainian](https://github.com/ArtfulBits/typescript-book)
###
[](https://basarat.gitbook.io/typescript#other-options)
Other Options
You can also download one of the Epub, Mobi, or PDF formats from the [actions tab](https://github.com/basarat/typescript-book/actions)
by clicking on the latest build run. You will find the files in the artifacts section.
###
[](https://basarat.gitbook.io/typescript#special-thanks)
Special Thanks
All the amazing [contributors](https://github.com/basarat/typescript-book/graphs/contributors)
๐น
Share URL: https://basarat.gitbook.io/typescript/
[NextGetting Started](https://basarat.gitbook.io/typescript/getting-started)
Last updated 1 year ago
* [TypeScript Deep Dive](https://basarat.gitbook.io/typescript#typescript-deep-dive)
* [Reviews](https://basarat.gitbook.io/typescript#reviews)
* [Get Started](https://basarat.gitbook.io/typescript#get-started)
* [Translations](https://basarat.gitbook.io/typescript#translations)
* [Other Options](https://basarat.gitbook.io/typescript#other-options)
* [Special Thanks](https://basarat.gitbook.io/typescript#special-thanks)
* [Share](https://basarat.gitbook.io/typescript#share)
---
# Getting Started | TypeScript Deep Dive
* [Getting Started with TypeScript](https://basarat.gitbook.io/typescript/getting-started#getting-started-with-typescript)
* [TypeScript Version](https://basarat.gitbook.io/typescript/getting-started#typescript-version)
[](https://basarat.gitbook.io/typescript/getting-started#getting-started-with-typescript)
Getting Started With TypeScript
------------------------------------------------------------------------------------------------------------------------------
TypeScript compiles into JavaScript. JavaScript is what you are actually going to execute (either in the browser or on the server). So you are going to need the following:
* TypeScript compiler (OSS available [in source](https://github.com/Microsoft/TypeScript/)
and on [NPM](https://www.npmjs.com/package/typescript)
)
* A TypeScript editor (you can use notepad if you want but I use [vscode ๐น](https://code.visualstudio.com/)
with an [extension I wrote](https://marketplace.visualstudio.com/items?itemName=basarat.god)
. Also [lots of other IDES support it as well](https://github.com/Microsoft/TypeScript/wiki/TypeScript-Editor-Support)
)
###
[](https://basarat.gitbook.io/typescript/getting-started#typescript-version)
TypeScript Version
Instead of using the _stable_ TypeScript compiler we will be presenting a lot of new stuff in this book that may not be associated with a version number yet. I generally recommend people to use the nightly version because **the compiler test suite only catches more bugs over time**.
You can install it on the command line as
Copy
npm install -g typescript@next
And now the command line `tsc` will be the latest and greatest. Various IDEs support it too, e.g.
* You can ask vscode to use this version by creating `.vscode/settings.json` with the following contents:
Copy
{
"typescript.tsdk": "./node_modules/typescript/lib"
}
###
[](https://basarat.gitbook.io/typescript/getting-started#getting-the-source-code)
Getting the Source Code
The source for this book is available in the books github repository [https://github.com/basarat/typescript-book/tree/master/code](https://github.com/basarat/typescript-book/tree/master/code)
most of the code samples can be copied into vscode and you can play with them as is. For code samples that need additional setup (e.g. npm modules), we will link you to the code sample before presenting the code. e.g.
`this/will/be/the/link/to/the/code.ts`
With a dev setup out of the way let's jump into TypeScript syntax.
[PreviousREADME](https://basarat.gitbook.io/typescript)
[NextWhy TypeScript](https://basarat.gitbook.io/typescript/getting-started/why-typescript)
Last updated 5 years ago
* [Getting Started With TypeScript](https://basarat.gitbook.io/typescript/getting-started#getting-started-with-typescript)
* [TypeScript Version](https://basarat.gitbook.io/typescript/getting-started#typescript-version)
* [Getting the Source Code](https://basarat.gitbook.io/typescript/getting-started#getting-the-source-code)
Copy
// This will be the code under discussion
---
# Why TypeScript | TypeScript Deep Dive
There are two main goals of TypeScript:
* Provide an _optional type system_ for JavaScript.
* Provide planned features from future JavaScript editions to current JavaScript engines
The desire for these goals is motivated below.
[](https://basarat.gitbook.io/typescript/getting-started/why-typescript#the-typescript-type-system)
The TypeScript type system
-----------------------------------------------------------------------------------------------------------------------------------
You might be wondering "**Why add types to JavaScript?**"
Types have proven ability to enhance code quality and understandability. Large teams (Google, Microsoft, Facebook) have continually arrived at this conclusion. Specifically:
* Types increase your agility when doing refactoring. _It's better for the compiler to catch errors than to have things fail at runtime_.
* Types are one of the best forms of documentation you can have. _The function signature is a theorem and the function body is the proof_.
However, types have a way of being unnecessarily ceremonious. TypeScript is very particular about keeping the barrier to entry as low as possible. Here's how:
###
[](https://basarat.gitbook.io/typescript/getting-started/why-typescript#your-javascript-is-typescript)
Your JavaScript is TypeScript
TypeScript provides compile time type safety for your JavaScript code. This is no surprise given its name. The great thing is that the types are completely optional. Your JavaScript code `.js` file can be renamed to a `.ts` file and TypeScript will still give you back valid `.js` equivalent to the original JavaScript file. TypeScript is _intentionally_ and strictly a superset of JavaScript with optional Type checking.
###
[](https://basarat.gitbook.io/typescript/getting-started/why-typescript#types-can-be-implicit)
Types can be Implicit
TypeScript will try to infer as much of the type information as it can in order to give you type safety with minimal cost of productivity during code development. For example, in the following example TypeScript will know that foo is of type `number` below and will give an error on the second line as shown:
Copy
var foo = 123;
foo = '456'; // Error: cannot assign `string` to `number`
// Is foo a number or a string?
This type inference is well motivated. If you do stuff like shown in this example, then, in the rest of your code, you cannot be certain that `foo` is a `number` or a `string`. Such issues turn up often in large multi-file code bases. We will deep dive into the type inference rules later.
###
[](https://basarat.gitbook.io/typescript/getting-started/why-typescript#types-can-be-explicit)
Types can be Explicit
As we've mentioned before, TypeScript will infer as much as it can safely. However, you can use annotations to:
1. Help along the compiler, and more importantly document stuff for the next developer who has to read your code (that might be future you!).
2. Enforce that what the compiler sees, is what you thought it should see. That is your understanding of the code matches an algorithmic analysis of the code (done by the compiler).
TypeScript uses postfix type annotations popular in other _optionally_ annotated languages (e.g. ActionScript and F#).
So if you do something wrong the compiler will report an error e.g.:
We will discuss all the details of all the annotation syntax supported by TypeScript in a later chapter.
###
[](https://basarat.gitbook.io/typescript/getting-started/why-typescript#types-are-structural)
Types are structural
In some languages (specifically nominally typed ones) static typing results in unnecessary ceremony because even though _you know_ that the code will work fine the language semantics force you to copy stuff around. This is why stuff like [automapper for C#](http://automapper.org/)
is _vital_ for C#. In TypeScript because we really want it to be easy for JavaScript developers with a minimum cognitive overload, types are _structural_. This means that _duck typing_ is a first class language construct. Consider the following example. The function `iTakePoint2D` will accept anything that contains all the things (`x` and `y`) it expects:
###
[](https://basarat.gitbook.io/typescript/getting-started/why-typescript#type-errors-do-not-prevent-javascript-emit)
Type errors do not prevent JavaScript emit
To make it easy for you to migrate your JavaScript code to TypeScript, even if there are compilation errors, by default TypeScript _will emit valid JavaScript_ the best that it can. e.g.
will emit the following js:
So you can incrementally upgrade your JavaScript code to TypeScript. This is very different from how many other language compilers work and yet another reason to move to TypeScript.
###
[](https://basarat.gitbook.io/typescript/getting-started/why-typescript#types-can-be-ambient)
Types can be ambient
A major design goal of TypeScript was to make it possible for you to safely and easily use existing JavaScript libraries in TypeScript. TypeScript does this by means of _declaration_. TypeScript provides you with a sliding scale of how much or how little effort you want to put in your declarations, the more effort you put the more type safety + code intelligence you get. Note that definitions for most of the popular JavaScript libraries have already been written for you by the [DefinitelyTyped community](https://github.com/borisyankov/DefinitelyTyped)
so for most purposes either:
1. The definition file already exists.
2. Or at the very least, you have a vast list of well reviewed TypeScript declaration templates already available
As a quick example of how you would author your own declaration file, consider a trivial example of [jquery](https://jquery.com/)
. By default (as is to be expected of good JS code) TypeScript expects you to declare (i.e. use `var` somewhere) before you use a variable
As a quick fix _you can tell TypeScript_ that there is indeed something called `$`:
If you want you can build on this basic definition and provide more information to help protect you from errors:
We will discuss the details of creating TypeScript definitions for existing JavaScript in detail later once you know more about TypeScript (e.g. stuff like `interface` and the `any`).
[](https://basarat.gitbook.io/typescript/getting-started/why-typescript#future-javascript-greater-than-now)
Future JavaScript => Now
-----------------------------------------------------------------------------------------------------------------------------------------
TypeScript provides a number of features that are planned in ES6 for current JavaScript engines (that only support ES5 etc). The TypeScript team is actively adding these features and this list is only going to get bigger over time and we will cover this in its own section. But just as a specimen here is an example of a class:
and the lovely fat arrow function:
###
[](https://basarat.gitbook.io/typescript/getting-started/why-typescript#summary)
Summary
In this section we have provided you with the motivation and design goals of TypeScript. With this out of the way we can dig into the nitty gritty details of TypeScript.
[PreviousGetting Started](https://basarat.gitbook.io/typescript/getting-started)
[NextJavaScript](https://basarat.gitbook.io/typescript/recap)
Last updated 5 years ago
* [The TypeScript type system](https://basarat.gitbook.io/typescript/getting-started/why-typescript#the-typescript-type-system)
* [Your JavaScript is TypeScript](https://basarat.gitbook.io/typescript/getting-started/why-typescript#your-javascript-is-typescript)
* [Types can be Implicit](https://basarat.gitbook.io/typescript/getting-started/why-typescript#types-can-be-implicit)
* [Types can be Explicit](https://basarat.gitbook.io/typescript/getting-started/why-typescript#types-can-be-explicit)
* [Types are structural](https://basarat.gitbook.io/typescript/getting-started/why-typescript#types-are-structural)
* [Type errors do not prevent JavaScript emit](https://basarat.gitbook.io/typescript/getting-started/why-typescript#type-errors-do-not-prevent-javascript-emit)
* [Types can be ambient](https://basarat.gitbook.io/typescript/getting-started/why-typescript#types-can-be-ambient)
* [Future JavaScript => Now](https://basarat.gitbook.io/typescript/getting-started/why-typescript#future-javascript-greater-than-now)
* [Summary](https://basarat.gitbook.io/typescript/getting-started/why-typescript#summary)
Copy
var foo: number = 123;
Copy
var foo: number = '123'; // Error: cannot assign a `string` to a `number`
Copy
interface Point2D {
x: number;
y: number;
}
interface Point3D {
x: number;
y: number;
z: number;
}
var point2D: Point2D = { x: 0, y: 10 }
var point3D: Point3D = { x: 0, y: 10, z: 20 }
function iTakePoint2D(point: Point2D) { /* do something */ }
iTakePoint2D(point2D); // exact match okay
iTakePoint2D(point3D); // extra information okay
iTakePoint2D({ x: 0 }); // Error: missing information `y`
Copy
var foo = 123;
foo = '456'; // Error: cannot assign a `string` to a `number`
Copy
var foo = 123;
foo = '456';
Copy
$('.awesome').show(); // Error: cannot find name `$`
Copy
declare var $: any;
$('.awesome').show(); // Okay!
Copy
declare var $: {
(selector:string): any;
};
$('.awesome').show(); // Okay!
$(123).show(); // Error: selector needs to be a string
Copy
class Point {
constructor(public x: number, public y: number) {
}
add(point: Point) {
return new Point(this.x + point.x, this.y + point.y);
}
}
var p1 = new Point(0, 10);
var p2 = new Point(10, 20);
var p3 = p1.add(p2); // { x: 10, y: 30 }
Copy
var inc = x => x+1;
---
# JavaScript | TypeScript Deep Dive
There were (and will continue to be) a lot of competitors in _Some syntax_ to _JavaScript_ compilers. TypeScript is different from them in that _Your JavaScript is TypeScript_. Here's a diagram:

JavaScript is TypeScript
However, it does mean that _you need to learn JavaScript_ (the good news is _you_ _**only**_ _need to learn JavaScript_). TypeScript is just standardizing all the ways you provide _good documentation_ on JavaScript.
* Just giving you a new syntax doesn't help catch bugs - but might help you write cleaner / less bugs (e.g. CoffeeScript).
* Creating a new language abstracts you too far from your runtimes and communities - but might help on-board you easier if its an already familiar flavour (e.g. Dart - closer for Java / C# devs).
TypeScript is just JavaScript with docs.
> JSNext is open to interpretation - not everything proposed for the next version of JS actually makes it to browsers. TypeScript only adds support for proposals once they reach [stage 3](https://tc39.es/process-document/)
> .
[](https://basarat.gitbook.io/typescript/recap#making-javascript-better)
Making JavaScript Better
------------------------------------------------------------------------------------------------------
TypeScript will try to protect you from portions of JavaScript that never worked (so you don't need to remember this stuff):
Essentially TypeScript is linting JavaScript. Just doing a better job at it than other linters that don't have _type information_.
[](https://basarat.gitbook.io/typescript/recap#you-still-need-to-learn-javascript)
You still need to learn JavaScript
--------------------------------------------------------------------------------------------------------------------------
That said TypeScript is very pragmatic about the fact that _you do write JavaScript_ so there are some things about JavaScript that you still need to know in order to not be caught off-guard. Let's discuss them next.
> Note: TypeScript is a superset of JavaScript. Just with documentation that can actually be used by compilers / IDEs ;)
[PreviousWhy TypeScript](https://basarat.gitbook.io/typescript/getting-started/why-typescript)
[NextEquality](https://basarat.gitbook.io/typescript/recap/equality)
Last updated 5 years ago
* [Making JavaScript Better](https://basarat.gitbook.io/typescript/recap#making-javascript-better)
* [You still need to learn JavaScript](https://basarat.gitbook.io/typescript/recap#you-still-need-to-learn-javascript)
Copy
[] + []; // JavaScript will give you "" (which makes little sense), TypeScript will error
//
// other things that are nonsensical in JavaScript
// - don't give a runtime error (making debugging hard)
// - but TypeScript will give a compile time error (making debugging unnecessary)
//
{} + []; // JS : 0, TS Error
[] + {}; // JS : "[object Object]", TS Error
{} + {}; // JS : NaN or [object Object][object Object] depending upon browser, TS Error
"hello" - 1; // JS : NaN, TS Error
function add(a,b) {
return
a + b; // JS : undefined, TS Error 'unreachable code detected'
}
---
# Equality | TypeScript Deep Dive
[](https://basarat.gitbook.io/typescript/recap/equality#equality)
Equality
-------------------------------------------------------------------------------
One thing to be careful about in JavaScript is the difference between `==` and `===`. As JavaScript tries to be resilient against programming errors `==` tries to do type coercion between two variables e.g. converts a string to a number so that you can compare with a number as shown below:
Copy
console.log(5 == "5"); // true , TS Error
console.log(5 === "5"); // false , TS Error
However, the choices JavaScript makes are not always ideal. For example, in the below example the first statement is false because `""` and `"0"` are both strings and are clearly not equal. However, in the second case both `0` and the empty string (`""`) are falsy (i.e. behave like `false`) and are therefore equal with respect to `==`. Both statements are false when you use `===`.
Copy
console.log("" == "0"); // false
console.log(0 == ""); // true
console.log("" === "0"); // false
console.log(0 === ""); // false
> Note that `string == number` and `string === number` are both compile time errors in TypeScript, so you don't normally need to worry about this.
Similar to `==` vs. `===`, there is `!=` vs. `!==`
So ProTip: Always use `===` and `!==` except for null checks, which we cover later.
[](https://basarat.gitbook.io/typescript/recap/equality#structural-equality)
Structural Equality
-----------------------------------------------------------------------------------------------------
If you want to compare two objects for structural equality `==`/`===` are _**not**_ sufficient. e.g.
Copy
console.log({a:123} == {a:123}); // False
console.log({a:123} === {a:123}); // False
To do such checks use the [deep-equal](https://www.npmjs.com/package/deep-equal)
npm package e.g.
However, quite commonly you don't need deep checks and all you really need is to check by some `id` e.g.
[PreviousJavaScript](https://basarat.gitbook.io/typescript/recap)
[NextReferences](https://basarat.gitbook.io/typescript/recap/references)
Last updated 5 years ago
* [Equality](https://basarat.gitbook.io/typescript/recap/equality#equality)
* [Structural Equality](https://basarat.gitbook.io/typescript/recap/equality#structural-equality)
Copy
import * as deepEqual from "deep-equal";
console.log(deepEqual({a:123},{a:123})); // True
Copy
type IdDisplay = {
id: string,
display: string
}
const list: IdDisplay[] = [\
{\
id: 'foo',\
display: 'Foo Select'\
},\
{\
id: 'bar',\
display: 'Bar Select'\
},\
]
const fooIndex = list.map(i => i.id).indexOf('foo');
console.log(fooIndex); // 0
---
# Null vs. Undefined | TypeScript Deep Dive
> [Free youtube video on the subject](https://www.youtube.com/watch?v=kaUfBNzuUAI)
JavaScript (and by extension TypeScript) has two bottom types : `null` and `undefined`. They are _intended_ to mean different things:
* Something hasn't been initialized : `undefined`.
* Something is currently unavailable: `null`.
[](https://basarat.gitbook.io/typescript/recap/null-undefined#checking-for-either)
Checking for either
-----------------------------------------------------------------------------------------------------------
Fact is you will need to deal with both. Interestingly in JavaScript with `==`, `null` and `undefined` are only equal to each other:
Copy
// Both null and undefined are only `==` to themselves and each other:
console.log(null == null); // true (of course)
console.log(undefined == undefined); // true (of course)
console.log(null == undefined); // true
// You don't have to worry about falsy values making through this check
console.log(0 == undefined); // false
console.log('' == undefined); // false
console.log(false == undefined); // false
Recommend `== null` to check for both `undefined` or `null`. You generally don't want to make a distinction between the two.
Copy
function foo(arg: string | null | undefined) {
if (arg != null) {
// arg must be a string as `!=` rules out both null and undefined.
}
}
> You could also do `== undefined`, but `== null` is more conventional/shorter.
One exception, root level `undefined` values which we discuss next.
[](https://basarat.gitbook.io/typescript/recap/null-undefined#checking-for-root-level-undefined)
Checking for root level undefined
---------------------------------------------------------------------------------------------------------------------------------------
Remember how I said you should use `== null`? Of course you do (cause I just said it ^). Don't use it for root level things. In strict mode if you use `foo` and `foo` is undefined you get a `ReferenceError` **exception** and the whole call stack unwinds.
> You should use strict mode ... and in fact the TS compiler will insert it for you if you use modules ... more on those later in the book so you don't have to be explicit about it :)
So to check if a variable is defined or not at a _global_ level you normally use `typeof`:
[](https://basarat.gitbook.io/typescript/recap/null-undefined#limit-explicit-use-of-undefined)
Limit explicit use of `undefined`
-------------------------------------------------------------------------------------------------------------------------------------
Because TypeScript gives you the opportunity to _document_ your structures separately from values instead of stuff like:
you should use a type annotation:
[](https://basarat.gitbook.io/typescript/recap/null-undefined#node-style-callbacks)
Node style callbacks
-------------------------------------------------------------------------------------------------------------
Node style callback functions (e.g. `(err,somethingElse)=>{ /* something */ }`) are generally called with `err` set to `null` if there isn't an error. You generally just use a truthy check for this anyways:
When creating your own APIs it's _okay_ to use `null` in this case for consistency. In all sincerity for your own APIs you should look at promises, in that case you actually don't need to bother with absent error values (you handle them with `.then` vs. `.catch`).
[](https://basarat.gitbook.io/typescript/recap/null-undefined#dont-use-undefined-as-a-means-of-denoting-validity)
Don't use `undefined` as a means of denoting _validity_
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
For example an awful function like this:
can be much better written like this:
[](https://basarat.gitbook.io/typescript/recap/null-undefined#json-and-serialization)
JSON and serialization
-----------------------------------------------------------------------------------------------------------------
The JSON standard has support for encoding `null` but not `undefined`. When JSON-encoding an object with an attribute that is `null`, the attribute will be included with its null value, whereas an attribute with an `undefined` value will be excluded entirely.
As a result, JSON-based databases may support `null` values but not `undefined` values. Since attributes set to `null` are encoded, you can transmit the intent to clear an attribute by setting its value to `null` before encoding and transmitting the object to a remote store.
Setting attribute values to undefined can save on storage and transmission costs, as the attribute names will not be encoded. However, this can complicate the semantics of clearing values vs. absent values.
[](https://basarat.gitbook.io/typescript/recap/null-undefined#final-thoughts)
Final thoughts
-------------------------------------------------------------------------------------------------
TypeScript team doesn't use `null` : [TypeScript coding guidelines](https://github.com/Microsoft/TypeScript/wiki/Coding-guidelines#null-and-undefined)
and it hasn't caused any problems. Douglas Crockford thinks [`null` is a bad idea](https://www.youtube.com/watch?v=PSGEjv3Tqo0&feature=youtu.be&t=9m21s)
and we should all just use `undefined`.
However, NodeJS style code bases uses `null` for Error arguments as standard as it denotes `Something is currently unavailable`. I personally don't care to distinguish between the two as most projects use libraries with differing opinions and just rule out both with `== null`.
[PreviousReferences](https://basarat.gitbook.io/typescript/recap/references)
[Nextthis](https://basarat.gitbook.io/typescript/recap/this)
Last updated 5 years ago
* [Checking for either](https://basarat.gitbook.io/typescript/recap/null-undefined#checking-for-either)
* [Checking for root level undefined](https://basarat.gitbook.io/typescript/recap/null-undefined#checking-for-root-level-undefined)
* [Limit explicit use of undefined](https://basarat.gitbook.io/typescript/recap/null-undefined#limit-explicit-use-of-undefined)
* [Node style callbacks](https://basarat.gitbook.io/typescript/recap/null-undefined#node-style-callbacks)
* [Don't use undefined as a means of denoting validity](https://basarat.gitbook.io/typescript/recap/null-undefined#dont-use-undefined-as-a-means-of-denoting-validity)
* [JSON and serialization](https://basarat.gitbook.io/typescript/recap/null-undefined#json-and-serialization)
* [Final thoughts](https://basarat.gitbook.io/typescript/recap/null-undefined#final-thoughts)
Copy
if (typeof someglobal !== 'undefined') {
// someglobal is now safe to use
console.log(someglobal);
}
Copy
function foo(){
// if Something
return {a:1,b:2};
// else
return {a:1,b:undefined};
}
Copy
function foo():{a:number,b?:number}{
// if Something
return {a:1,b:2};
// else
return {a:1};
}
Copy
fs.readFile('someFile', 'utf8', (err,data) => {
if (err) {
// do something
} else {
// no error
}
});
Copy
function toInt(str: string) {
return str ? parseInt(str) : undefined;
}
Copy
function toInt(str: string): { valid: boolean, int?: number } {
const int = parseInt(str);
if (isNaN(int)) {
return { valid: false };
}
else {
return { valid: true, int };
}
}
Copy
JSON.stringify({willStay: null, willBeGone: undefined}); // {"willStay":null}
---
# References | TypeScript Deep Dive
Beyond literals, any Object in JavaScript (including functions, arrays, regexp etc) are references. This means the following
[](https://basarat.gitbook.io/typescript/recap/references#mutations-are-across-all-references)
Mutations are across all references
---------------------------------------------------------------------------------------------------------------------------------------
Copy
var foo = {};
var bar = foo; // bar is a reference to the same object
foo.baz = 123;
console.log(bar.baz); // 123
[](https://basarat.gitbook.io/typescript/recap/references#equality-is-for-references)
Equality is for references
---------------------------------------------------------------------------------------------------------------------
Copy
var foo = {};
var bar = foo; // bar is a reference
var baz = {}; // baz is a *new object* distinct from `foo`
console.log(foo === bar); // true
console.log(foo === baz); // false
[PreviousEquality](https://basarat.gitbook.io/typescript/recap/equality)
[NextNull vs. Undefined](https://basarat.gitbook.io/typescript/recap/null-undefined)
Last updated 5 years ago
* [Mutations are across all references](https://basarat.gitbook.io/typescript/recap/references#mutations-are-across-all-references)
* [Equality is for references](https://basarat.gitbook.io/typescript/recap/references#equality-is-for-references)
---
# this | TypeScript Deep Dive
Any access to `this` keyword within a function is controlled by how the function is actually called. It is commonly referred to as the โcalling context.โ
Here is an example:
Copy
function foo() {
console.log(this);
}
foo(); // logs out the global e.g. `window` in browsers
let bar = {
foo
}
bar.foo(); // Logs out `bar` as `foo` was called on `bar`
So be mindful of your usage of `this`. If you want to disconnect `this` in a class from the calling context use an arrow function, [more on that later](https://basarat.gitbook.io/typescript/future-javascript/arrow-functions)
.
[PreviousNull vs. Undefined](https://basarat.gitbook.io/typescript/recap/null-undefined)
[NextClosure](https://basarat.gitbook.io/typescript/recap/closure)
Last updated 5 years ago
---
# Closure | TypeScript Deep Dive
The best thing that JavaScript ever got was closures. A function in JavaScript has access to any variables defined in the outer scope. Closures are best explained with examples:
Copy
function outerFunction(arg) {
var variableInOuterFunction = arg;
function bar() {
console.log(variableInOuterFunction); // Access a variable from the outer scope
}
// Call the local function to demonstrate that it has access to arg
bar();
}
outerFunction("hello closure"); // logs hello closure!
You can see that the inner function has access to a variable (variableInOuterFunction) from the outer scope. The variables in the outer function have been closed by (or bound in) the inner function. Hence the term **closure**. The concept in itself is simple enough and pretty intuitive.
Now the awesome part: The inner function can access the variables from the outer scope _even after the outer function has returned_. This is because the variables are still bound in the inner function and not dependent on the outer function. Again let's look at an example:
Copy
function outerFunction(arg) {
var variableInOuterFunction = arg;
return function() {
console.log(variableInOuterFunction);
}
}
var innerFunction = outerFunction("hello closure!");
// Note the outerFunction has returned
innerFunction(); // logs hello closure!
[](https://basarat.gitbook.io/typescript/recap/closure#reason-why-its-awesome)
Reason why it's awesome
-----------------------------------------------------------------------------------------------------------
It allows you to compose objects easily e.g. the revealing module pattern:
At a high level it is also what makes something like Node.js possible (don't worry if it doesn't click in your brain right now. It will eventually ๐น):
[Previousthis](https://basarat.gitbook.io/typescript/recap/this)
[NextNumber](https://basarat.gitbook.io/typescript/recap/number)
Last updated 5 years ago
Copy
function createCounter() {
let val = 0;
return {
increment() { val++ },
getVal() { return val }
}
}
let counter = createCounter();
counter.increment();
console.log(counter.getVal()); // 1
counter.increment();
console.log(counter.getVal()); // 2
Copy
// Pseudo code to explain the concept
server.on(function handler(req, res) {
loadData(req.id).then(function(data) {
// the `res` has been closed over and is available
res.send(data);
})
});
---
# Number | TypeScript Deep Dive
Whenever you are handling numbers in any programming language you need to be aware of the idiosyncrasies of how the language handles numbers. Here are a few critical pieces of information about numbers in JavaScript that you should be aware of.
[](https://basarat.gitbook.io/typescript/recap/number#core-type)
Core Type
-------------------------------------------------------------------------------
JavaScript has only one number type. It is a double-precision 64-bit `Number`. Below we discuss its limitations along with a recommended solution.
[](https://basarat.gitbook.io/typescript/recap/number#decimal)
Decimal
---------------------------------------------------------------------------
For those familiar with doubles / float in other languages, you would know that binary floating point numbers _do not_ map correctly to Decimal numbers. A trivial (and famous) example with JavaScript's built in numbers is shown below:
Copy
console.log(.1 + .2); // 0.30000000000000004
> For true decimal math use `big.js` mentioned below.
[](https://basarat.gitbook.io/typescript/recap/number#integer)
Integer
---------------------------------------------------------------------------
The integer limits represented by the built in number type are `Number.MAX_SAFE_INTEGER` and `Number.MIN_SAFE_INTEGER`.
Copy
console.log({max: Number.MAX_SAFE_INTEGER, min: Number.MIN_SAFE_INTEGER});
// {max: 9007199254740991, min: -9007199254740991}
**Safe** in this context refers to the fact that the value _cannot be the result of a rounding error_.
The unsafe values are `+1 / -1` away from these safe values and any amount of addition / subtraction will _round_ the result.
Copy
console.log(Number.MAX_SAFE_INTEGER + 1 === Number.MAX_SAFE_INTEGER + 2); // true!
console.log(Number.MIN_SAFE_INTEGER - 1 === Number.MIN_SAFE_INTEGER - 2); // true!
console.log(Number.MAX_SAFE_INTEGER); // 9007199254740991
console.log(Number.MAX_SAFE_INTEGER + 1); // 9007199254740992 - Correct
console.log(Number.MAX_SAFE_INTEGER + 2); // 9007199254740992 - Rounded!
console.log(Number.MAX_SAFE_INTEGER + 3); // 9007199254740994 - Rounded - correct by luck
console.log(Number.MAX_SAFE_INTEGER + 4); // 9007199254740996 - Rounded!
To check safety you can use ES6 `Number.isSafeInteger`:
> JavaScript will eventually get [BigInt](https://developers.google.com/web/updates/2018/05/bigint)
> support. For now, if you want arbitrary precision integer math use `big.js` mentioned below.
[](https://basarat.gitbook.io/typescript/recap/number#big.js)
big.js
-------------------------------------------------------------------------
Whenever you use math for financial calculations (e.g. GST calculation, money with cents, addition etc) use a library like [big.js](https://github.com/MikeMcl/big.js/)
which is designed for
* Perfect decimal math
* Safe out of bound integer values
Installation is simple:
Quick Usage example:
> Do not use this library for math used for UI / performance intensive purposes e.g charts, canvas drawing etc.
[](https://basarat.gitbook.io/typescript/recap/number#nan)
NaN
-------------------------------------------------------------------
When some number calculation is not representable by a valid number, JavaScript returns a special `NaN` value. A classic example is imaginary numbers:
Note: Equality checks **don't** work on `NaN` values. Use `Number.isNaN` instead:
[](https://basarat.gitbook.io/typescript/recap/number#infinity)
Infinity
-----------------------------------------------------------------------------
The outer bounds of values representable in Number are available as static `Number.MAX_VALUE` and `-Number.MAX_VALUE` values.
Values outside the range where precision isn't changed are clamped to these limits e.g.
Values outside the range where precision is changed resolve to special values `Infinity`/`-Infinity` e.g.
Of-course, these special infinity values also show up with arithmetic that requires it e.g.
You can use these `Infinity` values manually or using static members of the `Number` class as shown below:
Fortunately comparison operators (`<` / `>`) work reliably on infinity values:
[](https://basarat.gitbook.io/typescript/recap/number#infinitesimal)
Infinitesimal
---------------------------------------------------------------------------------------
The smallest non-zero value representable in Number is available as static `Number.MIN_VALUE`
Values smaller than `MIN_VALUE` ("underflow values") are converted to 0.
> Further intuition: Just like values bigger than `Number.MAX_VALUE` get clamped to INFINITY, values smaller than `Number.MIN_VALUE` get clamped to `0`.
[PreviousClosure](https://basarat.gitbook.io/typescript/recap/closure)
[NextTruthy](https://basarat.gitbook.io/typescript/recap/truthy)
Last updated 2 years ago
* [Core Type](https://basarat.gitbook.io/typescript/recap/number#core-type)
* [Decimal](https://basarat.gitbook.io/typescript/recap/number#decimal)
* [Integer](https://basarat.gitbook.io/typescript/recap/number#integer)
* [big.js](https://basarat.gitbook.io/typescript/recap/number#big.js)
* [NaN](https://basarat.gitbook.io/typescript/recap/number#nan)
* [Infinity](https://basarat.gitbook.io/typescript/recap/number#infinity)
* [Infinitesimal](https://basarat.gitbook.io/typescript/recap/number#infinitesimal)
Copy
// Safe value
console.log(Number.isSafeInteger(Number.MAX_SAFE_INTEGER)); // true
// Unsafe value
console.log(Number.isSafeInteger(Number.MAX_SAFE_INTEGER + 1)); // false
// Because it might have been rounded to it due to overflow
console.log(Number.isSafeInteger(Number.MAX_SAFE_INTEGER + 10)); // false
Copy
npm install big.js @types/big.js
Copy
import { Big } from 'big.js';
export const foo = new Big('111.11111111111111111111');
export const bar = foo.plus(new Big('0.00000000000000000001'));
// To get a number:
const x: number = Number(bar.toString()); // Loses the precision
Copy
console.log(Math.sqrt(-1)); // NaN
Copy
// Don't do this
console.log(NaN === NaN); // false!!
// Do this
console.log(Number.isNaN(NaN)); // true
Copy
console.log(Number.MAX_VALUE); // 1.7976931348623157e+308
console.log(-Number.MAX_VALUE); // -1.7976931348623157e+308
Copy
console.log(Number.MAX_VALUE + 1 == Number.MAX_VALUE); // true!
console.log(-Number.MAX_VALUE - 1 == -Number.MAX_VALUE); // true!
Copy
console.log(Number.MAX_VALUE + 1e292); // Infinity
console.log(-Number.MAX_VALUE - 1e292); // -Infinity
Copy
console.log( 1 / 0); // Infinity
console.log(-1 / 0); // -Infinity
Copy
console.log(Number.POSITIVE_INFINITY === Infinity); // true
console.log(Number.NEGATIVE_INFINITY === -Infinity); // true
Copy
console.log( Infinity > 1); // true
console.log(-Infinity < -1); // true
Copy
console.log(Number.MIN_VALUE); // 5e-324
Copy
console.log(Number.MIN_VALUE / 10); // 0
---
# Truthy | TypeScript Deep Dive
JavaScript has a concept of `truthy` i.e. things that evaluate like `true` would in certain positions (e.g. `if` conditions and the boolean `&&` `||` operators). The following things are truthy in JavaScript. An example is any number other than `0` e.g.
Copy
if (123) { // Will be treated like `true`
console.log('Any number other than 0 is truthy');
}
Something that isn't truthy is called `falsy`.
Here's a handy table for your reference.
Variable Type
When it is _falsy_
When it is _truthy_
`boolean`
`false`
`true`
`string`
`''` (empty string)
any other string
`number`
`0` `NaN`
any other number
`null`
always
never
`undefined`
always
never
Any other Object including empty ones like `{}`,`[]`
never
always
[](https://basarat.gitbook.io/typescript/recap/truthy#being-explicit)
Being explicit
-----------------------------------------------------------------------------------------
> The `!!` pattern
Quite commonly it helps to be explicit that the intent is to treat the value as a `boolean` and convert it into a _true boolean_ (one of `true`|`false`). You can easily convert values to a true boolean by prefixing it with `!!` e.g. `!!foo`. Its just `!` used _twice_. The first `!` converts the variable (in this case `foo`) to a boolean but inverts the logic (_truthy_ -`!`\> `false`, _falsy_ -`!`\> `true`). The second one toggles it again to match the nature of the original object (e.g. _truthy_ -`!`\> `false` -`!`\> `true`).
It is common to use this pattern in lots of places e.g.
Copy
// Direct variables
const hasName = !!name;
// As members of objects
const someObj = {
hasName: !!name
}
// e.g. in ReactJS JSX
{!!someName &&
{someName}
}
[PreviousNumber](https://basarat.gitbook.io/typescript/recap/number)
[NextFuture JavaScript Now](https://basarat.gitbook.io/typescript/future-javascript)
Last updated 5 years ago
---
# Future JavaScript Now | TypeScript Deep Dive
One of the main selling points of TypeScript is that it allows you to use a bunch of features from ES6 and beyond in current (ES3 and ES5 level) JavaScript engines (like current browsers and Node.js). Here we deep dive into why these features are useful followed by how these features are implemented in TypeScript.
Note: Not all of these features are slated for immediate addition to JavaScript but provide great utility to your code organization and maintenance. Also note that you are free to ignore any of the constructs that don't make sense for your project, although you will end up using most of them eventually ;)
[PreviousTruthy](https://basarat.gitbook.io/typescript/recap/truthy)
[NextClasses](https://basarat.gitbook.io/typescript/future-javascript/classes)
Last updated 5 years ago
---
# Rest Parameters | TypeScript Deep Dive
Rest parameters (denoted by `...argumentName` for the last argument) allow you to quickly accept multiple arguments in your function and get them as an array. This is demonstrated in the below example.
Copy
function iTakeItAll(first, second, ...allOthers) {
console.log(allOthers);
}
iTakeItAll('foo', 'bar'); // []
iTakeItAll('foo', 'bar', 'bas', 'qux'); // ['bas','qux']
Rest parameters can be used in any function be it `function`/`()=>`/`class member`.
[PreviousArrow Functions](https://basarat.gitbook.io/typescript/future-javascript/arrow-functions)
[Nextlet](https://basarat.gitbook.io/typescript/future-javascript/let)
Last updated 5 years ago
---
# Classes Emit | TypeScript Deep Dive
###
[](https://basarat.gitbook.io/typescript/future-javascript/classes/classes-emit#whats-up-with-the-iife)
What's up with the IIFE
The js generated for the class could have been:
Copy
function Point(x, y) {
this.x = x;
this.y = y;
}
Point.prototype.add = function (point) {
return new Point(this.x + point.x, this.y + point.y);
};
The reason it's wrapped in an Immediately-Invoked Function Expression (IIFE) i.e.
Copy
(function () {
// BODY
return Point;
})();
has to do with inheritance. It allows TypeScript to capture the base class as a variable `_super` e.g.
Copy
var Point3D = (function (_super) {
__extends(Point3D, _super);
function Point3D(x, y, z) {
_super.call(this, x, y);
this.z = z;
}
Point3D.prototype.add = function (point) {
var point2D = _super.prototype.add.call(this, point);
return new Point3D(point2D.x, point2D.y, this.z + point.z);
};
return Point3D;
})(Point);
Notice that the IIFE allows TypeScript to easily capture the base class `Point` in a `_super` variable and that is used consistently in the class body.
[](https://basarat.gitbook.io/typescript/future-javascript/classes/classes-emit#extends)
`__extends`
---------------------------------------------------------------------------------------------------------
You will notice that as soon as you inherit a class TypeScript also generates the following function:
Here `d` refers to the derived class and `b` refers to the base class. This function does two things:
1. copies the static members of the base class onto the child class i.e. `for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];`
2. sets up the child class function's prototype to optionally lookup members on the parent's `proto` i.e. effectively `d.prototype.__proto__ = b.prototype`
People rarely have trouble understanding 1, but many people struggle with 2. So an explanation is in order.
###
[](https://basarat.gitbook.io/typescript/future-javascript/classes/classes-emit#d.prototype.__proto__-b.prototype)
`d.prototype.__proto__ = b.prototype`
After having tutored many people about this I find the following explanation to be simplest. First we will explain how the code from `__extends` is equivalent to the simple `d.prototype.__proto__ = b.prototype`, and then why this line in itself is significant. To understand all this you need to know these things:
1. `__proto__`
2. `prototype`
3. effect of `new` on `this` inside the called function
4. effect of `new` on `prototype` and `__proto__`
All objects in JavaScript contain a `__proto__` member. This member is often not accessible in older browsers (sometimes documentation refers to this magical property as `[[prototype]]`). It has one objective: If a property is not found on an object during lookup (e.g. `obj.property`) then it is looked up at `obj.__proto__.property`. If it is still not found then `obj.__proto__.__proto__.property` till either: _it is found_ or _the latest_ `_.__proto___` _itself is null_. This explains why JavaScript is said to support _prototypal inheritance_ out of the box. This is shown in the following example, which you can run in the chrome console or Node.js:
Cool so you understand `__proto__`. Another useful fact is that all `function`s in JavaScript have a property called `prototype` and that it has a member `constructor` pointing back to the function. This is shown below:
Now let's look at _effect of_ `_new_` _on_ `_this_` _inside the called function_. Basically `this` inside the called function is going to point to the newly created object that will be returned from the function. It's simple to see if you mutate a property on `this` inside the function:
Now the only other thing you need to know is that calling `new` on a function assigns the `prototype` of the function to the `__proto__` of the newly created object that is returned from the function call. Here is the code you can run to completely understand it:
That's it. Now look at the following straight out of `__extends`. I've taken the liberty to number these lines:
Reading this function in reverse the `d.prototype = new __()` on line 3 effectively means `d.prototype = {__proto__ : __.prototype}` (because of the effect of `new` on `prototype` and `__proto__`), combining it with the previous line (i.e. line 2 `__.prototype = b.prototype;`) you get `d.prototype = {__proto__ : b.prototype}`.
But wait, we wanted `d.prototype.__proto__` i.e. just the proto changed and maintain the old `d.prototype.constructor`. This is where the significance of the first line (i.e. `function __() { this.constructor = d; }`) comes in. Here we will effectively have `d.prototype = {__proto__ : __.prototype, constructor : d}` (because of the effect of `new` on `this` inside the called function). So, since we restore `d.prototype.constructor`, the only thing we have truly mutated is the `__proto__` hence `d.prototype.__proto__ = b.prototype`.
###
[](https://basarat.gitbook.io/typescript/future-javascript/classes/classes-emit#d.prototype.__proto__-b.prototype-significance)
`d.prototype.__proto__ = b.prototype` significance
The significance is that it allows you to add member functions to a child class and inherit others from the base class. This is demonstrated by the following simple example:
Basically `bird.fly` will be looked up from `bird.__proto__.fly` (remember that `new` makes the `bird.__proto__` point to `Bird.prototype`) and `bird.walk` (an inherited member) will be looked up from `bird.__proto__.__proto__.walk` (as `bird.__proto__ == Bird.prototype` and `bird.__proto__.__proto__` == `Animal.prototype`).
[PreviousClasses](https://basarat.gitbook.io/typescript/future-javascript/classes)
[NextArrow Functions](https://basarat.gitbook.io/typescript/future-javascript/arrow-functions)
Last updated 5 years ago
* [What's up with the IIFE](https://basarat.gitbook.io/typescript/future-javascript/classes/classes-emit#whats-up-with-the-iife)
* [\_\_extends](https://basarat.gitbook.io/typescript/future-javascript/classes/classes-emit#extends)
* [d.prototype.\_\_proto\_\_ = b.prototype](https://basarat.gitbook.io/typescript/future-javascript/classes/classes-emit#d.prototype.__proto__-b.prototype)
* [d.prototype.\_\_proto\_\_ = b.prototype significance](https://basarat.gitbook.io/typescript/future-javascript/classes/classes-emit#d.prototype.__proto__-b.prototype-significance)
Copy
var __extends = this.__extends || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
Copy
var foo = {}
// setup on foo as well as foo.__proto__
foo.bar = 123;
foo.__proto__.bar = 456;
console.log(foo.bar); // 123
delete foo.bar; // remove from object
console.log(foo.bar); // 456
delete foo.__proto__.bar; // remove from foo.__proto__
console.log(foo.bar); // undefined
Copy
function Foo() { }
console.log(Foo.prototype); // {} i.e. it exists and is not undefined
console.log(Foo.prototype.constructor === Foo); // Has a member called `constructor` pointing back to the function
Copy
function Foo() {
this.bar = 123;
}
// call with the new operator
var newFoo = new Foo();
console.log(newFoo.bar); // 123
Copy
function Foo() { }
var foo = new Foo();
console.log(foo.__proto__ === Foo.prototype); // True!
Copy
1 function __() { this.constructor = d; }
2 __.prototype = b.prototype;
3 d.prototype = new __();
Copy
function Animal() { }
Animal.prototype.walk = function () { console.log('walk') };
function Bird() { }
Bird.prototype.__proto__ = Animal.prototype;
Bird.prototype.fly = function () { console.log('fly') };
var bird = new Bird();
bird.walk();
bird.fly();
---
# Classes | TypeScript Deep Dive
[](https://basarat.gitbook.io/typescript/future-javascript/classes#classes)
Classes
----------------------------------------------------------------------------------------
The reason why it's important to have classes in JavaScript as a first class item is that:
1. [Classes offer a useful structural abstraction](https://basarat.gitbook.io/typescript/main-1/classesareuseful)
2. Provides a consistent way for developers to use classes instead of every framework (emberjs,reactjs etc) coming up with their own version.
3. Object Oriented Developers already understand classes.
Finally JavaScript developers can _have_ `_class_`. Here we have a basic class called Point:
Copy
class Point {
x: number;
y: number;
constructor(x: number, y: number) {
this.x = x;
this.y = y;
}
add(point: Point) {
return new Point(this.x + point.x, this.y + point.y);
}
}
var p1 = new Point(0, 10);
var p2 = new Point(10, 20);
var p3 = p1.add(p2); // {x:10,y:30}
This class generates the following JavaScript on ES5 emit:
This is a fairly idiomatic traditional JavaScript class pattern now as a first class language construct.
[](https://basarat.gitbook.io/typescript/future-javascript/classes#inheritance)
Inheritance
------------------------------------------------------------------------------------------------
Classes in TypeScript (like other languages) support _single_ inheritance using the `extends` keyword as shown below:
If you have a constructor in your class then you _must_ call the parent constructor from your constructor (TypeScript will point this out to you). This ensures that the stuff that it needs to set on `this` gets set. Followed by the call to `super` you can add any additional stuff you want to do in your constructor (here we add another member `z`).
Note that you override parent member functions easily (here we override `add`) and still use the functionality of the super class in your members (using `super.` syntax).
[](https://basarat.gitbook.io/typescript/future-javascript/classes#statics)
Statics
----------------------------------------------------------------------------------------
TypeScript classes support `static` properties that are shared by all instances of the class. A natural place to put (and access) them is on the class itself and that is what TypeScript does:
You can have static members as well as static functions.
[](https://basarat.gitbook.io/typescript/future-javascript/classes#access-modifiers)
Access Modifiers
----------------------------------------------------------------------------------------------------------
TypeScript supports access modifiers `public`,`private` and `protected` which determine the accessibility of a `class` member as shown below:
accessible on
`public`
`protected`
`private`
class
yes
yes
yes
class children
yes
yes
no
class instances
yes
no
no
If an access modifier is not specified it is implicitly `public` as that matches the _convenient_ nature of JavaScript ๐น.
Note that at runtime (in the generated JS) these have no significance but will give you compile time errors if you use them incorrectly. An example of each is shown below:
As always these modifiers work for both member properties and member functions.
[](https://basarat.gitbook.io/typescript/future-javascript/classes#abstract)
Abstract
------------------------------------------------------------------------------------------
`abstract` can be thought of as an access modifier. We present it separately because opposed to the previously mentioned modifiers it can be on a `class` as well as any member of the class. Having an `abstract` modifier primarily means that such functionality _cannot be directly invoked_ and a child class must provide the functionality.
* `abstract` **classes** cannot be directly instantiated. Instead the user must create some `class` that inherits from the `abstract class`.
* `abstract` **members** cannot be directly accessed and a child class must provide the functionality.
[](https://basarat.gitbook.io/typescript/future-javascript/classes#constructor-is-optional)
Constructor is optional
------------------------------------------------------------------------------------------------------------------------
The class does not need to have a constructor. e.g. the following is perfectly fine.
[](https://basarat.gitbook.io/typescript/future-javascript/classes#define-using-constructor)
Define using constructor
--------------------------------------------------------------------------------------------------------------------------
Having a member in a class and initializing it like below:
is such a common pattern that TypeScript provides a shorthand where you can prefix the member with an _access modifier_ and it is automatically declared on the class and copied from the constructor. So the previous example can be re-written as (notice `public x:number`):
[](https://basarat.gitbook.io/typescript/future-javascript/classes#property-initializer)
Property initializer
------------------------------------------------------------------------------------------------------------------
This is a nifty feature supported by TypeScript (from ES7 actually). You can initialize any member of the class outside the class constructor, useful to provide default (notice `members = []`)
[PreviousFuture JavaScript Now](https://basarat.gitbook.io/typescript/future-javascript)
[NextClasses Emit](https://basarat.gitbook.io/typescript/future-javascript/classes/classes-emit)
Last updated 5 years ago
* [Classes](https://basarat.gitbook.io/typescript/future-javascript/classes#classes)
* [Inheritance](https://basarat.gitbook.io/typescript/future-javascript/classes#inheritance)
* [Statics](https://basarat.gitbook.io/typescript/future-javascript/classes#statics)
* [Access Modifiers](https://basarat.gitbook.io/typescript/future-javascript/classes#access-modifiers)
* [Abstract](https://basarat.gitbook.io/typescript/future-javascript/classes#abstract)
* [Constructor is optional](https://basarat.gitbook.io/typescript/future-javascript/classes#constructor-is-optional)
* [Define using constructor](https://basarat.gitbook.io/typescript/future-javascript/classes#define-using-constructor)
* [Property initializer](https://basarat.gitbook.io/typescript/future-javascript/classes#property-initializer)
Copy
var Point = (function () {
function Point(x, y) {
this.x = x;
this.y = y;
}
Point.prototype.add = function (point) {
return new Point(this.x + point.x, this.y + point.y);
};
return Point;
})();
Copy
class Point3D extends Point {
z: number;
constructor(x: number, y: number, z: number) {
super(x, y);
this.z = z;
}
add(point: Point3D) {
var point2D = super.add(point);
return new Point3D(point2D.x, point2D.y, this.z + point.z);
}
}
Copy
class Something {
static instances = 0;
constructor() {
Something.instances++;
}
}
var s1 = new Something();
var s2 = new Something();
console.log(Something.instances); // 2
Copy
class FooBase {
public x: number;
private y: number;
protected z: number;
}
// EFFECT ON INSTANCES
var foo = new FooBase();
foo.x; // okay
foo.y; // ERROR : private
foo.z; // ERROR : protected
// EFFECT ON CHILD CLASSES
class FooChild extends FooBase {
constructor() {
super();
this.x; // okay
this.y; // ERROR: private
this.z; // okay
}
}
Copy
abstract class FooCommand {}
class BarCommand extends FooCommand {}
const fooCommand: FooCommand = new FooCommand(); // Cannot create an instance of an abstract class.
const barCommand = new BarCommand(); // You can create an instance of a class that inherits from an abstract class.
Copy
abstract class FooCommand {
abstract execute(): string;
}
class BarErrorCommand extends FooCommand {} // 'BarErrorCommand' needs implement abstract member 'execute'.
class BarCommand extends FooCommand {
execute() {
return `Command Bar executed`;
}
}
const barCommand = new BarCommand();
barCommand.execute(); // Command Bar executed
Copy
class Foo {}
var foo = new Foo();
Copy
class Foo {
x: number;
constructor(x:number) {
this.x = x;
}
}
Copy
class Foo {
constructor(public x:number) {
}
}
Copy
class Foo {
members = []; // Initialize directly
add(x) {
this.members.push(x);
}
}
---
# const | TypeScript Deep Dive
`const` is a very welcomed addition offered by ES6 / TypeScript. It allows you to be immutable with variables. This is good from a documentation as well as a runtime perspective. To use const just replace `var` with `const`:
Copy
const foo = 123;
> The syntax is much better (IMHO) than other languages that force the user to type something like `let constant foo` i.e. a variable + behavior specifier.
`const` is a good practice for both readability and maintainability and avoids using _magic literals_ e.g.
Copy
// Low readability
if (x > 10) {
}
// Better!
const maxRows = 10;
if (x > maxRows) {
}
[](https://basarat.gitbook.io/typescript/future-javascript/const#const-declarations-must-be-initialized)
const declarations must be initialized
----------------------------------------------------------------------------------------------------------------------------------------------------
The following is a compiler error:
Copy
const foo; // ERROR: const declarations must be initialized
[](https://basarat.gitbook.io/typescript/future-javascript/const#left-hand-side-of-assignment-cannot-be-a-constant)
Left hand side of assignment cannot be a constant
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Constants are immutable after creation, so if you try to assign them to a new value it is a compiler error:
[](https://basarat.gitbook.io/typescript/future-javascript/const#block-scoped)
Block Scoped
------------------------------------------------------------------------------------------------
A `const` is block scoped like we saw with [`let`](https://basarat.gitbook.io/typescript/future-javascript/let)
:
[](https://basarat.gitbook.io/typescript/future-javascript/const#deep-immutability)
Deep immutability
----------------------------------------------------------------------------------------------------------
A `const` works with object literals as well, as far as protecting the variable _reference_ is concerned:
However, it still allows sub properties of objects to be mutated, as shown below:
[](https://basarat.gitbook.io/typescript/future-javascript/const#prefer-const)
Prefer const
------------------------------------------------------------------------------------------------
Always use `const`, unless you plan to either lazily initialization of a variable, or do a reassignment (use `let` for those cases).
[Previouslet](https://basarat.gitbook.io/typescript/future-javascript/let)
[NextDestructuring](https://basarat.gitbook.io/typescript/future-javascript/destructuring)
Last updated 5 years ago
* [const declarations must be initialized](https://basarat.gitbook.io/typescript/future-javascript/const#const-declarations-must-be-initialized)
* [Left hand side of assignment cannot be a constant](https://basarat.gitbook.io/typescript/future-javascript/const#left-hand-side-of-assignment-cannot-be-a-constant)
* [Block Scoped](https://basarat.gitbook.io/typescript/future-javascript/const#block-scoped)
* [Deep immutability](https://basarat.gitbook.io/typescript/future-javascript/const#deep-immutability)
* [Prefer const](https://basarat.gitbook.io/typescript/future-javascript/const#prefer-const)
Copy
const foo = 123;
foo = 456; // ERROR: Left-hand side of an assignment expression cannot be a constant
Copy
const foo = 123;
if (true) {
const foo = 456; // Allowed as its a new variable limited to this `if` block
}
Copy
const foo = { bar: 123 };
foo = { bar: 456 }; // ERROR : Left hand side of an assignment expression cannot be a constant
Copy
const foo = { bar: 123 };
foo.bar = 456; // Allowed!
console.log(foo); // { bar: 456 }
---
# Arrow Functions | TypeScript Deep Dive
* [Arrow Functions](https://basarat.gitbook.io/typescript/future-javascript/arrow-functions#arrow-functions)
* [Tip: Arrow Function Need](https://basarat.gitbook.io/typescript/future-javascript/arrow-functions#tip-arrow-function-need)
* [Tip: Arrow Function Danger](https://basarat.gitbook.io/typescript/future-javascript/arrow-functions#tip-arrow-function-danger)
* [Tip: Libraries that use `this`](https://basarat.gitbook.io/typescript/future-javascript/arrow-functions#tip-arrow-functions-with-libraries-that-use-this)
* [Tip: Arrow Function inheritance](https://basarat.gitbook.io/typescript/future-javascript/arrow-functions#tip-arrow-functions-and-inheritance)
* [Tip: Quick object return](https://basarat.gitbook.io/typescript/future-javascript/arrow-functions#tip-quick-object-return)
[](https://basarat.gitbook.io/typescript/future-javascript/arrow-functions#arrow-functions)
Arrow Functions
----------------------------------------------------------------------------------------------------------------
Lovingly called the _fat arrow_ (because `->` is a thin arrow and `=>` is a fat arrow) and also called a _lambda function_ (because of other languages). Another commonly used feature is the fat arrow function `()=>something`. The motivation for a _fat arrow_ is:
1. You don't need to keep typing `function`
2. It lexically captures the meaning of `this`
3. It lexically captures the meaning of `arguments`
For a language that claims to be functional, in JavaScript you tend to be typing `function` quite a lot. The fat arrow makes it simple for you to create a function
Copy
var inc = (x)=>x+1;
`this` has traditionally been a pain point in JavaScript. As a wise man once said "I hate JavaScript as it tends to lose the meaning of `this` all too easily". Fat arrows fix it by capturing the meaning of `this` from the surrounding context. Consider this pure JavaScript class:
Copy
function Person(age) {
this.age = age;
this.growOld = function() {
this.age++;
}
}
var person = new Person(1);
setTimeout(person.growOld,1000);
setTimeout(function() { console.log(person.age); },2000); // 1, should have been 2
If you run this code in the browser `this` within the function is going to point to `window` because `window` is going to be what executes the `growOld` function. Fix is to use an arrow function:
The reason why this works is the reference to `this` is captured by the arrow function from outside the function body. This is equivalent to the following JavaScript code (which is what you would write yourself if you didn't have TypeScript):
Note that since you are using TypeScript you can be even sweeter in syntax and combine arrows with classes:
> [A sweet video about this pattern ๐น](https://egghead.io/lessons/typescript-make-usages-of-this-safe-in-class-methods)
###
[](https://basarat.gitbook.io/typescript/future-javascript/arrow-functions#tip-arrow-function-need)
Tip: Arrow Function Need
Beyond the terse syntax, you only _need_ to use the fat arrow if you are going to give the function to someone else to call. Effectively:
If you are going to call it yourself, i.e.
then `this` is going to be the correct calling context (in this example `person`).
###
[](https://basarat.gitbook.io/typescript/future-javascript/arrow-functions#tip-arrow-function-danger)
Tip: Arrow Function Danger
In fact if you want `this` _to be the calling context_ you should _not use the arrow function_. This is the case with callbacks used by libraries like jquery, underscore, mocha and others. If the documentation mentions functions on `this` then you should probably just use a `function` instead of a fat arrow. Similarly if you plan to use `arguments` don't use an arrow function.
###
[](https://basarat.gitbook.io/typescript/future-javascript/arrow-functions#tip-arrow-functions-with-libraries-that-use-this)
Tip: Arrow functions with libraries that use `this`
Many libraries do this e.g. `jQuery` iterables (one example [https://api.jquery.com/jquery.each/](https://api.jquery.com/jquery.each/)
) will use `this` to pass you the object that it is currently iterating over. In this case if you want to access the library passed `this` as well as the surrounding context just use a temp variable like `_self` like you would in the absence of arrow functions.
###
[](https://basarat.gitbook.io/typescript/future-javascript/arrow-functions#tip-arrow-functions-and-inheritance)
Tip: Arrow functions and inheritance
Arrow functions as properties on classes work fine with inheritance:
However, they do not work with the `super` keyword when you try to override the function in a child class. Properties go on `this`. Since there is only one `this` such functions cannot participate in a call to `super` (`super` only works on prototype members). You can easily get around it by creating a copy of the method before overriding it in the child.
[](https://basarat.gitbook.io/typescript/future-javascript/arrow-functions#tip-quick-object-return)
Tip: Quick object return
---------------------------------------------------------------------------------------------------------------------------------
Sometimes you need a function that just returns a simple object literal. However, something like
is parsed as a _block_ containing a _JavaScript Label_ by JavaScript runtimes (cause of the JavaScript specification).
> If that doesn't make sense, don't worry, as you get a nice compiler error from TypeScript saying "unused label" anyways. Labels are an old (and mostly unused) JavaScript feature that you can ignore as a modern GOTO (considered bad by experienced developers ๐น)
You can fix it by surrounding the object literal with `()`:
[PreviousClasses Emit](https://basarat.gitbook.io/typescript/future-javascript/classes/classes-emit)
[NextRest Parameters](https://basarat.gitbook.io/typescript/future-javascript/rest-parameters)
Last updated 5 years ago
* [Arrow Functions](https://basarat.gitbook.io/typescript/future-javascript/arrow-functions#arrow-functions)
* [Tip: Arrow Function Need](https://basarat.gitbook.io/typescript/future-javascript/arrow-functions#tip-arrow-function-need)
* [Tip: Arrow Function Danger](https://basarat.gitbook.io/typescript/future-javascript/arrow-functions#tip-arrow-function-danger)
* [Tip: Arrow functions with libraries that use this](https://basarat.gitbook.io/typescript/future-javascript/arrow-functions#tip-arrow-functions-with-libraries-that-use-this)
* [Tip: Arrow functions and inheritance](https://basarat.gitbook.io/typescript/future-javascript/arrow-functions#tip-arrow-functions-and-inheritance)
* [Tip: Quick object return](https://basarat.gitbook.io/typescript/future-javascript/arrow-functions#tip-quick-object-return)
Copy
function Person(age) {
this.age = age;
this.growOld = () => {
this.age++;
}
}
var person = new Person(1);
setTimeout(person.growOld,1000);
setTimeout(function() { console.log(person.age); },2000); // 2
Copy
function Person(age) {
this.age = age;
var _this = this; // capture this
this.growOld = function() {
_this.age++; // use the captured this
}
}
var person = new Person(1);
setTimeout(person.growOld,1000);
setTimeout(function() { console.log(person.age); },2000); // 2
Copy
class Person {
constructor(public age:number) {}
growOld = () => {
this.age++;
}
}
var person = new Person(1);
setTimeout(person.growOld,1000);
setTimeout(function() { console.log(person.age); },2000); // 2
Copy
var growOld = person.growOld;
// Then later someone else calls it:
growOld();
Copy
person.growOld();
Copy
let _self = this;
something.each(function() {
console.log(_self); // the lexically scoped value
console.log(this); // the library passed value
});
Copy
class Adder {
constructor(public a: number) {}
add = (b: number): number => {
return this.a + b;
}
}
class Child extends Adder {
callAdd(b: number) {
return this.add(b);
}
}
// Demo to show it works
const child = new Child(123);
console.log(child.callAdd(123)); // 246
Copy
class Adder {
constructor(public a: number) {}
// This function is now safe to pass around
add = (b: number): number => {
return this.a + b;
}
}
class ExtendedAdder extends Adder {
// Create a copy of parent before creating our own
private superAdd = this.add;
// Now create our override
add = (b: number): number => {
return this.superAdd(b);
}
}
Copy
// WRONG WAY TO DO IT
var foo = () => {
bar: 123
};
Copy
// Correct ๐น
var foo = () => ({
bar: 123
});
---
# let | TypeScript Deep Dive
`var` Variables in JavaScript are _function scoped_. This is different from many other languages (C# / Java etc.) where the variables are _block scoped_. If you bring a _block scoped_ mindset to JavaScript, you would expect the following to print `123`, instead it will print `456`:
Copy
var foo = 123;
if (true) {
var foo = 456;
}
console.log(foo); // 456
This is because `{` does not create a new _variable scope_. The variable `foo` is the same inside the if _block_ as it is outside the if block. This is a common source of errors in JavaScript programming. This is why TypeScript (and ES6) introduces the `let` keyword to allow you to define variables with true _block scope_. That is if you use `let` instead of `var` you get a true unique element disconnected from what you might have defined outside the scope. The same example is demonstrated with `let`:
Copy
let foo = 123;
if (true) {
let foo = 456;
}
console.log(foo); // 123
Another place where `let` would save you from errors is loops.
Copy
var index = 0;
var array = [1, 2, 3];
for (let index = 0; index < array.length; index++) {
console.log(array[index]);
}
console.log(index); // 0
In all sincerity we find it better to use `let` whenever possible as it leads to fewer surprises for new and existing multi-lingual developers.
[](https://basarat.gitbook.io/typescript/future-javascript/let#functions-create-a-new-scope)
Functions create a new scope
------------------------------------------------------------------------------------------------------------------------------
Since we mentioned it, we'd like to demonstrate that functions create a new variable scope in JavaScript. Consider the following:
This behaves as you would expect. Without this it would be very difficult to write code in JavaScript.
[](https://basarat.gitbook.io/typescript/future-javascript/let#generated-js)
Generated JS
----------------------------------------------------------------------------------------------
The JS generated by TypeScript is simple renaming of the `let` variable if a similar name already exists in the surrounding scope. E.g. the following is generated as is with a simple replacement of `let` with `var`:
However, if the variable name is already taken by the surrounding scope then a new variable name is generated as shown (notice `foo_1`):
[](https://basarat.gitbook.io/typescript/future-javascript/let#switch)
Switch
----------------------------------------------------------------------------------
You can wrap your `case` bodies in `{}` to reuse variable names reliably in different `case` statement as shown below:
[](https://basarat.gitbook.io/typescript/future-javascript/let#let-in-closures)
let in closures
----------------------------------------------------------------------------------------------------
A common programming interview question for a JavaScript developer is what is the log of this simple file:
One would have expected it to be `0,1,2`. Surprisingly it is going to be `3` for all three functions. Reason is that all three functions are using the variable `i` from the outer scope and at the time we execute them (in the second loop) the value of `i` will be `3` (that's the termination condition for the first loop).
A fix would be to create a new variable in each loop specific to that loop iteration. As we've learnt before we can create a new variable scope by creating a new function and immediately executing it (i.e. the IIFE pattern from classes `(function() { /* body */ })();`) as shown below:
Here the functions close over (hence called a `closure`) the _local_ variable (conveniently named `local`) and use that instead of the loop variable `i`.
> Note that closures come with a performance impact (they need to store the surrounding state).
The ES6 `let` keyword in a loop would have the same behavior as the previous example:
Using a `let` instead of `var` creates a variable `i` unique to each loop iteration.
[](https://basarat.gitbook.io/typescript/future-javascript/let#summary)
Summary
------------------------------------------------------------------------------------
`let` is extremely useful to have for the vast majority of code. It can greatly enhance your code readability and decrease the chance of a programming error.
[PreviousRest Parameters](https://basarat.gitbook.io/typescript/future-javascript/rest-parameters)
[Nextconst](https://basarat.gitbook.io/typescript/future-javascript/const)
Last updated 5 years ago
* [Functions create a new scope](https://basarat.gitbook.io/typescript/future-javascript/let#functions-create-a-new-scope)
* [Generated JS](https://basarat.gitbook.io/typescript/future-javascript/let#generated-js)
* [Switch](https://basarat.gitbook.io/typescript/future-javascript/let#switch)
* [let in closures](https://basarat.gitbook.io/typescript/future-javascript/let#let-in-closures)
* [Summary](https://basarat.gitbook.io/typescript/future-javascript/let#summary)
Copy
var foo = 123;
function test() {
var foo = 456;
}
test();
console.log(foo); // 123
Copy
if (true) {
let foo = 123;
}
// becomes //
if (true) {
var foo = 123;
}
Copy
var foo = '123';
if (true) {
let foo = 123;
}
// becomes //
var foo = '123';
if (true) {
var foo_1 = 123; // Renamed
}
Copy
switch (name) {
case 'x': {
let x = 5;
// ...
break;
}
case 'y': {
let x = 10;
// ...
break;
}
}
Copy
var funcs = [];
// create a bunch of functions
for (var i = 0; i < 3; i++) {
funcs.push(function() {
console.log(i);
})
}
// call them
for (var j = 0; j < 3; j++) {
funcs[j]();
}
Copy
var funcs = [];
// create a bunch of functions
for (var i = 0; i < 3; i++) {
(function() {
var local = i;
funcs.push(function() {
console.log(local);
})
})();
}
// call them
for (var j = 0; j < 3; j++) {
funcs[j]();
}
Copy
var funcs = [];
// create a bunch of functions
for (let i = 0; i < 3; i++) { // Note the use of let
funcs.push(function() {
console.log(i);
})
}
// call them
for (var j = 0; j < 3; j++) {
funcs[j]();
}
---
# Destructuring | TypeScript Deep Dive
TypeScript supports the following forms of Destructuring (literally named after de-structuring i.e. breaking up the structure):
1. Object Destructuring
2. Array Destructuring
It is easy to think of destructuring as an inverse of _structuring_. The method of _structuring_ in JavaScript is the object literal:
Copy
var foo = {
bar: {
bas: 123
}
};
Without the awesome _structuring_ support built into JavaScript, creating new objects on the fly would indeed be very cumbersome. Destructuring brings the same level of convenience to getting data out of a structure.
[](https://basarat.gitbook.io/typescript/future-javascript/destructuring#object-destructuring)
Object Destructuring
------------------------------------------------------------------------------------------------------------------------
Destructuring is useful because it allows you to do in a single line, what would otherwise require multiple lines. Consider the following case:
Copy
var rect = { x: 0, y: 10, width: 15, height: 20 };
// Destructuring assignment
var {x, y, width, height} = rect;
console.log(x, y, width, height); // 0,10,15,20
rect.x = 10;
({x, y, width, height} = rect); // assign to existing variables using outer parentheses
console.log(x, y, width, height); // 10,10,15,20
Here in the absence of destructuring you would have to pick off `x,y,width,height` one by one from `rect`.
To assign an extracted variable to a new variable name you can do the following:
Additionally you can get _deep_ data out of a structure using destructuring. This is shown in the following example:
[](https://basarat.gitbook.io/typescript/future-javascript/destructuring#object-destructuring-with-rest)
Object Destructuring with rest
--------------------------------------------------------------------------------------------------------------------------------------------
You can pick up any number of elements from an object and get _an object_ of the remaining elements using object destructuring with rest.
A common use case is also to ignore certain properties. For example:
[](https://basarat.gitbook.io/typescript/future-javascript/destructuring#array-destructuring)
Array Destructuring
----------------------------------------------------------------------------------------------------------------------
A common programming question: "How to swap two variables without using a third one?". The TypeScript solution:
Note that array destructuring is effectively the compiler doing the `[0], [1], ...` and so on for you. There is no guarantee that these values will exist.
[](https://basarat.gitbook.io/typescript/future-javascript/destructuring#array-destructuring-with-rest)
Array Destructuring with rest
------------------------------------------------------------------------------------------------------------------------------------------
You can pick up any number of elements from an array and get _an array_ of the remaining elements using array destructuring with rest.
[](https://basarat.gitbook.io/typescript/future-javascript/destructuring#array-destructuring-with-ignores)
Array Destructuring with ignores
------------------------------------------------------------------------------------------------------------------------------------------------
You can ignore any index by simply leaving its location empty i.e. `, ,` in the left hand side of the assignment. For example:
[](https://basarat.gitbook.io/typescript/future-javascript/destructuring#js-generation)
JS Generation
----------------------------------------------------------------------------------------------------------
The JavaScript generation for non ES6 targets simply involves creating temporary variables, just like you would have to do yourself without native language support for destructuring e.g.
[](https://basarat.gitbook.io/typescript/future-javascript/destructuring#summary)
Summary
----------------------------------------------------------------------------------------------
Destructuring can make your code more readable and maintainable by reducing the line count and making the intent clear. Array destructuring can allow you to use arrays as though they were tuples.
[Previousconst](https://basarat.gitbook.io/typescript/future-javascript/const)
[NextSpread Operator](https://basarat.gitbook.io/typescript/future-javascript/spread-operator)
Last updated 5 years ago
* [Object Destructuring](https://basarat.gitbook.io/typescript/future-javascript/destructuring#object-destructuring)
* [Object Destructuring with rest](https://basarat.gitbook.io/typescript/future-javascript/destructuring#object-destructuring-with-rest)
* [Array Destructuring](https://basarat.gitbook.io/typescript/future-javascript/destructuring#array-destructuring)
* [Array Destructuring with rest](https://basarat.gitbook.io/typescript/future-javascript/destructuring#array-destructuring-with-rest)
* [Array Destructuring with ignores](https://basarat.gitbook.io/typescript/future-javascript/destructuring#array-destructuring-with-ignores)
* [JS Generation](https://basarat.gitbook.io/typescript/future-javascript/destructuring#js-generation)
* [Summary](https://basarat.gitbook.io/typescript/future-javascript/destructuring#summary)
Copy
// structure
const obj = {"some property": "some value"};
// destructure
const {"some property": someProperty} = obj;
console.log(someProperty === "some value"); // true
Copy
var foo = { bar: { bas: 123 } };
var {bar: {bas}} = foo; // Effectively `var bas = foo.bar.bas;`
Copy
var {w, x, ...remaining} = {w: 1, x: 2, y: 3, z: 4};
console.log(w, x, remaining); // 1, 2, {y:3,z:4}
Copy
// Example function
function goto(point2D: {x: number, y: number}) {
// Imagine some code that might break
// if you pass in an object
// with more items than desired
}
// Some point you get from somewhere
const point3D = {x: 1, y: 2, z: 3};
/** A nifty use of rest to remove extra properties */
const { z, ...point2D } = point3D;
goto(point2D);
Copy
var x = 1, y = 2;
[x, y] = [y, x];
console.log(x, y); // 2,1
Copy
var [x, y, ...remaining] = [1, 2, 3, 4];
console.log(x, y, remaining); // 1, 2, [3,4]
Copy
var [x, , ...remaining] = [1, 2, 3, 4];
console.log(x, remaining); // 1, [3,4]
Copy
var x = 1, y = 2;
[x, y] = [y, x];
console.log(x, y); // 2,1
// becomes //
var x = 1, y = 2;
_a = [y,x], x = _a[0], y = _a[1];
console.log(x, y);
var _a;
---
# for...of | TypeScript Deep Dive
A common error experienced by beginning JavaScript developers is that `for...in` for an array does not iterate over the array items. Instead it iterates over the _keys_ of the object passed in. This is demonstrated in the below example. Here you would expect `9,2,5` but you get the indexes `0,1,2`:
Copy
var someArray = [9, 2, 5];
for (var item in someArray) {
console.log(item); // 0,1,2
}
This is one of the reasons why `for...of` exists in TypeScript (and ES6). The following iterates over the array correctly logging out the members as expected:
Copy
var someArray = [9, 2, 5];
for (var item of someArray) {
console.log(item); // 9,2,5
}
Similarly TypeScript has no trouble going through a string character by character using `for...of`:
Copy
var hello = "is it me you're looking for?";
for (var char of hello) {
console.log(char); // is it me you're looking for?
}
[](https://basarat.gitbook.io/typescript/future-javascript/for...of#js-generation)
JS Generation
-----------------------------------------------------------------------------------------------------
For pre ES6 targets TypeScript will generate the standard `for (var i = 0; i < list.length; i++)` kind of loop. For example here's what gets generated for our previous example:
Copy
var someArray = [9, 2, 5];
for (var item of someArray) {
console.log(item);
}
// becomes //
for (var _i = 0; _i < someArray.length; _i++) {
var item = someArray[_i];
console.log(item);
}
You can see that using `for...of` makes _intent_ clearer and also decreases the amount of code you have to write (and variable names you need to come up with).
[](https://basarat.gitbook.io/typescript/future-javascript/for...of#limitations)
Limitations
-------------------------------------------------------------------------------------------------
If you are not targeting ES6 or above, the generated code assumes the property `length` exists on the object and that the object can be indexed via numbers e.g. `obj[2]`. So it is only supported on `string` and `array` for these legacy JS engines.
If TypeScript can see that you are not using an array or a string it will give you a clear error _"is not an array type or a string type"_;
Use `for...of` only for stuff that _you know_ to be an array or a string. Note that this limitation might be removed in a future version of TypeScript.
[](https://basarat.gitbook.io/typescript/future-javascript/for...of#summary)
Summary
-----------------------------------------------------------------------------------------
You would be surprised at how many times you will be iterating over the elements of an array. The next time you find yourself doing that, give `for...of` a go. You might just make the next person who reviews your code happy.
[PreviousSpread Operator](https://basarat.gitbook.io/typescript/future-javascript/spread-operator)
[NextIterators](https://basarat.gitbook.io/typescript/future-javascript/iterators)
Last updated 5 years ago
* [JS Generation](https://basarat.gitbook.io/typescript/future-javascript/for...of#js-generation)
* [Limitations](https://basarat.gitbook.io/typescript/future-javascript/for...of#limitations)
* [Summary](https://basarat.gitbook.io/typescript/future-javascript/for...of#summary)
Copy
let articleParagraphs = document.querySelectorAll("article > p");
// Error: Nodelist is not an array type or a string type
for (let paragraph of articleParagraphs) {
paragraph.classList.add("read");
}
---
# Project | TypeScript Deep Dive
To create a successful project using TypeScript you need to understand the various project organization language features available. In this section we will cover "compilation context", declaration spaces and modules.
[PreviousAsync Await](https://basarat.gitbook.io/typescript/future-javascript/async-await)
[NextCompilation Context](https://basarat.gitbook.io/typescript/project/compilation-context)
Last updated 5 years ago
---
# Spread Operator | TypeScript Deep Dive
The main objective of the spread operator is to _spread_ the elements of an array or object. This is best explained with examples.
[](https://basarat.gitbook.io/typescript/future-javascript/spread-operator#apply)
Apply
--------------------------------------------------------------------------------------------
A common use case is to spread an array into the function arguments. Previously you would need to use `Function.prototype.apply`:
Copy
function foo(x, y, z) { }
var args = [0, 1, 2];
foo.apply(null, args);
Now you can do this simply by prefixing the arguments with `...` as shown below:
Copy
function foo(x, y, z) { }
var args = [0, 1, 2];
foo(...args);
Here we are _spreading_ the `args` array into positional `arguments`.
[](https://basarat.gitbook.io/typescript/future-javascript/spread-operator#destructuring)
Destructuring
------------------------------------------------------------------------------------------------------------
We've already seen one usage of this in _destructuring_:
Copy
var [x, y, ...remaining] = [1, 2, 3, 4];
console.log(x, y, remaining); // 1,2,[3,4]
The motivation here is to simply make it easy for you to capture the remaining elements of an array when destructuring.
[](https://basarat.gitbook.io/typescript/future-javascript/spread-operator#array-assignment)
Array Assignment
------------------------------------------------------------------------------------------------------------------
The spread operator allows you to easily place an _expanded version_ of an array into another array. This is demonstrated in the example below:
You can put the expanded array in at any position, and get the effect you'd expect:
[](https://basarat.gitbook.io/typescript/future-javascript/spread-operator#object-spread)
Object spread
------------------------------------------------------------------------------------------------------------
You can also spread an object into another object. A common use case is to simply add a property to an object without mutating the original:
For objects, the order of where you put the spread matters. This works something like `Object.assign`, and does what you'd expect: what comes first is 'overridden' by what comes later:
Another common use case is a simple shallow extend:
[](https://basarat.gitbook.io/typescript/future-javascript/spread-operator#summary)
Summary
------------------------------------------------------------------------------------------------
`apply` is something that you often use in JavaScript, so it's good to have a better syntax where you don't have that ugly `null` for the `this` argument. Also having a dedicated syntax for moving arrays out of (destructuring) or into (assignment) other arrays provides a neat syntax for when you are doing array processing on partial arrays.
[PreviousDestructuring](https://basarat.gitbook.io/typescript/future-javascript/destructuring)
[Nextfor...of](https://basarat.gitbook.io/typescript/future-javascript/for...of)
Last updated 5 years ago
* [Apply](https://basarat.gitbook.io/typescript/future-javascript/spread-operator#apply)
* [Destructuring](https://basarat.gitbook.io/typescript/future-javascript/spread-operator#destructuring)
* [Array Assignment](https://basarat.gitbook.io/typescript/future-javascript/spread-operator#array-assignment)
* [Object spread](https://basarat.gitbook.io/typescript/future-javascript/spread-operator#object-spread)
* [Summary](https://basarat.gitbook.io/typescript/future-javascript/spread-operator#summary)
Copy
var list = [1, 2];
list = [...list, 3, 4];
console.log(list); // [1,2,3,4]
Copy
var list = [1, 2];
list = [0, ...list, 4];
console.log(list); // [0,1,2,4]
Copy
const point2D = {x: 1, y: 2};
/** Create a new object by using all the point2D props along with z */
const point3D = {...point2D, z: 3};
Copy
const point2D = {x: 1, y: 2};
const anotherPoint3D = {x: 5, z: 4, ...point2D};
console.log(anotherPoint3D); // {x: 1, y: 2, z: 4}
const yetAnotherPoint3D = {...point2D, x: 5, z: 4}
console.log(yetAnotherPoint3D); // {x: 5, y: 2, z: 4}
Copy
const foo = {a: 1, b: 2, c: 0};
const bar = {c: 1, d: 2};
/** Merge foo and bar */
const fooBar = {...foo, ...bar};
// fooBar is now {a: 1, b: 2, c: 1, d: 2}
---
# Template Strings | TypeScript Deep Dive
Syntactically these are strings that use backticks ( i.e. \` ) instead of single (') or double (") quotes. The motivation of Template Literals is three fold:
* String Interpolation
* Multiline Strings
* Tagged Templates
[](https://basarat.gitbook.io/typescript/future-javascript/template-strings#string-interpolation)
String Interpolation
---------------------------------------------------------------------------------------------------------------------------
Another common use case is when you want to generate some string out of some static strings + some variables. For this you would need some _templating logic_ and this is where _template strings_ originally got their name from. They have since been officially renamed to _template literals_. Here's how you would potentially generate an html string previously:
Copy
var lyrics = 'Never gonna give you up';
var html = '
' + lyrics + '
';
Now with template literals you can just do:
Copy
var lyrics = 'Never gonna give you up';
var html = `
${lyrics}
`;
Note that any placeholder inside the interpolation (`${` and `}`) is treated as a JavaScript expression and evaluated as such e.g. you can do fancy math.
Copy
console.log(`1 and 1 make ${1 + 1}`);
[](https://basarat.gitbook.io/typescript/future-javascript/template-strings#multiline-literals)
Multiline Literals
-----------------------------------------------------------------------------------------------------------------------
Ever wanted to put a newline in a JavaScript string? Perhaps you wanted to embed some lyrics? You would have needed to _escape the literal newline_ using our favorite escape character `\`, and then put a new line into the string manually `\n` at the next line. This is shown below:
Copy
var lyrics = "Never gonna give you up \
\nNever gonna let you down";
With TypeScript you can just use a template string:
[](https://basarat.gitbook.io/typescript/future-javascript/template-strings#tagged-templates)
Tagged Templates
-------------------------------------------------------------------------------------------------------------------
You can place a function (called a `tag`) before the template string and it gets the opportunity to pre process the template string literals plus the values of all the placeholder expressions and return a result. A few notes:
* All the static literals are passed in as an array for the first argument.
* All the values of the placeholders expressions are passed in as the remaining arguments. Most commonly you would just use rest parameters to convert these into an array as well.
Here is an example where we have a tag function (named `htmlEscape`) that escapes the html from all the placeholders:
> Note: You can annotate `placeholders` to be any `[]`. Whatever you annotate it as, TypeScript will type check to make sure the placeholders used to call the tag match the annotation. For example if you expect to deal with `string` or `number`s you can annotate `...placeholders:(string | number)[]`
[](https://basarat.gitbook.io/typescript/future-javascript/template-strings#generated-js)
Generated JS
-----------------------------------------------------------------------------------------------------------
For pre ES6 compile targets the code is fairly simple. Multiline strings become escaped strings. String interpolation becomes _string concatenation_. Tagged Templates become function calls.
[](https://basarat.gitbook.io/typescript/future-javascript/template-strings#summary)
Summary
-------------------------------------------------------------------------------------------------
Multiline strings and string interpolation are just great things to have in any language. It's great that you can now use them in your JavaScript (thanks TypeScript!). Tagged templates allow you to create powerful string utilities.
[PreviousIterators](https://basarat.gitbook.io/typescript/future-javascript/iterators)
[NextPromise](https://basarat.gitbook.io/typescript/future-javascript/promise)
Last updated 5 years ago
* [String Interpolation](https://basarat.gitbook.io/typescript/future-javascript/template-strings#string-interpolation)
* [Multiline Literals](https://basarat.gitbook.io/typescript/future-javascript/template-strings#multiline-literals)
* [Tagged Templates](https://basarat.gitbook.io/typescript/future-javascript/template-strings#tagged-templates)
* [Generated JS](https://basarat.gitbook.io/typescript/future-javascript/template-strings#generated-js)
* [Summary](https://basarat.gitbook.io/typescript/future-javascript/template-strings#summary)
Copy
var lyrics = `Never gonna give you up
Never gonna let you down`;
Copy
var say = "a bird in hand > two in the bush";
var html = htmlEscape `
I would just like to say : ${say}
`;
// a sample tag function
function htmlEscape(literals: TemplateStringsArray, ...placeholders: string[]) {
let result = "";
// interleave the literals with the placeholders
for (let i = 0; i < placeholders.length; i++) {
result += literals[i];
result += placeholders[i]
.replace(/&/g, '&')
.replace(/"/g, '"')
.replace(/'/g, ''')
.replace(//g, '>');
}
// add the last literal
result += literals[literals.length - 1];
return result;
}
---
# Async Await | TypeScript Deep Dive
> [A PRO egghead video course that covers the same material](https://egghead.io/courses/async-await-using-typescript)
As a thought experiment imagine the following: a way to tell the JavaScript runtime to pause the executing of code on the `await` keyword when used on a promise and resume _only_ once (and if) the promise returned from the function is settled:
Copy
// Not actual code. A thought experiment
async function foo() {
try {
var val = await getMeAPromise();
console.log(val);
}
catch(err) {
console.log('Error: ', err.message);
}
}
When the promise settles execution continues,
* if it was fulfilled then await will return the value,
* if it's rejected an error will be thrown synchronously which we can catch.
This suddenly (and magically) makes asynchronous programming as easy as synchronous programming. Three things needed for this thought experiment are:
* Ability to _pause function_ execution.
* Ability to _put a value inside_ the function.
* Ability to _throw an exception inside_ the function.
This is exactly what generators allowed us to do! The thought experiment _is actually real_ and so is the `async`/`await` implementation in TypeScript / JavaScript. Under the covers it just uses generators.
[](https://basarat.gitbook.io/typescript/future-javascript/async-await#generated-javascript)
Generated JavaScript
----------------------------------------------------------------------------------------------------------------------
You don't have to understand this, but it's fairly simple if you've [read up on generators](https://basarat.gitbook.io/typescript/future-javascript/generators)
. The function `foo` can be simply wrapped up as follows:
where the `wrapToReturnPromise` just executes the generator function to get the `generator` and then use `generator.next()`, if the value is a `promise` it would `then`+`catch` the promise and depending upon the result call `generator.next(result)` or `generator.throw(error)`. That's it!
[](https://basarat.gitbook.io/typescript/future-javascript/async-await#async-await-support-in-typescript)
Async Await Support in TypeScript
------------------------------------------------------------------------------------------------------------------------------------------------
**Async - Await** has been supported by [TypeScript since version 1.7](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-1-7.html)
. Asynchronous functions are prefixed with the _async_ keyword; _await_ suspends the execution until an asynchronous function return promise is fulfilled and unwraps the value from the _Promise_ returned. It was only supported for **target es6** transpiling directly to **ES6 generators**.
**TypeScript 2.1** [added the capability to ES3 and ES5 run-times](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-1.html)
, meaning youโll be free to take advantage of it no matter what environment youโre using. It's important to notice that we can use async / await with TypeScript 2.1 and many browsers are supported, of course, having globally added a **polyfill for Promise**.
Let's see this **example** and take a look at this code to figure out how TypeScript async / await **notation** works:
**Transpiling to ES6 (--target es6)**
You can see full example [here](https://cdn.rawgit.com/basarat/typescript-book/705e4496/code/async-await/es6/asyncAwaitES6.js)
.
**Transpiling to ES5 (--target es5)**
You can see full example [here](https://cdn.rawgit.com/basarat/typescript-book/705e4496/code/async-await/es5/asyncAwaitES5.js)
.
**Note**: for both target scenarios, we need to make sure our run-time has an ECMAScript-compliant Promise available globally. That might involve grabbing a polyfill for Promise. We also need to make sure that TypeScript knows Promise exists by setting our lib flag to something like "dom", "es2015" or "dom", "es2015.promise", "es5". **We can see what browsers DO have Promise support (native and polyfilled)** [**here**](https://kangax.github.io/compat-table/es6/#test-Promise)
**.**
[PreviousGenerators](https://basarat.gitbook.io/typescript/future-javascript/generators)
[NextProject](https://basarat.gitbook.io/typescript/project)
Last updated 5 years ago
* [Generated JavaScript](https://basarat.gitbook.io/typescript/future-javascript/async-await#generated-javascript)
* [Async Await Support in TypeScript](https://basarat.gitbook.io/typescript/future-javascript/async-await#async-await-support-in-typescript)
Copy
const foo = wrapToReturnPromise(function* () {
try {
var val = yield getMeAPromise();
console.log(val);
}
catch(err) {
console.log('Error: ', err.message);
}
});
Copy
function delay(milliseconds: number, count: number): Promise {
return new Promise(resolve => {
setTimeout(() => {
resolve(count);
}, milliseconds);
});
}
// async function always returns a Promise
async function dramaticWelcome(): Promise {
console.log("Hello");
for (let i = 0; i < 5; i++) {
// await is converting Promise into number
const count: number = await delay(500, i);
console.log(count);
}
console.log("World!");
}
dramaticWelcome();
Copy
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
function delay(milliseconds, count) {
return new Promise(resolve => {
setTimeout(() => {
resolve(count);
}, milliseconds);
});
}
// async function always returns a Promise
function dramaticWelcome() {
return __awaiter(this, void 0, void 0, function* () {
console.log("Hello");
for (let i = 0; i < 5; i++) {
// await is converting Promise into number
const count = yield delay(500, i);
console.log(count);
}
console.log("World!");
});
}
dramaticWelcome();
Copy
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [0, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
function delay(milliseconds, count) {
return new Promise(function (resolve) {
setTimeout(function () {
resolve(count);
}, milliseconds);
});
}
// async function always returns a Promise
function dramaticWelcome() {
return __awaiter(this, void 0, void 0, function () {
var i, count;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
console.log("Hello");
i = 0;
_a.label = 1;
case 1:
if (!(i < 5)) return [3 /*break*/, 4];
return [4 /*yield*/, delay(500, i)];
case 2:
count = _a.sent();
console.log(count);
_a.label = 3;
case 3:
i++;
return [3 /*break*/, 1];
case 4:
console.log("World!");
return [2 /*return*/];
}
});
});
}
dramaticWelcome();
---
# Node.js QuickStart | TypeScript Deep Dive
TypeScript has had _first class_ support for Node.js since inception. Here's how to setup a quick Node.js project:
> Note: many of these steps are actually just common practice Node.js setup steps
1. Setup a Node.js project `package.json`. Quick one : `npm init -y`
2. Add TypeScript (`npm install typescript --save-dev`)
3. Add `node.d.ts` (`npm install @types/node --save-dev`)
4. Init a `tsconfig.json` for TypeScript options with a few key options in your tsconfig.json (`npx tsc --init --rootDir src --outDir lib --esModuleInterop --resolveJsonModule --lib es6,dom --module commonjs`)
That's it! Fire up your IDE (e.g. `code .`) and play around. Now you can use all the built in node modules (e.g. `import * as fs from 'fs';`) with all the safety and developer ergonomics of TypeScript!
All your TypeScript code goes in `src` and the generated JavaScript goes in `lib`.
[](https://basarat.gitbook.io/typescript/nodejs#bonus-live-compile--run)
Bonus: Live compile + run
-------------------------------------------------------------------------------------------------------
* Add `ts-node` which we will use for live compile + run in node (`npm install ts-node --save-dev`)
* Add `nodemon` which will invoke `ts-node` whenever a file is changed (`npm install nodemon --save-dev`)
Now just add a `script` target to your `package.json` based on your application entry e.g. assuming its `index.ts`:
Copy
"scripts": {
"start": "npm run build:live",
"build": "tsc -p .",
"build:live": "nodemon --watch 'src/**/*.ts' --exec \"ts-node\" src/index.ts"
},
So you can now run `npm start` and as you edit `index.ts`:
* nodemon reruns its command (ts-node)
* ts-node transpiles automatically picking up tsconfig.json and the installed TypeScript version,
* ts-node runs the output JavaScript through Node.js.
And when you are ready to deploy your JavaScript application run `npm run build`.
[](https://basarat.gitbook.io/typescript/nodejs#bonus-points)
Bonus points
-------------------------------------------------------------------------------
Such NPM modules work just fine with browserify (using tsify) or webpack (using ts-loader).
[PreviousDynamic Import Expressions](https://basarat.gitbook.io/typescript/project/dynamic-import-expressions)
[NextBrowser QuickStart](https://basarat.gitbook.io/typescript/browser)
Last updated 5 years ago
* [Bonus: Live compile + run](https://basarat.gitbook.io/typescript/nodejs#bonus-live-compile--run)
* [Bonus points](https://basarat.gitbook.io/typescript/nodejs#bonus-points)
---
# Which Files? | TypeScript Deep Dive
Use `include` and `exclude` to specify files / folders / globs. E.g.:
Copy
{
"include":[\
"./folder"\
],
"exclude":[\
"./folder/**/*.spec.ts",\
"./folder/someSubFolder"\
]
}
[](https://basarat.gitbook.io/typescript/project/compilation-context/files#globs)
Globs
--------------------------------------------------------------------------------------------
* For globs : `**/*` (e.g. sample usage `somefolder/**/*`) means all folder and any files (the extensions `.ts`/`.tsx` will be assumed and if `allowJs:true` so will `.js`/`.jsx`)
[](https://basarat.gitbook.io/typescript/project/compilation-context/files#files-option)
`files` option
------------------------------------------------------------------------------------------------------------
Alternatively, you can use `files` to be explicit:
Copy
{
"files":[\
"./some/file.ts"\
]
}
But it is not recommended as you have to keep updating it. Instead use `include` to just add the containing folder.
[Previoustsconfig.json](https://basarat.gitbook.io/typescript/project/compilation-context/tsconfig)
[NextDeclaration Spaces](https://basarat.gitbook.io/typescript/project/declarationspaces)
Last updated 5 years ago
* [Globs](https://basarat.gitbook.io/typescript/project/compilation-context/files#globs)
* [files option](https://basarat.gitbook.io/typescript/project/compilation-context/files#files-option)
---
# Iterators | TypeScript Deep Dive
Iterator itself is not a TypeScript or ES6 feature, Iterator is a Behavioral Design Pattern common for Object oriented programming languages. It is, generally, an object which implements the following interface:
Copy
interface Iterator {
next(value?: any): IteratorResult;
return?(value?: any): IteratorResult;
throw?(e?: any): IteratorResult;
}
([More on that `` notation later](https://basarat.gitbook.io/typescript/type-system/generics)
) This interface allows to retrieve a value from some collection or sequence which belongs to the object.
The `IteratorResult` is simply a `value`+`done` pair:
Copy
interface IteratorResult {
done: boolean;
value: T;
}
Imagine that there's an object of some frame, which includes the list of components of which this frame consists. With Iterator interface it is possible to retrieve components from this frame object like below:
Copy
class Component {
constructor (public name: string) {}
}
class Frame implements Iterator {
private pointer = 0;
constructor(public name: string, public components: Component[]) {}
public next(): IteratorResult {
if (this.pointer < this.components.length) {
return {
done: false,
value: this.components[this.pointer++]
}
} else {
return {
done: true,
value: null
}
}
}
}
let frame = new Frame("Door", [new Component("top"), new Component("bottom"), new Component("left"), new Component("right")]);
let iteratorResult1 = frame.next(); //{ done: false, value: Component { name: 'top' } }
let iteratorResult2 = frame.next(); //{ done: false, value: Component { name: 'bottom' } }
let iteratorResult3 = frame.next(); //{ done: false, value: Component { name: 'left' } }
let iteratorResult4 = frame.next(); //{ done: false, value: Component { name: 'right' } }
let iteratorResult5 = frame.next(); //{ done: true, value: null }
//It is possible to access the value of iterator result via the value property:
let component = iteratorResult1.value; //Component { name: 'top' }
Again. Iterator itself is not a TypeScript feature, this code could work without implementing Iterator and IteratorResult interfaces explicitly. However, it is very helpful to use these common ES6 [interfaces](https://basarat.gitbook.io/typescript/type-system/interfaces)
for code consistency.
Ok, Nice, but could be more helpful. ES6 defines the _iterable protocol_ which includes the \[Symbol.iterator\] `symbol` if the Iterable interface is implemented:
Unfortunately `frame.next()` won't work with this pattern and it also looks a bit clunky. IterableIterator interface to the rescue!
Both `frame.next()` and `for` cycle now work fine with IterableIterator interface.
Iterator does not have to iterate a finite value. The typical example is a Fibonacci sequence:
[](https://basarat.gitbook.io/typescript/future-javascript/iterators#building-code-with-iterators-for-es5-target)
Building code with iterators for ES5 target
------------------------------------------------------------------------------------------------------------------------------------------------------------------
Code examples above require ES6 target. However, it could work with ES5 target as well if target JS engine supports `Symbol.iterator`. This can be achieved by using ES6 lib with ES5 target (add es6.d.ts to your project) to make it compile. Compiled code should work in node 4+, Google Chrome and in some other browsers.
[Previousfor...of](https://basarat.gitbook.io/typescript/future-javascript/for...of)
[NextTemplate Strings](https://basarat.gitbook.io/typescript/future-javascript/template-strings)
Last updated 5 years ago
Copy
//...
class Frame implements Iterable {
constructor(public name: string, public components: Component[]) {}
[Symbol.iterator]() {
let pointer = 0;
let components = this.components;
return {
next(): IteratorResult {
if (pointer < components.length) {
return {
done: false,
value: components[pointer++]
}
} else {
return {
done: true,
value: null
}
}
}
}
}
}
let frame = new Frame("Door", [new Component("top"), new Component("bottom"), new Component("left"), new Component("right")]);
for (let cmp of frame) {
console.log(cmp);
}
Copy
//...
class Frame implements IterableIterator {
private pointer = 0;
constructor(public name: string, public components: Component[]) {}
public next(): IteratorResult {
if (this.pointer < this.components.length) {
return {
done: false,
value: this.components[this.pointer++]
}
} else {
return {
done: true,
value: null
}
}
}
[Symbol.iterator](): IterableIterator {
return this;
}
}
//...
Copy
class Fib implements IterableIterator {
protected fn1 = 0;
protected fn2 = 1;
constructor(protected maxValue?: number) {}
public next(): IteratorResult {
var current = this.fn1;
this.fn1 = this.fn2;
this.fn2 = current + this.fn1;
if (this.maxValue != null && current >= this.maxValue) {
return {
done: true,
value: null
}
}
return {
done: false,
value: current
}
}
[Symbol.iterator](): IterableIterator {
return this;
}
}
let fib = new Fib();
fib.next() //{ done: false, value: 0 }
fib.next() //{ done: false, value: 1 }
fib.next() //{ done: false, value: 1 }
fib.next() //{ done: false, value: 2 }
fib.next() //{ done: false, value: 3 }
fib.next() //{ done: false, value: 5 }
let fibMax50 = new Fib(50);
console.log(Array.from(fibMax50)); // [ 0, 1, 1, 2, 3, 5, 8, 13, 21, 34 ]
let fibMax21 = new Fib(21);
for(let num of fibMax21) {
console.log(num); //Prints fibonacci sequence 0 to 21
}
---
# Library QuickStart | TypeScript Deep Dive
* [A lesson on creating TypeScript node modules](https://egghead.io/lessons/typescript-create-high-quality-npm-packages-using-typescript)
Using modules written in TypeScript is super fun as you get great compile time safety and autocomplete (essentially executable documentation).
TypeScript modules can be consumed both in the nodejs (as is) browser (with something like webpack).
Creating a high quality TypeScript module is simple. Assume the following desired folder structure for your package:
Copy
package
โโ package.json
โโ tsconfig.json
โโ src
โ โโ index.ts
โ โโ foo.ts
โ โโ ...All your source files (Authored)
โโ lib
โโ index.d.ts.map
โโ index.d.ts
โโ index.js
โโ foo.d.ts.map
โโ foo.d.ts
โโ foo.js
โโ ... All your compiled files (Generated)
* `src/index.ts`: Here you would export anything you expect to be consumed from your project. E.g `export { Foo } from './foo';`. Exporting from this file makes it available for consumption when someone does `import { /* Here */ } from 'example';`
* In your `tsconfig.json`
* have `compilerOptions`: `"outDir": "lib"` + `"declaration": true` + `"declarationMap" : true` < This generates `.js` (JavaScript) `.d.ts` (declarations for TypeSafety) and `.d.ts.map` (enables `declaration .d.ts` => `source .ts` IDE navigation) in the lib folder.
* have `include: ["src"]` < This includes all the files from the `src` dir.
* In your `package.json` have
* `"main": "lib/index"` < This tells to load `lib/index.js` for runtime code.
* `"types": "lib/index"` < This tells TypeScript to load `lib/index.d.ts` for type checking.
Example package:
* `npm install typestyle` [for TypeStyle](https://www.npmjs.com/package/typestyle)
* Usage: `import { style } from 'typestyle';` will be completely type safe.
[](https://basarat.gitbook.io/typescript/library#managing-dependencies)
Managing Dependencies
--------------------------------------------------------------------------------------------------
###
[](https://basarat.gitbook.io/typescript/library#devdependencies)
devDependencies
* If your package depends on another package while you are developing it (e.g. `prettier`) you should install them as a `devDependency`. This way they will not pollute the `node_modules` of your module's consumers (as `npm i foo` does not install `devDependencies` of `foo`).
* `typescript` is normally a `devDependency` as you only use it to build your package. The consumers can use your package with or without TypeScript.
* If your package depends on other JavaScript authored packages and you want to use it with type safety in your project, put their types (e.g. `@types/foo`) in `devDependencies`. JavaScript types should be managed _out of bound_ from the main NPM streams. The JavaScript ecosystem breaks types without semantic versioning too commonly, so if your users need types for these they should install the `@types/foo` version that works for them. If you want to guide users to install these types you can put them in `peerDependencies` mentioned next.
###
[](https://basarat.gitbook.io/typescript/library#peerdependencies)
peerDependencies
If your package depends on a package that it heavily _works with_ (as opposed to _works using_) e.g. `react`, put them in `peerDependencies` just like you would with raw JS packages. To test them locally you should also put them in `devDependencies`.
Now:
* When you are developing the package you will get the version of the dependency you specified in your `devDependencies`.
* When someone installs your package they will _not_ get this dependency (as `npm i foo` does not install `devDependencies` of `foo`) but they will get a warning that they should install the missing `peerDependencies` of your package.
###
[](https://basarat.gitbook.io/typescript/library#dependencies)
dependencies
If your package _wraps_ another package (meant for internal use even after compilation) you should put them in `dependencies`. Now when someone installs your package they will get your package + any of its dependencies.
[PreviousBrowser QuickStart](https://basarat.gitbook.io/typescript/browser)
[NextTypeScript's Type System](https://basarat.gitbook.io/typescript/type-system)
Last updated 5 years ago
* [Managing Dependencies](https://basarat.gitbook.io/typescript/library#managing-dependencies)
* [devDependencies](https://basarat.gitbook.io/typescript/library#devdependencies)
* [peerDependencies](https://basarat.gitbook.io/typescript/library#peerdependencies)
* [dependencies](https://basarat.gitbook.io/typescript/library#dependencies)
---
# Modules | TypeScript Deep Dive
[](https://basarat.gitbook.io/typescript/project/modules#global-module)
Global Module
------------------------------------------------------------------------------------------
By default when you start typing code in a new TypeScript file your code is in a _global_ namespace. As a demo consider a file `foo.ts`:
Copy
var foo = 123;
If you now create a _new_ file `bar.ts` in the same project, you will be _allowed_ by the TypeScript type system to use the variable `foo` as if it was available globally:
Copy
var bar = foo; // allowed
Needless to say having a global namespace is dangerous as it opens your code up for naming conflicts. We recommend using file modules which are presented next.
[](https://basarat.gitbook.io/typescript/project/modules#file-module)
File Module
--------------------------------------------------------------------------------------
Also called _external modules_. If you have an `import` or an `export` at the root level of a TypeScript file then it creates a _local_ scope within that file. So if we were to change the previous `foo.ts` to the following (note the `export` usage):
Copy
export var foo = 123;
We will no longer have `foo` in the global namespace. This can be demonstrated by creating a new file `bar.ts` as follows:
Copy
var bar = foo; // ERROR: "cannot find name 'foo'"
If you want to use stuff from `foo.ts` in `bar.ts` _you need to explicitly import it_. This is shown in an updated `bar.ts` below:
Copy
import { foo } from "./foo";
var bar = foo; // allowed
Using an `import` in `bar.ts` not only allows you to bring in stuff from other files, but also marks the file `bar.ts` as a _module_ and therefore, declarations in `bar.ts` don't pollute the global namespace either.
What JavaScript is generated from a given TypeScript file that uses external modules is driven by the compiler flag called `module`.
[PreviousDeclaration Spaces](https://basarat.gitbook.io/typescript/project/declarationspaces)
[NextFile Module Details](https://basarat.gitbook.io/typescript/project/modules/external-modules)
Last updated 5 years ago
* [Global Module](https://basarat.gitbook.io/typescript/project/modules#global-module)
* [File Module](https://basarat.gitbook.io/typescript/project/modules#file-module)
---
# tsconfig.json | TypeScript Deep Dive
[](https://basarat.gitbook.io/typescript/project/compilation-context/tsconfig#basic)
Basic
-----------------------------------------------------------------------------------------------
It is extremely easy to get started with tsconfig.json as the basic file you need is:
Copy
{}
i.e. an empty JSON file at the _root_ of your project. This way TypeScript will include _all_ the `.ts` files in this directory (and sub directories) as a part of the compilation context. It will also select a few sane default compiler options.
[](https://basarat.gitbook.io/typescript/project/compilation-context/tsconfig#compileroptions)
compilerOptions
-------------------------------------------------------------------------------------------------------------------
You can customize the compiler options using `compilerOptions`:
Copy
{
"compilerOptions": {
/* Basic Options */
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'. */
"module": "commonjs", /* Specify module code generation: 'commonjs', 'amd', 'system', 'umd' or 'es2015'. */
"lib": [], /* Specify library files to be included in the compilation: */
"allowJs": true, /* Allow JavaScript files to be compiled. */
"checkJs": true, /* Report errors in .js files. */
"jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
"declaration": true, /* Generates corresponding '.d.ts' file. */
"sourceMap": true, /* Generates corresponding '.map' file. */
"outFile": "./", /* Concatenate and emit output to single file. */
"outDir": "./", /* Redirect output structure to the directory. */
"rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
"removeComments": true, /* Do not emit comments to output. */
"noEmit": true, /* Do not emit outputs. */
"importHelpers": true, /* Import emit helpers from 'tslib'. */
"downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
"isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
/* Strict Type-Checking Options */
"strict": true, /* Enable all strict type-checking options. */
"noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
"strictNullChecks": true, /* Enable strict null checks. */
"noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
"alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
/* Additional Checks */
"noUnusedLocals": true, /* Report errors on unused locals. */
"noUnusedParameters": true, /* Report errors on unused parameters. */
"noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
"noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
/* Module Resolution Options */
"moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
"baseUrl": "./", /* Base directory to resolve non-absolute module names. */
"paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
"rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
"typeRoots": [], /* List of folders to include type definitions from. */
"types": [], /* Type declaration files to be included in compilation. */
"allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
/* Source Map Options */
"sourceRoot": "./", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
"mapRoot": "./", /* Specify the location where debugger should locate map files instead of generated locations. */
"inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
"inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
/* Experimental Options */
"experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
"emitDecoratorMetadata": true /* Enables experimental support for emitting type metadata for decorators. */
}
}
These (and more) compiler options will be discussed later.
[](https://basarat.gitbook.io/typescript/project/compilation-context/tsconfig#typescript-compiler)
TypeScript compiler
---------------------------------------------------------------------------------------------------------------------------
Good IDEs come with built in support for on the fly `ts` to `js` compilation. However, if you want to run the TypeScript compiler manually from the command line when using `tsconfig.json`, you can do it in a few ways:
* Just run `tsc` and it will look for `tsconfig.json` in the current as well as all parent folders till it finds it.
* Run `tsc -p ./path-to-project-directory`. Of course the path can be absolute or relative to the current directory.
You can even start the TypeScript compiler in _watch_ mode using `tsc -w` and it will watch your TypeScript project files for changes.
[PreviousCompilation Context](https://basarat.gitbook.io/typescript/project/compilation-context)
[NextWhich Files?](https://basarat.gitbook.io/typescript/project/compilation-context/files)
Last updated 5 years ago
* [Basic](https://basarat.gitbook.io/typescript/project/compilation-context/tsconfig#basic)
* [compilerOptions](https://basarat.gitbook.io/typescript/project/compilation-context/tsconfig#compileroptions)
* [TypeScript compiler](https://basarat.gitbook.io/typescript/project/compilation-context/tsconfig#typescript-compiler)
---
# Browser QuickStart | TypeScript Deep Dive
[](https://basarat.gitbook.io/typescript/browser#typescript-in-the-browser)
TypeScript in the browser
----------------------------------------------------------------------------------------------------------
[](https://designtsx.com/)
If you are using TypeScript to create a web application here are my recommendations to get a quick TypeScript + React (my UI framework of choice) project setup.
###
[](https://basarat.gitbook.io/typescript/browser#general-machine-setup)
General Machine Setup
* Install [Node.js](https://nodejs.org/en/download/)
* Install [Git](https://git-scm.com/downloads)
###
[](https://basarat.gitbook.io/typescript/browser#project-setup-quick)
Project Setup Quick
Use [https://github.com/basarat/react-typescript](https://github.com/basarat/react-typescript)
as a base.
Copy
git clone https://github.com/basarat/react-typescript.git
cd react-typescript
npm install
Now use it as a base and jump to [develop your amazing application](https://basarat.gitbook.io/typescript/browser#develop-your-amazing-application)
###
[](https://basarat.gitbook.io/typescript/browser#project-setup-detailed)
Project Setup Detailed
If you want to learn more about the details of how that project is created (instead of using it as a base), here are the steps on how its setup from scratch:
* Create a project dir:
* Create `tsconfig.json`:
* Create `package.json`.
* Create a `webpack.config.js` to bundle your modules into a single `app.js` file that contains all your resources:
* `src/templates/index.html` file. It will be used as the template for the `index.html` generated by webpack. The generated file will be in the `public` folder and and then served from your webserver:
* `src/app/app.tsx` that is your frontend application entry point:
[](https://basarat.gitbook.io/typescript/browser#develop-your-amazing-application)
Develop your amazing application
------------------------------------------------------------------------------------------------------------------------
> You can get the latest packages using `npm install typescript@latest react@latest react-dom@latest @types/react@latest @types/react-dom@latest webpack@latest webpack-dev-server@latest webpack-cli@latest ts-loader@latest clean-webpack-plugin@latest html-webpack-plugin@latest --save-exact`
* Do live development by running `npm start`.
* Visit [http://localhost:8080](http://localhost:8080/)
* Edit the `src/app/app.tsx` (or any ts/tsx file used in some way by `src/app/app.tsx`) and application live reloads.
* Edit the `src/templates/index.html` and the server live reloads.
* Build production assets by running `npm run build`.
* Serve the `public` folder (which contains the built assets) from your server.
[PreviousNode.js QuickStart](https://basarat.gitbook.io/typescript/nodejs)
[NextLibrary QuickStart](https://basarat.gitbook.io/typescript/library)
Last updated 5 years ago
* [TypeScript in the browser](https://basarat.gitbook.io/typescript/browser#typescript-in-the-browser)
* [General Machine Setup](https://basarat.gitbook.io/typescript/browser#general-machine-setup)
* [Project Setup Quick](https://basarat.gitbook.io/typescript/browser#project-setup-quick)
* [Project Setup Detailed](https://basarat.gitbook.io/typescript/browser#project-setup-detailed)
* [Develop your amazing application](https://basarat.gitbook.io/typescript/browser#develop-your-amazing-application)
Copy
mkdir your-project
cd your-project
Copy
{
"compilerOptions": {
"sourceMap": true,
"module": "commonjs",
"esModuleInterop": true,
"resolveJsonModule": true,
"experimentalDecorators": true,
"target": "es5",
"jsx": "react",
"lib": [\
"dom",\
"es6"\
]
},
"include": [\
"src"\
],
"compileOnSave": false
}
Copy
{
"name": "react-typescript",
"version": "0.0.0",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/basarat/react-typescript.git"
},
"scripts": {
"build": "webpack -p",
"start": "webpack-dev-server -d --content-base ./public"
},
"dependencies": {
"@types/react": "16.4.10",
"@types/react-dom": "16.0.7",
"clean-webpack-plugin": "0.1.19",
"html-webpack-plugin": "3.2.0",
"react": "16.4.2",
"react-dom": "16.4.2",
"ts-loader": "4.4.2",
"typescript": "3.0.1",
"webpack": "4.16.5",
"webpack-cli": "3.1.0",
"webpack-dev-server": "3.1.5"
}
}
Copy
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/app/app.tsx',
plugins: [\
new CleanWebpackPlugin({\
cleanAfterEveryBuildPatterns: ['public/build']\
}),\
new HtmlWebpackPlugin({\
template: 'src/templates/index.html'\
}),\
],
output: {
path: __dirname + '/public',
filename: 'build/[name].[contenthash].js'
},
resolve: {
extensions: ['.ts', '.tsx', '.js']
},
module: {
rules: [\
{ test: /\.tsx?$/, loader: 'ts-loader' }\
]
}
}
Copy
Copy
import * as React from 'react';
import * as ReactDOM from 'react-dom';
const Hello: React.FunctionComponent<{ compiler: string, framework: string }> = (props) => {
return (
{props.compiler}
{props.framework}
);
}
ReactDOM.render(
,
document.getElementById("root")
);
---
# Dynamic Import Expressions | TypeScript Deep Dive
**Dynamic import expressions** are a new feature and part of **ECMAScript** that allows users to asynchronously request a module at any arbitrary point in your program. **TC39** JavaScript committee has itโs own proposal which is in stage 3, and itโs called [import() proposal for JavaScript](https://github.com/tc39/proposal-dynamic-import)
.
Alternatively, **webpack** bundler has a feature called [**Code Splitting**](https://webpack.js.org/guides/code-splitting/)
which allows you to split your bundle into chunks which can be downloaded asynchronously at a later time. For instance, this allows to serve a minimal bootstrap bundle first and to asynchronously load additional features later.
Itโs natural to think (if we are using webpack in our dev workflow) that [TypeScript 2.4 dynamic import expressions](https://github.com/Microsoft/TypeScript/wiki/What%27s-new-in-TypeScript#dynamic-import-expressions)
will **automatically produce** bundle chunks and automatically code-split your JS final bundle. BUT, that is not as easy as it seems, because it depends on the **tsconfig.json configuration** we are working with.
The thing is that webpack code splitting supports two similar techniques to achieve this goal: using **import()** (preferred, ECMAScript proposal) and **require.ensure()** (legacy, webpack specific). And what that means is the expected TypeScript output is **leave the import() statement as it is** instead of transpile it to anything else.
Letโs see an example to figure out how to configure webpack + TypeScript 2.4.
In the following code I want to **lazy load the library** _**moment**_ but I am interested in code splitting as well, which means, having the moment library in a separate chunk of JS (JavaScript file) that will be loaded only when required.
Copy
import(/* webpackChunkName: "momentjs" */ "moment")
.then((moment) => {
// lazyModule has all of the proper types, autocomplete works,
// type checking works, code references work \o/
const time = moment().format();
console.log("TypeScript >= 2.4.0 Dynamic Import Expression:");
console.log(time);
})
.catch((err) => {
console.log("Failed to load moment", err);
});
Here is the tsconfig.json:
Copy
{
"compilerOptions": {
"target": "es5",
"module": "esnext",
"lib": [\
"dom",\
"es5",\
"scripthost",\
"es2015.promise"\
],
"jsx": "react",
"declaration": false,
"sourceMap": true,
"outDir": "./dist/js",
"strict": true,
"moduleResolution": "node",
"typeRoots": [\
"./node_modules/@types"\
],
"types": [\
"node",\
"react",\
"react-dom"\
]
}
}
**Important notes**:
* Using **"module": "esnext"** TypeScript produces the mimic import() statement to be input for Webpack Code Splitting.
* For further information read this article: [Dynamic Import Expressions and webpack 2 Code Splitting integration with TypeScript 2.4](https://blog.josequinto.com/2017/06/29/dynamic-import-expressions-and-webpack-code-splitting-integration-with-typescript-2-4/)
.
You can see full example [here](https://cdn.rawgit.com/basarat/typescript-book/705e4496/code/dynamic-import-expressions/dynamicImportExpression.js)
.
[PreviousNamespaces](https://basarat.gitbook.io/typescript/project/namespaces)
[NextNode.js QuickStart](https://basarat.gitbook.io/typescript/nodejs)
Last updated 5 years ago
---
# Promise | TypeScript Deep Dive
[](https://basarat.gitbook.io/typescript/future-javascript/promise#promise)
Promise
----------------------------------------------------------------------------------------
The `Promise` class is something that exists in many modern JavaScript engines and can be easily [polyfilled](https://github.com/stefanpenner/es6-promise)
. The main motivation for promises is to bring synchronous style error handling to Async / Callback style code.
###
[](https://basarat.gitbook.io/typescript/future-javascript/promise#callback-style-code)
Callback style code
In order to fully appreciate promises let's present a simple sample that proves the difficulty of creating reliable Async code with just callbacks. Consider the simple case of authoring an async version of loading JSON from a file. A synchronous version of this can be quite simple:
Copy
import fs = require('fs');
function loadJSONSync(filename: string) {
return JSON.parse(fs.readFileSync(filename));
}
// good json file
console.log(loadJSONSync('good.json'));
// non-existent file, so fs.readFileSync fails
try {
console.log(loadJSONSync('absent.json'));
}
catch (err) {
console.log('absent.json error', err.message);
}
// invalid json file i.e. the file exists but contains invalid JSON so JSON.parse fails
try {
console.log(loadJSONSync('invalid.json'));
}
catch (err) {
console.log('invalid.json error', err.message);
}
There are three behaviors of this simple `loadJSONSync` function, a valid return value, a file system error or a JSON.parse error. We handle the errors with a simple try/catch as you are used to when doing synchronous programming in other languages. Now let's make a good async version of such a function. A decent initial attempt with trivial error checking logic would be as follows:
Simple enough, it takes a callback, passes any file system errors to the callback. If no file system errors, it returns the `JSON.parse` result. A few points to keep in mind when working with async functions based on callbacks are:
1. Never call the callback twice.
2. Never throw an error.
However, this simple function fails to accommodate for point two. In fact, `JSON.parse` throws an error if it is passed bad JSON and the callback never gets called and the application crashes. This is demonstrated in the below example:
A naive attempt at fixing this would be to wrap the `JSON.parse` in a try catch as shown in the below example:
However, there is a subtle bug in this code. If the callback (`cb`), and not `JSON.parse`, throws an error, since we wrapped it in a `try`/`catch`, the `catch` executes and we call the callback again i.e. the callback gets called twice! This is demonstrated in the example below:
This is because our `loadJSON` function wrongfully wrapped the callback in a `try` block. There is a simple lesson to remember here.
> Simple lesson: Contain all your sync code in a try catch, except when you call the callback.
Following this simple lesson, we have a fully functional async version of `loadJSON` as shown below:
Admittedly this is not hard to follow once you've done it a few times but nonetheless itโs a lot of boiler plate code to write simply for good error handling. Now let's look at a better way to tackle asynchronous JavaScript using promises.
[](https://basarat.gitbook.io/typescript/future-javascript/promise#creating-a-promise)
Creating a Promise
--------------------------------------------------------------------------------------------------------------
A promise can be either `pending` or `fulfilled` or `rejected`.

promise states and fates
Let's look at creating a promise. It's a simple matter of calling `new` on `Promise` (the promise constructor). The promise constructor is passed `resolve` and `reject` functions for settling the promise state:
###
[](https://basarat.gitbook.io/typescript/future-javascript/promise#subscribing-to-the-fate-of-the-promise)
Subscribing to the fate of the promise
The promise fate can be subscribed to using `.then` (if resolved) or `.catch` (if rejected).
> TIP: Promise Shortcuts
>
> * Quickly creating an already resolved promise: `Promise.resolve(result)`
>
> * Quickly creating an already rejected promise: `Promise.reject(error)`
>
###
[](https://basarat.gitbook.io/typescript/future-javascript/promise#chain-ability-of-promises)
Chain-ability of Promises
The chain-ability of promises **is the heart of the benefit that promises provide**. Once you have a promise, from that point on, you use the `then` function to create a chain of promises.
* If you return a promise from any function in the chain, `.then` is only called once the value is resolved:
* You can aggregate the error handling of any preceding portion of the chain with a single `catch`:
* The `catch` actually returns a new promise (effectively creating a new promise chain):
* Any synchronous errors thrown in a `then` (or `catch`) result in the returned promise to fail:
* Only the relevant (nearest tailing) `catch` is called for a given error (as the catch starts a new promise chain).
* A `catch` is only called in case of an error in the preceding chain:
The fact that:
* errors jump to the tailing `catch` (and skip any middle `then` calls) and
* synchronous errors also get caught by any tailing `catch`.
effectively provides us with an async programming paradigm that allows better error handling than raw callbacks. More on this below.
###
[](https://basarat.gitbook.io/typescript/future-javascript/promise#typescript-and-promises)
TypeScript and promises
The great thing about TypeScript is that it understands the flow of values through a promise chain:
Of course it also understands unwrapping any function calls that might return a promise:
###
[](https://basarat.gitbook.io/typescript/future-javascript/promise#converting-a-callback-style-function-to-return-a-promise)
Converting a callback style function to return a promise
Just wrap the function call in a promise and
* `reject` if an error occurs,
* `resolve` if it is all good.
E.g. let's wrap `fs.readFile`:
The most reliable way to do this is to hand write it and it doesn't have to be as verbose as the previous example e.g. converting `setTimeout` into a promisified `delay` function is super easy:
Note that there is a handy dandy function in NodeJS that does this `node style function => promise returning function` magic for you:
> Webpack supports the `util` module out of the box and you can use it in the browser as well.
If you have a node callback style function as a _member_ be sure to `bind` it as well to make sure it has the correct `this`:
###
[](https://basarat.gitbook.io/typescript/future-javascript/promise#revisiting-the-json-example)
Revisiting the JSON example
Now let's revisit our `loadJSON` example and rewrite an async version that uses promises. All that we need to do is read the file contents as a promise, then parse them as JSON and we are done. This is illustrated in the below example:
Usage (notice how similar it is to the original `sync` version introduced at the start of this section ๐น):
The reason why this function was simpler is because the "`loadFile`(async) + `JSON.parse` (sync) => `catch`" consolidation was done by the promise chain. Also the callback was not called by _us_ but called by the promise chain so we didn't have the chance of making the mistake of wrapping it in a `try/catch`.
###
[](https://basarat.gitbook.io/typescript/future-javascript/promise#parallel-control-flow)
Parallel control flow
We have seen how trivial doing a serial sequence of async tasks is with promises. It is simply a matter of chaining `then` calls.
However, you might potentially want to run a series of async tasks and then do something with the results of all of these tasks. `Promise` provides a static `Promise.all` function that you can use to wait for `n` number of promises to complete. You provide it with an array of `n` promises and it gives you an array of `n` resolved values. Below we show Chaining as well as Parallel:
Sometimes, you want to run a series of async tasks, but you get all you need as long as any one of these tasks is settled. `Promise` provides a static `Promise.race` function for this scenario:
[PreviousTemplate Strings](https://basarat.gitbook.io/typescript/future-javascript/template-strings)
[NextGenerators](https://basarat.gitbook.io/typescript/future-javascript/generators)
Last updated 5 years ago
* [Promise](https://basarat.gitbook.io/typescript/future-javascript/promise#promise)
* [Callback style code](https://basarat.gitbook.io/typescript/future-javascript/promise#callback-style-code)
* [Creating a Promise](https://basarat.gitbook.io/typescript/future-javascript/promise#creating-a-promise)
* [Subscribing to the fate of the promise](https://basarat.gitbook.io/typescript/future-javascript/promise#subscribing-to-the-fate-of-the-promise)
* [Chain-ability of Promises](https://basarat.gitbook.io/typescript/future-javascript/promise#chain-ability-of-promises)
* [TypeScript and promises](https://basarat.gitbook.io/typescript/future-javascript/promise#typescript-and-promises)
* [Converting a callback style function to return a promise](https://basarat.gitbook.io/typescript/future-javascript/promise#converting-a-callback-style-function-to-return-a-promise)
* [Revisiting the JSON example](https://basarat.gitbook.io/typescript/future-javascript/promise#revisiting-the-json-example)
* [Parallel control flow](https://basarat.gitbook.io/typescript/future-javascript/promise#parallel-control-flow)
Copy
import fs = require('fs');
// A decent initial attempt .... but not correct. We explain the reasons below
function loadJSON(filename: string, cb: (error: Error, data: any) => void) {
fs.readFile(filename, function (err, data) {
if (err) cb(err);
else cb(null, JSON.parse(data));
});
}
Copy
import fs = require('fs');
// A decent initial attempt .... but not correct
function loadJSON(filename: string, cb: (error: Error, data: any) => void) {
fs.readFile(filename, function (err, data) {
if (err) cb(err);
else cb(null, JSON.parse(data));
});
}
// load invalid json
loadJSON('invalid.json', function (err, data) {
// This code never executes
if (err) console.log('bad.json error', err.message);
else console.log(data);
});
Copy
import fs = require('fs');
// A better attempt ... but still not correct
function loadJSON(filename: string, cb: (error: Error) => void) {
fs.readFile(filename, function (err, data) {
if (err) {
cb(err);
}
else {
try {
cb(null, JSON.parse(data));
}
catch (err) {
cb(err);
}
}
});
}
// load invalid json
loadJSON('invalid.json', function (err, data) {
if (err) console.log('bad.json error', err.message);
else console.log(data);
});
Copy
import fs = require('fs');
function loadJSON(filename: string, cb: (error: Error) => void) {
fs.readFile(filename, function (err, data) {
if (err) {
cb(err);
}
else {
try {
cb(null, JSON.parse(data));
}
catch (err) {
cb(err);
}
}
});
}
// a good file but a bad callback ... gets called again!
loadJSON('good.json', function (err, data) {
console.log('our callback called');
if (err) console.log('Error:', err.message);
else {
// let's simulate an error by trying to access a property on an undefined variable
var foo;
// The following code throws `Error: Cannot read property 'bar' of undefined`
console.log(foo.bar);
}
});
Copy
$ node asyncbadcatchdemo.js
our callback called
our callback called
Error: Cannot read property 'bar' of undefined
Copy
import fs = require('fs');
function loadJSON(filename: string, cb: (error: Error) => void) {
fs.readFile(filename, function (err, data) {
if (err) return cb(err);
// Contain all your sync code in a try catch
try {
var parsed = JSON.parse(data);
}
catch (err) {
return cb(err);
}
// except when you call the callback
return cb(null, parsed);
});
}
Copy
const promise = new Promise((resolve, reject) => {
// the resolve / reject functions control the fate of the promise
});
Copy
const promise = new Promise((resolve, reject) => {
resolve(123);
});
promise.then((res) => {
console.log('I get called:', res === 123); // I get called: true
});
promise.catch((err) => {
// This is never called
});
Copy
const promise = new Promise((resolve, reject) => {
reject(new Error("Something awful happened"));
});
promise.then((res) => {
// This is never called
});
promise.catch((err) => {
console.log('I get called:', err.message); // I get called: 'Something awful happened'
});
Copy
Promise.resolve(123)
.then((res) => {
console.log(res); // 123
return 456;
})
.then((res) => {
console.log(res); // 456
return Promise.resolve(123); // Notice that we are returning a Promise
})
.then((res) => {
console.log(res); // 123 : Notice that this `then` is called with the resolved value
return 123;
})
Copy
// Create a rejected promise
Promise.reject(new Error('something bad happened'))
.then((res) => {
console.log(res); // not called
return 456;
})
.then((res) => {
console.log(res); // not called
return 123;
})
.then((res) => {
console.log(res); // not called
return 123;
})
.catch((err) => {
console.log(err.message); // something bad happened
});
Copy
// Create a rejected promise
Promise.reject(new Error('something bad happened'))
.then((res) => {
console.log(res); // not called
return 456;
})
.catch((err) => {
console.log(err.message); // something bad happened
return 123;
})
.then((res) => {
console.log(res); // 123
})
Copy
Promise.resolve(123)
.then((res) => {
throw new Error('something bad happened'); // throw a synchronous error
return 456;
})
.then((res) => {
console.log(res); // never called
return Promise.resolve(789);
})
.catch((err) => {
console.log(err.message); // something bad happened
})
Copy
Promise.resolve(123)
.then((res) => {
throw new Error('something bad happened'); // throw a synchronous error
return 456;
})
.catch((err) => {
console.log('first catch: ' + err.message); // something bad happened
return 123;
})
.then((res) => {
console.log(res); // 123
return Promise.resolve(789);
})
.catch((err) => {
console.log('second catch: ' + err.message); // never called
})
Copy
Promise.resolve(123)
.then((res) => {
return 456;
})
.catch((err) => {
console.log("HERE"); // never called
})
Copy
Promise.resolve(123)
.then((res) => {
// res is inferred to be of type `number`
return true;
})
.then((res) => {
// res is inferred to be of type `boolean`
});
Copy
function iReturnPromiseAfter1Second(): Promise {
return new Promise((resolve) => {
setTimeout(() => resolve("Hello world!"), 1000);
});
}
Promise.resolve(123)
.then((res) => {
// res is inferred to be of type `number`
return iReturnPromiseAfter1Second(); // We are returning `Promise`
})
.then((res) => {
// res is inferred to be of type `string`
console.log(res); // Hello world!
});
Copy
import fs = require('fs');
function readFileAsync(filename: string): Promise {
return new Promise((resolve,reject) => {
fs.readFile(filename,(err,result) => {
if (err) reject(err);
else resolve(result);
});
});
}
Copy
const delay = (ms: number) => new Promise(res => setTimeout(res, ms));
Copy
/** Sample usage */
import fs from 'fs';
import util from 'util';
const readFile = util.promisify(fs.readFile);
Copy
const dbGet = util.promisify(db.get).bind(db);
Copy
function loadJSONAsync(filename: string): Promise {
return readFileAsync(filename) // Use the function we just wrote
.then(function (res) {
return JSON.parse(res);
});
}
Copy
// good json file
loadJSONAsync('good.json')
.then(function (val) { console.log(val); })
.catch(function (err) {
console.log('good.json error', err.message); // never called
})
// non-existent json file
.then(function () {
return loadJSONAsync('absent.json');
})
.then(function (val) { console.log(val); }) // never called
.catch(function (err) {
console.log('absent.json error', err.message);
})
// invalid json file
.then(function () {
return loadJSONAsync('invalid.json');
})
.then(function (val) { console.log(val); }) // never called
.catch(function (err) {
console.log('bad.json error', err.message);
});
Copy
// an async function to simulate loading an item from some server
function loadItem(id: number): Promise<{ id: number }> {
return new Promise((resolve) => {
console.log('loading item', id);
setTimeout(() => { // simulate a server delay
resolve({ id: id });
}, 1000);
});
}
// Chained / Sequential
let item1, item2;
loadItem(1)
.then((res) => {
item1 = res;
return loadItem(2);
})
.then((res) => {
item2 = res;
console.log('done');
}); // overall time will be around 2s
// Concurrent / Parallel
Promise.all([loadItem(1), loadItem(2)])
.then((res) => {
[item1, item2] = res;
console.log('done');
}); // overall time will be around 1s
Copy
var task1 = new Promise(function(resolve, reject) {
setTimeout(resolve, 1000, 'one');
});
var task2 = new Promise(function(resolve, reject) {
setTimeout(resolve, 2000, 'two');
});
Promise.race([task1, task2]).then(function(value) {
console.log(value); // "one"
// Both resolve, but task1 resolves faster
});
---
# Generators | TypeScript Deep Dive
`function *` is the syntax used to create a _generator function_. Calling a generator function returns a _generator object_. The generator object just follows the [iterator](https://basarat.gitbook.io/typescript/future-javascript/iterators)
interface (i.e. the `next`, `return` and `throw` functions).
There are two key motivations behind generator functions:
[](https://basarat.gitbook.io/typescript/future-javascript/generators#lazy-iterators)
Lazy Iterators
---------------------------------------------------------------------------------------------------------
Generator functions can be used to create lazy iterators e.g. the following function returns an **infinite** list of integers on demand:
Copy
function* infiniteSequence() {
var i = 0;
while(true) {
yield i++;
}
}
var iterator = infiniteSequence();
while (true) {
console.log(iterator.next()); // { value: xxxx, done: false } forever and ever
}
Of course if the iterator does end, you get the result of `{ done: true }` as demonstrated below:
Copy
function* idMaker(){
let index = 0;
while(index < 3)
yield index++;
}
let gen = idMaker();
console.log(gen.next()); // { value: 0, done: false }
console.log(gen.next()); // { value: 1, done: false }
console.log(gen.next()); // { value: 2, done: false }
console.log(gen.next()); // { done: true }
[](https://basarat.gitbook.io/typescript/future-javascript/generators#externally-controlled-execution)
Externally Controlled Execution
-------------------------------------------------------------------------------------------------------------------------------------------
This is the part of generators that is truly exciting. It essentially allows a function to pause its execution and pass control (fate) of the remainder of the function execution to the caller.
A generator function does not execute when you call it. It just creates a generator object. Consider the following example along with a sample execution:
If you run this you get the following output:
* The function only starts execution once `next` is called on the generator object.
* The function _pauses_ as soon as a `yield` statement is encountered.
* The function _resumes_ when `next` is called.
> So essentially the execution of the generator function is controllable by the generator object.
Our communication using the generator has been mostly one way with the generator returning values for the iterator. One extremely powerful feature of generators in JavaScript is that they allow two way communications (with caveats).
* you can control the resulting value of the `yield` expression using `iterator.next(valueToInject)`
* you can throw an exception at the point of the `yield` expression using `iterator.throw(error)`
The following example demonstrates `iterator.next(valueToInject)`:
Since `yield` returns the parameter passed to the iterator's `next` function, and all iterators' `next` functions accept a parameter of any type, TypeScript will always assign the `any` type to the result of the `yield` operator (`bar` above).
> You are on your own to coerce the result to the type you expect, and ensure that only values of that type are passed to next (such as by scaffolding an additional type-enforcement layer that calls `next` for you.) If strong typing is important to you, you may want to avoid two-way communication altogether, as well as packages that rely heavily on it (e.g., redux-saga).
The following example demonstrates `iterator.throw(error)`:
So here is the summary:
* `yield` allows a generator function to pause its communication and pass control to an external system
* the external system can push a value into the generator function body
* the external system can throw an exception into the generator function body
How is this useful? Jump to the next section [**async/await**](https://basarat.gitbook.io/typescript/future-javascript/async-await)
and find out.
[PreviousPromise](https://basarat.gitbook.io/typescript/future-javascript/promise)
[NextAsync Await](https://basarat.gitbook.io/typescript/future-javascript/async-await)
Last updated 5 years ago
* [Lazy Iterators](https://basarat.gitbook.io/typescript/future-javascript/generators#lazy-iterators)
* [Externally Controlled Execution](https://basarat.gitbook.io/typescript/future-javascript/generators#externally-controlled-execution)
Copy
function* generator(){
console.log('Execution started');
yield 0;
console.log('Execution resumed');
yield 1;
console.log('Execution resumed');
}
var iterator = generator();
console.log('Starting iteration'); // This will execute before anything in the generator function body executes
console.log(iterator.next()); // { value: 0, done: false }
console.log(iterator.next()); // { value: 1, done: false }
console.log(iterator.next()); // { value: undefined, done: true }
Copy
$ node outside.js
Starting iteration
Execution started
{ value: 0, done: false }
Execution resumed
{ value: 1, done: false }
Execution resumed
{ value: undefined, done: true }
Copy
function* generator() {
const bar = yield 'foo'; // bar may be *any* type
console.log(bar); // bar!
}
const iterator = generator();
// Start execution till we get first yield value
const foo = iterator.next();
console.log(foo.value); // foo
// Resume execution injecting bar
const nextThing = iterator.next('bar');
Copy
function* generator() {
try {
yield 'foo';
}
catch(err) {
console.log(err.message); // bar!
}
}
var iterator = generator();
// Start execution till we get first yield value
var foo = iterator.next();
console.log(foo.value); // foo
// Resume execution throwing an exception 'bar'
var nextThing = iterator.throw(new Error('bar'));
---
# JSX | TypeScript Deep Dive
[](https://designtsx.com/)
TypeScript supports JSX transpilation and code analysis. If you are unfamiliar with JSX here is an excerpt from the [official website](https://facebook.github.io/jsx/)
:
> JSX is an XML-like syntax extension to ECMAScript without any defined semantics. It's NOT intended to be implemented by engines or browsers. It's NOT a proposal to incorporate JSX into the ECMAScript spec itself. It's intended to be used by various preprocessors (transpilers) to transform these tokens into standard ECMAScript.
The motivation behind JSX is to allow users to write HTML like views _in JavaScript_ so that you can:
* Have the view Type Checked by the same code that is going to check your JavaScript
* Have the view be aware of the context it is going to operate under (i.e. strengthen the _controller-view_ connection in traditional MVC).
* Reuse JavaScript patterns for HTML maintenance e.g. `Array.prototype.map`, `?:`, `switch` etc instead of creating new (and probably poorly typed) alternatives.
This decreases the chances of errors and increases the maintainability of your user interfaces. The main consumer of JSX at this point is [ReactJS from facebook](http://facebook.github.io/react/)
. This is the usage of JSX that we will discuss here.
[PreviousMixins](https://basarat.gitbook.io/typescript/type-system/mixins)
[NextReact](https://basarat.gitbook.io/typescript/tsx/react)
Last updated 5 years ago
---
# Options | TypeScript Deep Dive
There are a few things that TypeScript prevents you from doing out of the box e.g. using a variable that _isn't ever declared_ (of course you can use a _declaration file_ for external systems).
That said, traditionally programming languages have a hard boundary between what is and isn't allowed by the type system. TypeScript is different in that it gives you control over where you put the slider. This is really to allow you to use the JavaScript you know and love with as much safety as **you** want. There are lots of compiler options to control exactly this slider so let's have a look.
[](https://basarat.gitbook.io/typescript/intro#boolean-options)
Boolean Options
------------------------------------------------------------------------------------
`compilerOptions` that are `boolean` can be specified as `compilerOptions` in `tsconfig.json`:
Copy
{
"compilerOptions": {
"someBooleanOption": true
}
}
or on the command line
Copy
tsc --someBooleanOption
> All of these are `false` by default.
Click [here](https://www.typescriptlang.org/docs/handbook/compiler-options.html)
to see all compiler options.
[PreviousNon React JSX](https://basarat.gitbook.io/typescript/tsx/others)
[NextnoImplicitAny](https://basarat.gitbook.io/typescript/intro/noimplicitany)
Last updated 5 years ago
---
# Errors in TypeScript | TypeScript Deep Dive
In this section we discuss how to read and understand TypeScript errors. We follow this with common errors and their solutions.
[PreviousstrictNullChecks](https://basarat.gitbook.io/typescript/intro/strictnullchecks)
[NextInterpreting Errors](https://basarat.gitbook.io/typescript/main/interpreting-errors)
Last updated 5 years ago
---
# noImplicitAny | TypeScript Deep Dive
There are some things that cannot be inferred or inferring them might result in unexpected errors. A fine example is function arguments. If you don't annotate them, its unclear what should and shouldn't be valid e.g.
Copy
function log(someArg) {
sendDataToServer(someArg);
}
// What arg is valid and what isn't?
log(123);
log('hello world');
So if you don't annotate some function argument, TypeScript assumes `any` and moves on. This essentially turns off type checking for such cases, which is what a JavaScript dev would expect. But this can catch people that want high safety off guard. Hence there is an option, `noImplicitAny`, that when switched on will flag the cases where the type cannot be inferred e.g.
Copy
function log(someArg) { // Error : someArg has an implicit `any` type
sendDataToServer(someArg);
}
Of course you can then go ahead and annotate:
Copy
function log(someArg: number) {
sendDataToServer(someArg);
}
And if you truly want _zero safety_ you can mark it _explicitly_ as `any`:
Copy
function log(someArg: any) {
sendDataToServer(someArg);
}
[PreviousOptions](https://basarat.gitbook.io/typescript/intro)
[NextstrictNullChecks](https://basarat.gitbook.io/typescript/intro/strictnullchecks)
Last updated 5 years ago
---
# Testing | TypeScript Deep Dive
TypeScript can be used with any JavaScript testing framework that you want. In the worst case you can always do a simple `TypeScript -> JavaScript` transform and go your merry way.
That said, in this section look at options that we have enjoyed greatly ๐น
[PreviousNPM](https://basarat.gitbook.io/typescript/index)
[NextJest](https://basarat.gitbook.io/typescript/intro-1/jest)
Last updated 5 years ago
---
# strictNullChecks | TypeScript Deep Dive
By default `null` and `undefined` are assignable to all types in TypeScript e.g.
Copy
let foo: number = 123;
foo = null; // Okay
foo = undefined; // Okay
This is modelled after how a lot of people write JavaScript. However, like all things, TypeScript allows you to be _explicit_ about what _can and cannot be_ assigned a `null` or `undefined`.
In strict null checking mode, `null` and `undefined` are different:
Copy
let foo = undefined;
foo = null; // NOT Okay
Let's say we have a `Member` interface:
Copy
interface Member {
name: string,
age?: number
}
Not every `Member` will provide their age, so `age` is an optional property, meaning the value of `age` may or may not be `undefined`.
`undefined` is the root of all evil. It often leads to runtime errors. It is easy to write code that will throw `Error` at runtime:
Copy
getMember()
.then(member: Member => {
const stringifyAge = member.age.toString() // Cannot read property 'toString' of undefined
})
But in strict null checking mode, this error will be caught at compile time:
[](https://basarat.gitbook.io/typescript/intro/strictnullchecks#non-null-assertion-operator)
Non-Null Assertion Operator
-----------------------------------------------------------------------------------------------------------------------------
A new `!` post-fix expression operator may be used to assert that its operand is non-null and non-undefined in contexts where the type checker is unable to conclude that fact. For example:
> Note that it is just an assertion, and just like type assertions _you are responsible_ for making sure the value is not null. A non-null assertion is essentially you telling the compiler "I know it's not null so let me use it as though it's not null".
###
[](https://basarat.gitbook.io/typescript/intro/strictnullchecks#definite-assignment-assertion-operator)
Definite Assignment Assertion Operator
TypeScript will also complain about properties in classes not being initialized e.g.:
You can use the definite assignment assertion postfixed to the property name to tell TypeScript that you are initializing it somewhere other than the constructor e.g.
You can also use this assertion with simple variable declarations e.g.:
> Like all assertions, you are telling the compiler to trust you. The compiler will not complain even if the code doesn't actually always assign the property.
[PreviousnoImplicitAny](https://basarat.gitbook.io/typescript/intro/noimplicitany)
[NextErrors in TypeScript](https://basarat.gitbook.io/typescript/main)
Last updated 5 years ago
* [Non-Null Assertion Operator](https://basarat.gitbook.io/typescript/intro/strictnullchecks#non-null-assertion-operator)
* [Definite Assignment Assertion Operator](https://basarat.gitbook.io/typescript/intro/strictnullchecks#definite-assignment-assertion-operator)
Copy
getMember()
.then(member: Member => {
const stringifyAge = member.age.toString() // Object is possibly 'undefined'
})
Copy
// Compiled with --strictNullChecks
function validateEntity(e?: Entity) {
// Throw exception if e is null or invalid entity
}
function processEntity(e?: Entity) {
validateEntity(e);
let a = e.name; // TS ERROR: e may be null.
let b = e!.name; // OKAY. We are asserting that e is non-null.
}
Copy
class C {
foo: number; // OKAY as assigned in constructor
bar: string = "hello"; // OKAY as has property initializer
baz: boolean; // TS ERROR: Property 'baz' has no initializer and is not assigned directly in the constructor.
constructor() {
this.foo = 42;
}
}
Copy
class C {
foo!: number;
// ^
// Notice this exclamation point!
// This is the "definite assignment assertion" modifier.
constructor() {
this.initialize();
}
initialize() {
this.foo = 0;
}
}
Copy
let a: number[]; // No assertion
let b!: number[]; // Assert
initialize();
a.push(4); // TS ERROR: variable used before assignment
b.push(4); // OKAY: because of the assertion
function initialize() {
a = [0, 1, 2, 3];
b = [0, 1, 2, 3];
}
---
# React | TypeScript Deep Dive
> [Free series of youtube videos on React / TypeScript best practices](https://www.youtube.com/watch?v=7EW67MqgJvs&list=PLYvdvJlnTOjHNayH7MukKbSJ6PueUNkkG)
>
> [PRO Egghead course on TypeScript and React](https://egghead.io/courses/use-typescript-to-develop-react-applications)
[](https://designtsx.com/)
[](https://basarat.gitbook.io/typescript/tsx/react#setup)
Setup
--------------------------------------------------------------------
Our [browser quickstart already sets you up to develop react applications](https://basarat.gitbook.io/typescript/browser)
. Here are the key highlights.
* Use files with the extension `.tsx` (instead of `.ts`).
* Use `"jsx" : "react"` in your `tsconfig.json`'s `compilerOptions`.
* Install the definitions for JSX and React into your project : (`npm i -D @types/react @types/react-dom`).
* Import react into your `.tsx` files (`import * as React from "react"`).
[](https://basarat.gitbook.io/typescript/tsx/react#html-tags-vs.-components)
HTML Tags vs. Components
----------------------------------------------------------------------------------------------------------
React can either render HTML tags (strings) or React components. The JavaScript emit for these elements is different (`React.createElement('div')` vs. `React.createElement(MyComponent)`). The way this is determined is by the _case_ of the _first_ letter. `foo` is treated as an HTML tag and `Foo` is treated as a component.
[](https://basarat.gitbook.io/typescript/tsx/react#type-checking)
Type Checking
------------------------------------------------------------------------------------
###
[](https://basarat.gitbook.io/typescript/tsx/react#html-tags)
HTML Tags
An HTML Tag `foo` is to be of the type `JSX.IntrinsicElements.foo`. These types are already defined for all the major tags in a file `react-jsx.d.ts` which we had you install as a part of the setup. Here is a sample of the the contents of the file:
###
[](https://basarat.gitbook.io/typescript/tsx/react#function-components)
Function Components
You can define function components simply with the `React.FunctionComponent` interface e.g.
###
[](https://basarat.gitbook.io/typescript/tsx/react#void-function-components)
Void Function Components
As of [@types/react PR #46643](https://github.com/DefinitelyTyped/DefinitelyTyped/pull/46643)
, you can use a new `React.VoidFunctionComponent` or `React.VFC` type if you wish to declare that a component does not take `children`. This is an interim solution until the next major version of the type defs (where VoidFunctionComponent will be deprecated and FunctionComponent will by default accept no children).
###
[](https://basarat.gitbook.io/typescript/tsx/react#class-components)
Class Components
Components are type checked based on the `props` property of the component. This is modeled after how JSX is transformed i.e. the attributes become the `props` of the component.
The `react.d.ts` file defines the `React.Component` class which you should extend in your own class providing your own `Props` and `State` interfaces. This is demonstrated below:
###
[](https://basarat.gitbook.io/typescript/tsx/react#react-jsx-tip-interface-for-renderable)
React JSX Tip: Interface for renderable
React can render a few things like `JSX` or `string`. These are all consolidated into the type `React.ReactNode` so use it for when you want to accept renderables e.g.
###
[](https://basarat.gitbook.io/typescript/tsx/react#react-jsx-tip-accept-an-instance-of-a-component)
React JSX Tip: Accept an instance of a Component
The react type definitions provide `React.ReactElement` to allow you to annotate the result of a `` class component instantiation. e.g.
> Of course you can use this as a function argument annotation and even React component prop member.
###
[](https://basarat.gitbook.io/typescript/tsx/react#react-jsx-tip-accept-a-component-that-can-act-on-props-and-be-rendered-using-jsx)
React JSX Tip: Accept a _component_ that can act on props and be rendered using JSX
The type `React.Component` consolidates `React.ComponentClass
| React.StatelessComponent
` so you can accept _something_ that takes type `Props` and renders it using JSX e.g.
###
[](https://basarat.gitbook.io/typescript/tsx/react#react-jsx-tip-generic-components)
React JSX Tip: Generic components
It works exactly as expected. Here is an example:
###
[](https://basarat.gitbook.io/typescript/tsx/react#generic-functions)
Generic functions
Something like the following works fine:
However, using an arrow generic function will not:
**Workaround**: Use `extends` on the generic parameter to hint the compiler that it's a generic, e.g.:
###
[](https://basarat.gitbook.io/typescript/tsx/react#react-tip-strongly-typed-refs)
React Tip: Strongly Typed Refs
You basically initialize a variable as a union of the ref and `null` and then initialize it as as callback e.g.
And the same with ref's for native elements e.g.
###
[](https://basarat.gitbook.io/typescript/tsx/react#type-assertions)
Type Assertions
Use `as Foo` syntax for type assertions as we [mentioned before](https://basarat.gitbook.io/typescript/type-system/type-assertion#as-foo-vs-foo)
.
[](https://basarat.gitbook.io/typescript/tsx/react#default-props)
Default Props
------------------------------------------------------------------------------------
* Stateful components with default props: You can tell TypeScript that a property will be provided externally (by React) by using a _null assertion_ operator (this isn't ideal but is the simplest minimum _extra code_ solution I could think of).
* SFC with default props: Recommend leveraging simple JavaScript patterns as they work well with TypeScript's type system e.g.
[](https://basarat.gitbook.io/typescript/tsx/react#declaring-a-webcomponent)
Declaring a webcomponent
----------------------------------------------------------------------------------------------------------
If you are using a web component the default React type definitions (`@types/react`) will not know about it. But you can declare it easily e.g. to declare a webcomponent called `my-awesome-slider` that takes Props `MyAwesomeSliderProps` you would:
Now you can use it in TSX:
[PreviousJSX](https://basarat.gitbook.io/typescript/tsx)
[NextNon React JSX](https://basarat.gitbook.io/typescript/tsx/others)
Last updated 5 years ago
* [Setup](https://basarat.gitbook.io/typescript/tsx/react#setup)
* [HTML Tags vs. Components](https://basarat.gitbook.io/typescript/tsx/react#html-tags-vs.-components)
* [Type Checking](https://basarat.gitbook.io/typescript/tsx/react#type-checking)
* [HTML Tags](https://basarat.gitbook.io/typescript/tsx/react#html-tags)
* [Function Components](https://basarat.gitbook.io/typescript/tsx/react#function-components)
* [Void Function Components](https://basarat.gitbook.io/typescript/tsx/react#void-function-components)
* [Class Components](https://basarat.gitbook.io/typescript/tsx/react#class-components)
* [React JSX Tip: Interface for renderable](https://basarat.gitbook.io/typescript/tsx/react#react-jsx-tip-interface-for-renderable)
* [React JSX Tip: Accept an instance of a Component](https://basarat.gitbook.io/typescript/tsx/react#react-jsx-tip-accept-an-instance-of-a-component)
* [React JSX Tip: Accept a component that can act on props and be rendered using JSX](https://basarat.gitbook.io/typescript/tsx/react#react-jsx-tip-accept-a-component-that-can-act-on-props-and-be-rendered-using-jsx)
* [React JSX Tip: Generic components](https://basarat.gitbook.io/typescript/tsx/react#react-jsx-tip-generic-components)
* [Generic functions](https://basarat.gitbook.io/typescript/tsx/react#generic-functions)
* [React Tip: Strongly Typed Refs](https://basarat.gitbook.io/typescript/tsx/react#react-tip-strongly-typed-refs)
* [Type Assertions](https://basarat.gitbook.io/typescript/tsx/react#type-assertions)
* [Default Props](https://basarat.gitbook.io/typescript/tsx/react#default-props)
* [Declaring a webcomponent](https://basarat.gitbook.io/typescript/tsx/react#declaring-a-webcomponent)
Copy
declare module JSX {
interface IntrinsicElements {
a: React.HTMLAttributes;
abbr: React.HTMLAttributes;
div: React.HTMLAttributes;
span: React.HTMLAttributes;
/// so on ...
}
}
Copy
type Props = {
foo: string;
}
const MyComponent: React.FunctionComponent = (props) => {
return {props.foo}
}
Copy
type Props = {
foo: string
}
// OK now, in future, error
const FunctionComponent: React.FunctionComponent = ({ foo, children }: Props) => {
return
{foo} {children}
; // OK
};
// Error now (children not support), in future, deprecated
const VoidFunctionComponent: React.VoidFunctionComponent = ({ foo, children }) => {
return
{foo}{children}
;
};
Copy
type Props = {
foo: string;
}
class MyComponent extends React.Component {
render() {
return {this.props.foo}
}
}
Copy
type Props = {
header: React.ReactNode;
body: React.ReactNode;
}
class MyComponent extends React.Component {
render() {
return