├── .gitattributes ├── .github └── workflows │ └── build.yml ├── .gitignore ├── CONTRIBUTING.md ├── GLOSSARY.md ├── LICENSE.md ├── README.md ├── SUMMARY.md ├── book.json ├── code ├── async-await │ ├── es5 │ │ ├── asyncAwaitES5.js │ │ ├── asyncAwaitES5.ts │ │ └── tsconfig.json │ └── es6 │ │ ├── asyncAwaitES6.js │ │ ├── asyncAwaitES6.ts │ │ └── tsconfig.json ├── compiler │ ├── node_modules │ │ ├── .bin │ │ │ ├── ntsc │ │ │ ├── ntsc.cmd │ │ │ ├── ntse │ │ │ ├── ntse.cmd │ │ │ ├── ntsserver │ │ │ └── ntsserver.cmd │ │ └── ntypescript │ │ │ ├── .npmignore │ │ │ ├── .travis.yml │ │ │ ├── CONTRIBUTING.md │ │ │ ├── Gruntfile.js │ │ │ ├── LICENCE │ │ │ ├── README.md │ │ │ ├── appveyor.yml │ │ │ ├── bin │ │ │ ├── lib.core.d.ts │ │ │ ├── lib.core.es6.d.ts │ │ │ ├── lib.d.ts │ │ │ ├── lib.dom.d.ts │ │ │ ├── lib.es6.d.ts │ │ │ ├── lib.scriptHost.d.ts │ │ │ ├── lib.webworker.d.ts │ │ │ ├── ntypescript.d.ts │ │ │ ├── ntypescript.js │ │ │ ├── tsc │ │ │ ├── tsc.js │ │ │ ├── tse │ │ │ ├── tsserver │ │ │ ├── tsserver.js │ │ │ ├── typescript.d.ts │ │ │ ├── typescript.js │ │ │ ├── typescriptServices.d.ts │ │ │ └── typescriptServices.js │ │ │ ├── extensions │ │ │ ├── addExtensions.d.ts │ │ │ ├── addExtensions.js │ │ │ ├── addExtensions.ts │ │ │ ├── extensions.d.ts │ │ │ ├── extensions.js │ │ │ ├── extensions.ts │ │ │ └── tsconfig.json │ │ │ ├── kicktravis │ │ │ ├── package.json │ │ │ ├── prepare.sh │ │ │ ├── quick.sh │ │ │ ├── register.js │ │ │ ├── register.ts │ │ │ ├── release.sh │ │ │ ├── tasks │ │ │ ├── ntypescript.js │ │ │ └── ntypescript.ts │ │ │ ├── tsconfig.json │ │ │ ├── tsd.json │ │ │ ├── tse.js │ │ │ ├── tse.ts │ │ │ └── typings │ │ │ ├── gruntjs │ │ │ └── gruntjs.d.ts │ │ │ ├── node │ │ │ └── node.d.ts │ │ │ └── tsd.d.ts │ ├── package.json │ ├── parser │ │ ├── runParser.js │ │ └── runParser.ts │ ├── scanner │ │ ├── runScanner.js │ │ ├── runScanner.ts │ │ ├── runScannerWithPositions.js │ │ └── runScannerWithPositions.ts │ ├── tsconfig.json │ ├── tsd.json │ └── typings │ │ ├── node │ │ └── node.d.ts │ │ └── tsd.d.ts ├── declarationspaces │ ├── declarationspace.js │ └── declarationspace.ts ├── dynamic-import-expressions │ ├── dynamicImportExpression.js │ ├── dynamicImportExpression.ts │ ├── package.json │ └── tsconfig.json ├── errors │ ├── common-errors.ts │ ├── interpreting-errors.ts │ └── tsconfig.json ├── es6 │ ├── classes │ │ ├── abstract.js │ │ ├── abstract.ts │ │ ├── class.js │ │ ├── class.ts │ │ ├── super.js │ │ ├── super.ts │ │ └── tsconfig.json │ ├── const.js │ ├── const.ts │ ├── destructuring.js │ ├── destructuring.ts │ ├── enums.js │ ├── enums.ts │ ├── for..of.js │ ├── for..of.ts │ ├── forof.js │ ├── iterators.js │ ├── iterators.ts │ ├── let.js │ ├── let.ts │ ├── rest-parameters.js │ ├── rest-parameters.ts │ ├── spread-operator.js │ ├── spread-operator.ts │ ├── template-strings.js │ ├── template-strings.ts │ ├── test.js │ ├── test.ts │ └── tsconfig.json ├── javascript │ ├── closure.js │ ├── closure.ts │ └── tsconfig.json ├── tips │ ├── bindIsBad.js │ ├── bindIsBad.ts │ ├── currying.js │ ├── currying.ts │ ├── lazyObjectLiteralInitialization.js │ ├── lazyObjectLiteralInitialization.ts │ ├── mixins.js │ ├── mixins.ts │ ├── nominalTyping.js │ ├── nominalTyping.ts │ ├── statefulFunctions.js │ ├── statefulFunctions.ts │ ├── stringEnums.js │ ├── stringEnums.ts │ └── tsconfig.json └── types │ ├── assertion.js │ ├── assertion.ts │ ├── callable.ts │ ├── freshness │ ├── freshness.js │ ├── freshness.ts │ ├── index-signatures.js │ ├── index-signatures.ts │ └── tsconfig.json │ ├── functions.js │ ├── functions.ts │ ├── generics.js │ ├── generics.ts │ ├── interfaces.js │ ├── interfaces.ts │ ├── keyof.ts │ ├── lib │ ├── exclude │ │ ├── nolibd.js │ │ ├── nolibd.ts │ │ └── tsconfig.json │ └── usage │ │ ├── libd.js │ │ ├── libd.ts │ │ └── tsconfig.json │ ├── libd.js │ ├── literal-types.js │ ├── literal-types.ts │ ├── migrating │ ├── migrating.js │ ├── migrating.ts │ └── tsconfig.json │ ├── readonly.js │ ├── readonly.ts │ ├── stringLiteralType.js │ ├── tsconfig.json │ ├── type-compatibility.js │ ├── type-compatibility.ts │ ├── type-inference.js │ ├── type-inference.ts │ ├── typeGuard.js │ ├── typeGuard.ts │ ├── types.js │ └── types.ts ├── cover.jpg ├── docs ├── arrow-functions.md ├── async-await.md ├── classes-emit.md ├── classes.md ├── compiler-options.md ├── compiler │ ├── ast-tip-children.md │ ├── ast-tip-syntaxkind.md │ ├── ast-trivia.md │ ├── ast.md │ ├── binder-container.md │ ├── binder-declarations.md │ ├── binder-diagnostics.md │ ├── binder-functions.md │ ├── binder-symbolflags.md │ ├── binder-symboltable.md │ ├── binder.md │ ├── checker-diagnostics.md │ ├── checker-global.md │ ├── checker.md │ ├── contributing.md │ ├── emitter-functions.md │ ├── emitter-sourcemaps.md │ ├── emitter.md │ ├── make-global.md │ ├── overview.md │ ├── parser-functions.md │ ├── parser.md │ ├── program.md │ └── scanner.md ├── const.md ├── declaration.md ├── destructuring.md ├── enums.md ├── errors │ ├── common-errors.md │ ├── interpreting-errors.md │ └── main.md ├── for...of.md ├── future-javascript.md ├── generators.md ├── getting-started.md ├── iterators.md ├── javascript │ ├── closure.md │ ├── equality.md │ ├── null-undefined.md │ ├── number.md │ ├── recap.md │ ├── references.md │ ├── this.md │ └── truthy.md ├── jsx │ ├── others.md │ ├── react.md │ └── tsx.md ├── let.md ├── npm │ └── index.md ├── options │ ├── intro.md │ ├── noImplicitAny.md │ └── strictNullChecks.md ├── project │ ├── compilation-context.md │ ├── declarationspaces.md │ ├── dynamic-import-expressions.md │ ├── external-modules.md │ ├── files.md │ ├── globals.md │ ├── module-resolution.md │ ├── modules.md │ ├── namespaces.md │ ├── project.md │ └── tsconfig.md ├── promise.md ├── quick │ ├── browser.md │ ├── library.md │ └── nodejs.md ├── rest-parameters.md ├── spread-operator.md ├── staging │ ├── async-await.md │ └── generators.md ├── state │ └── mobx.md ├── styleguide │ ├── sample.js │ ├── sample.ts │ ├── styleguide.md │ └── tsconfig.json ├── template-strings.md ├── testing │ ├── cypress.md │ ├── intro.md │ └── jest.md ├── tips │ ├── barrel.md │ ├── build-toggles.md │ ├── classesAreUseful.md │ ├── create-arrays.md │ ├── currying.md │ ├── defaultIsBad.md │ ├── functionParameters.md │ ├── jquery.md │ ├── lazyObjectLiteralInitialization.md │ ├── main.md │ ├── nominalTyping.md │ ├── outFile.md │ ├── propertySetters.md │ ├── singleton.md │ ├── statefulFunctions.md │ ├── staticConstructor.md │ ├── stringEnums.md │ ├── typeInstantiation.md │ └── typed-event.md ├── tools │ ├── changelog.md │ ├── eslint.md │ ├── husky.md │ ├── intro.md │ └── prettier.md ├── types │ ├── @types.md │ ├── advanced.md │ ├── ambient │ │ ├── d.ts.md │ │ ├── intro.md │ │ └── variables.md │ ├── callable.md │ ├── discriminated-unions.md │ ├── exceptions.md │ ├── freshness.md │ ├── functions.md │ ├── generics.md │ ├── index-signatures.md │ ├── interfaces.md │ ├── lib.d.ts.md │ ├── literal-types.md │ ├── migrating.md │ ├── mixins.md │ ├── moving-types.md │ ├── never.md │ ├── readonly.md │ ├── type-assertion.md │ ├── type-compatibility.md │ ├── type-inference.md │ ├── type-system.md │ └── typeGuard.md └── why-typescript.md ├── footer.md ├── header.html ├── images ├── atomts.png ├── designtsx-banner-large.png ├── designtsx-banner.png ├── errors │ └── interpreting-errors │ │ └── ide.png ├── github.png ├── promise states and fates.png ├── promise states and fates.vsd ├── venn.png └── venn.vsd └── snippets └── md-snippets.cson /.gitattributes: -------------------------------------------------------------------------------- 1 | # core.autocrlf 2 | * text=auto 3 | 4 | *.js linguist-language=TypeScript 5 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build ebook 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | branches: 9 | - master 10 | 11 | jobs: 12 | build: 13 | runs-on: ubuntu-latest 14 | env: 15 | SHA: ${{ github.sha }} 16 | steps: 17 | - uses: actions/checkout@v1 18 | - uses: actions/setup-node@v1 19 | with: 20 | node-version: '12.18.2' 21 | - run: sudo apt update 22 | - run: sudo apt install libegl1 libopengl0 libxcb-cursor-dev 23 | - run: sudo -v && wget -nv -O- https://download.calibre-ebook.com/linux-installer.sh | sudo sh /dev/stdin 24 | - run: sudo npm install -g gitbook-cli 25 | - run: gitbook install 26 | - run: mkdir output 27 | - run: gitbook pdf . ./output/typescript-book-${SHA}.pdf 28 | - run: gitbook epub . ./output/typescript-book-${SHA}.epub 29 | - run: gitbook mobi . ./output/typescript-book-${SHA}.mobi 30 | - name: upload pdf artifact 31 | uses: actions/upload-artifact@v1 32 | with: 33 | name: typescript-book.pdf 34 | path: output/typescript-book-${{ env.SHA }}.pdf 35 | - name: upload epub artifact 36 | uses: actions/upload-artifact@v1 37 | with: 38 | name: typescript-book.epub 39 | path: output/typescript-book-${{ env.SHA }}.epub 40 | - name: upload mobi artifact 41 | uses: actions/upload-artifact@v1 42 | with: 43 | name: typescript-book.mobi 44 | path: output/typescript-book-${{ env.SHA }}.mobi 45 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Mac 2 | *.DS_Store 3 | 4 | # IDEs 5 | .alm 6 | .vscode 7 | 8 | 9 | # Node rules: 10 | ## Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 11 | .grunt 12 | 13 | ## Dependency directory 14 | ## Commenting this out is preferred by some people, see 15 | ## https://docs.npmjs.com/misc/faq#should-i-check-my-node_modules-folder-into-git 16 | node_modules 17 | 18 | # Book build output 19 | _book 20 | 21 | # eBook build output 22 | *.epub 23 | *.mobi 24 | *.pdf 25 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | This book is developed using [GitBook](https://github.com/GitbookIO/gitbook). Authored in Markdown files (I use [atom](http://atom.io)). 4 | 5 | Here's how to setup a Dev Environment: 6 | 7 | ``` 8 | npm install gitbook-cli -g 9 | gitbook install 10 | gitbook serve . 11 | ``` 12 | > Note: serve needs port `35729` (for live reload) and `4000` for serving http://localhost:4000. 13 | 14 | Also you can mostly just edit the `.md` files in [`/docs`](https://github.com/basarat/typescript-book/docs) using github and create a Pull Request (PR). 15 | 16 | # Code 17 | All the code for the book is in the `/code` folder. Tested with `atom-typescript`. 18 | 19 | ### More Gitbook Tips 20 | * Links best work if they are relative (e.g. `./foo.md`) to the *current* file. 21 | * For links in the same file (`#foo-bar` style links) best to click the heading on github to get what gitbook expects. 22 | 23 | ### TypeScript Compiler Docs 24 | Thanks to the TypeScript team for providing much of the docs: https://github.com/Microsoft/TypeScript/wiki/Architectural-Overview that are used to write the compiler story. 25 | -------------------------------------------------------------------------------- /GLOSSARY.md: -------------------------------------------------------------------------------- 1 | # Duck Typing 2 | If it walks like a duck and quacks like a duck, it is a duck. For TypeScript if it has all the members structurally then it is okay for other things (irrespecitive of name) that accept that structure. 3 | 4 | # OE 5 | Operating Environment. I'd like to use the term Operating System, but that is not necessarily what I mean here. Think Browser,Node.js,WScriptHost etc. 6 | 7 | # Incremental Parsing 8 | Re-Parsing as the user edits the code. -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Creative Commons 2 | 3 | https://creativecommons.org/licenses/by/4.0/ 4 | -------------------------------------------------------------------------------- /book.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "en", 3 | "author": "Basarat Ali Syed", 4 | "title": "TypeScript Deep Dive", 5 | "plugins": ["edit-link", "github", "adsense","header"], 6 | "pluginsConfig": { 7 | "layout": { 8 | "headerPath" : "header.html" 9 | }, 10 | "lunr": { 11 | "ignoreSpecialCharacters": true 12 | }, 13 | "edit-link": { 14 | "base": "https://github.com/basarat/typescript-book/tree/master", 15 | "label": "Edit This Page" 16 | }, 17 | "github": { 18 | "url": "https://github.com/basarat/typescript-book/" 19 | }, 20 | "adsense": { 21 | "client": "ca-pub-4656761253552116", 22 | "slot": "2017468453", 23 | "format": "auto", 24 | "element": ".page-inner section", 25 | "position": "bottom" 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /code/async-await/es5/asyncAwaitES5.ts: -------------------------------------------------------------------------------- 1 | function delay(milliseconds: number, count: number): Promise { 2 | return new Promise(resolve => { 3 | setTimeout(() => { 4 | resolve(count); 5 | }, milliseconds); 6 | }); 7 | } 8 | 9 | // async function always return a Promise 10 | async function dramaticWelcome(): Promise { 11 | console.log("Hello"); 12 | 13 | for (let i = 0; i < 5; i++) { 14 | // await is converting Promise into number 15 | const count: number = await delay(500, i); 16 | console.log(count); 17 | } 18 | 19 | console.log("World!"); 20 | } 21 | 22 | dramaticWelcome(); -------------------------------------------------------------------------------- /code/async-await/es5/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'. */ 4 | "module": "commonjs", /* Specify module code generation: 'commonjs', 'amd', 'system', 'umd' or 'es2015'. */ 5 | "lib": ["dom", "es2015.promise", "es5"] /* Specify library files to be included in the compilation: */ 6 | }, 7 | "files": [ 8 | "./asyncAwaitES5.ts" 9 | ] 10 | } -------------------------------------------------------------------------------- /code/async-await/es6/asyncAwaitES6.js: -------------------------------------------------------------------------------- 1 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 2 | return new (P || (P = Promise))(function (resolve, reject) { 3 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 4 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 5 | function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } 6 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 7 | }); 8 | }; 9 | function delay(milliseconds, count) { 10 | return new Promise(resolve => { 11 | setTimeout(() => { 12 | resolve(count); 13 | }, milliseconds); 14 | }); 15 | } 16 | // async function always return a Promise 17 | function dramaticWelcome() { 18 | return __awaiter(this, void 0, void 0, function* () { 19 | console.log("Hello"); 20 | for (let i = 0; i < 5; i++) { 21 | // await is converting Promise into number 22 | const count = yield delay(500, i); 23 | console.log(count); 24 | } 25 | console.log("World!"); 26 | }); 27 | } 28 | dramaticWelcome(); 29 | -------------------------------------------------------------------------------- /code/async-await/es6/asyncAwaitES6.ts: -------------------------------------------------------------------------------- 1 | function delay(milliseconds: number, count: number): Promise { 2 | return new Promise(resolve => { 3 | setTimeout(() => { 4 | resolve(count); 5 | }, milliseconds); 6 | }); 7 | } 8 | 9 | // async function always return a Promise 10 | async function dramaticWelcome(): Promise { 11 | console.log("Hello"); 12 | 13 | for (let i = 0; i < 5; i++) { 14 | // await is converting Promise into number 15 | const count: number = await delay(500, i); 16 | console.log(count); 17 | } 18 | 19 | console.log("World!"); 20 | } 21 | 22 | dramaticWelcome(); -------------------------------------------------------------------------------- /code/async-await/es6/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'. */ 4 | "module": "commonjs" /* Specify module code generation: 'commonjs', 'amd', 'system', 'umd' or 'es2015'. */ 5 | }, 6 | "files": [ 7 | "./asyncAwaitES6.ts" 8 | ] 9 | } -------------------------------------------------------------------------------- /code/compiler/node_modules/.bin/ntsc: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | basedir=`dirname "$0"` 3 | 4 | case `uname` in 5 | *CYGWIN*) basedir=`cygpath -w "$basedir"`;; 6 | esac 7 | 8 | if [ -x "$basedir/node" ]; then 9 | "$basedir/node" "$basedir/../ntypescript/bin/tsc" "$@" 10 | ret=$? 11 | else 12 | node "$basedir/../ntypescript/bin/tsc" "$@" 13 | ret=$? 14 | fi 15 | exit $ret 16 | -------------------------------------------------------------------------------- /code/compiler/node_modules/.bin/ntsc.cmd: -------------------------------------------------------------------------------- 1 | @IF EXIST "%~dp0\node.exe" ( 2 | "%~dp0\node.exe" "%~dp0\..\ntypescript\bin\tsc" %* 3 | ) ELSE ( 4 | @SETLOCAL 5 | @SET PATHEXT=%PATHEXT:;.JS;=;% 6 | node "%~dp0\..\ntypescript\bin\tsc" %* 7 | ) -------------------------------------------------------------------------------- /code/compiler/node_modules/.bin/ntse: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | basedir=`dirname "$0"` 3 | 4 | case `uname` in 5 | *CYGWIN*) basedir=`cygpath -w "$basedir"`;; 6 | esac 7 | 8 | if [ -x "$basedir/node" ]; then 9 | "$basedir/node" "$basedir/../ntypescript/bin/tse" "$@" 10 | ret=$? 11 | else 12 | node "$basedir/../ntypescript/bin/tse" "$@" 13 | ret=$? 14 | fi 15 | exit $ret 16 | -------------------------------------------------------------------------------- /code/compiler/node_modules/.bin/ntse.cmd: -------------------------------------------------------------------------------- 1 | @IF EXIST "%~dp0\node.exe" ( 2 | "%~dp0\node.exe" "%~dp0\..\ntypescript\bin\tse" %* 3 | ) ELSE ( 4 | @SETLOCAL 5 | @SET PATHEXT=%PATHEXT:;.JS;=;% 6 | node "%~dp0\..\ntypescript\bin\tse" %* 7 | ) -------------------------------------------------------------------------------- /code/compiler/node_modules/.bin/ntsserver: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | basedir=`dirname "$0"` 3 | 4 | case `uname` in 5 | *CYGWIN*) basedir=`cygpath -w "$basedir"`;; 6 | esac 7 | 8 | if [ -x "$basedir/node" ]; then 9 | "$basedir/node" "$basedir/../ntypescript/bin/tsserver" "$@" 10 | ret=$? 11 | else 12 | node "$basedir/../ntypescript/bin/tsserver" "$@" 13 | ret=$? 14 | fi 15 | exit $ret 16 | -------------------------------------------------------------------------------- /code/compiler/node_modules/.bin/ntsserver.cmd: -------------------------------------------------------------------------------- 1 | @IF EXIST "%~dp0\node.exe" ( 2 | "%~dp0\node.exe" "%~dp0\..\ntypescript\bin\tsserver" %* 3 | ) ELSE ( 4 | @SETLOCAL 5 | @SET PATHEXT=%PATHEXT:;.JS;=;% 6 | node "%~dp0\..\ntypescript\bin\tsserver" %* 7 | ) -------------------------------------------------------------------------------- /code/compiler/node_modules/ntypescript/.npmignore: -------------------------------------------------------------------------------- 1 | TypeScript 2 | .gitmodules 3 | tests -------------------------------------------------------------------------------- /code/compiler/node_modules/ntypescript/.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - iojs 4 | env: 5 | global: 6 | - secure: WXkeUKwWKTv2uUCyIiDdQ0e5gQCoX9gGj6wiNh9G7IATqcecxTw6cpQGj3J8YWDIjbtNXfAkJwohhGtXYr7VnkXRA1s0POYM+8cvM5I+ZDtZkXM9EvCwMYxf9XZ8qQ/4fegeSoZqfx1qgh+Sfh6Wp93I4W+AfB8VONLIGgXr172QGwYmkynPpC//mYA6sUZoQo4Y796PtBblc+7oM0a5A5chQ5r1CVqPqRZ/i9aNrH2UTdYjCMNE395LqwHSJGk5eunT5ebA4OcClme1wL78MJtGS1ZZIOEHSBv7mBrOcp29kYknc/m1PaOYBMdppmRBLr6Q5oUg8QzaILW2TypsWkosWpSlbemW1lsutqlFRkmtsjfX3ZVOoeIx/7J9v+pDA2gb7VMtNzwlkRpcLfHBmfuXuiPNXwLS1Ogl2D8JUD+rjwB3FI6pE2zZqNL7zMe7yhCQ/1wqGdlNqB1Ifb9T2RRkDCEUr+dw3sGn6Ecgk4XThUwY3vVzABj0C906Wc7UpsVvf1qjLCRg48lYG8kmhLqEylL+IUs3XXMSv69/YLxnDvRdF/d1FZHWKcoTeWYmXr3k1q0ePYEDXpX6/8MXWix1Qql4AAOjIxOgRufBPlDWe6QS2b97K4OPo+m3cf/RaLPz+jUOpf59l6CNnceBYLKs00Taf0KSgs+YVADAV6M= 7 | before_script: 8 | - git config --global user.email "basaratali@gmail.com" 9 | - git config --global user.name "Travis-CI" 10 | - git remote set-url origin https://github.com/basarat/ntypescript.git 11 | script: 12 | - bash prepare.sh 13 | after_success: 14 | - git config credential.helper "store --file=.git/credentials" 15 | - echo "https://${GH_TOKEN}:@github.com" > .git/credentials 16 | - git config --global push.default matching 17 | - bash release.sh 18 | 19 | # Only master kicks a build 20 | branches: 21 | only: 22 | - master 23 | 24 | deploy: 25 | provider: npm 26 | email: basaratali@gmail.com 27 | api_key: 28 | secure: qUecySLzb8peMNoWTuKuPM6YgHTwyLhs0mOyuWmeovJZzpxoLxG3qCfQjxekCSnGmLqd3nSKuP2T8DXaytJqEcB/c2eSrsv13jcw4hfAl1EAQjqFL18xzf7zO6mpjDZWP+eWdNwr1jH+Z+uvu1Qkb0uVvDtYgaWai31JpY4q7Vz+OKKz3V+loqeygysm5IZFEpzV96XI39EZZSwMa0pC51g1gZVx71AbORWI9zyPEw0QDysSr4NkU5DaqCvk0GVVGwU03YMFRJVQWs2H8B0SfQT1Nj8glUIYfXZ8BuZr7nTYwCnOSa27Yn5H17XHc+Zl8CPRtTNlkaVUSpDEF4hpMj2fKpePd4OXRzkud2aXMyd+IEmvf/s9kZRstFic7mly9vKS06jtQsWISeI1fULF121DKtoQX+zmwU2TFD21xo/VeuSHD2YpSkfbVnb9/ezqOAx/eqQXaTIOfw31+eR2eAb2bhgW0T6p7aJXMrIBw+VaPxa6Ckls6ItOKMBj/l00Hn/fP8oucNte9FlgevcS+ieOmzGw4Y2tb1RK5AUYQA+F39xXRH0upiYk8BxvLq9Qg/xuCUbMxJ8Ax37ObVW2QBdVhJlNleMt3iZMQQS/OLUHgGPyFmrXmavc3yQM38Bot6ScOsUehe/ViOIMeNO4mRCxUdgKEAyi0SgL604nFKE= 29 | on: 30 | repo: TypeStrong/ntypescript 31 | -------------------------------------------------------------------------------- /code/compiler/node_modules/ntypescript/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Release 2 | 3 | ## Quickly 4 | 5 | Quick workflow (runs `prepare` and `release`): 6 | 7 | ```sh 8 | quick.sh 9 | ``` 10 | 11 | ## Manually 12 | 13 | ```sh 14 | prepare.sh 15 | ``` 16 | 17 | Manual verification here ... then: 18 | 19 | ```sh 20 | release.sh 21 | npm publish 22 | ``` 23 | 24 | ## globals 25 | 26 | You can try the globals using: 27 | 28 | ``` 29 | npm link 30 | ``` 31 | 32 | # Inspiration 33 | https://github.com/Arnavion/typescript-github 34 | 35 | # Travis 36 | Cron job setup using : http://traviscron.pythonanywhere.com/ for daily 37 | -------------------------------------------------------------------------------- /code/compiler/node_modules/ntypescript/Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | 3 | grunt.initConfig({ 4 | ntypescript: { 5 | options: { 6 | project: '.' 7 | }, 8 | default: {}, 9 | pass: { 10 | options: { 11 | project: './tests/grunt/pass' 12 | } 13 | }, 14 | fail: { 15 | options: { 16 | project: './tests/grunt/fail' 17 | } 18 | }, 19 | }, 20 | }); 21 | 22 | grunt.loadTasks('tasks'); 23 | // They would do: 24 | // grunt.loadNpmTasks('ntypescript'); 25 | 26 | grunt.registerTask('default', ['ntypescript:default']); 27 | }; -------------------------------------------------------------------------------- /code/compiler/node_modules/ntypescript/LICENCE: -------------------------------------------------------------------------------- 1 | MIT 2 | -------------------------------------------------------------------------------- /code/compiler/node_modules/ntypescript/appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 1.0.{build} 2 | os: MinGW 3 | environment: 4 | access_token: 5 | secure: keMAbmi7iJ7xgQfIIv8IWFhu2h/ghgJc43OzQ2Fr554ZPQzhohZ9/+2TA3886VCo 6 | build_script: 7 | - prepare.sh 8 | on_success: 9 | - git config --global credential.helper store 10 | - ps: Add-Content "$env:USERPROFILE\.git-credentials" "https://$($env:access_token):x-oauth-basic@github.com`n" 11 | - release.sh 12 | -------------------------------------------------------------------------------- /code/compiler/node_modules/ntypescript/bin/tsc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | require('./tsc.js') 3 | -------------------------------------------------------------------------------- /code/compiler/node_modules/ntypescript/bin/tse: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | require('../tse.js') 3 | -------------------------------------------------------------------------------- /code/compiler/node_modules/ntypescript/bin/tsserver: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | require('./tsserver.js') 3 | -------------------------------------------------------------------------------- /code/compiler/node_modules/ntypescript/extensions/addExtensions.d.ts: -------------------------------------------------------------------------------- 1 | declare var require: any, __dirname: any; 2 | declare var fs: any; 3 | declare var EOL: string; 4 | declare function readFile(filePath: string): string; 5 | declare function writeFile(filePath: string, content: string): void; 6 | declare var dtsWithGlobal: string; 7 | declare var dtsExtensionsGlobal: string; 8 | declare var jsOriginal: string; 9 | declare var jsExtensions: string; 10 | declare var finalDtsLocation: string; 11 | declare var finalJsLocation: string; 12 | declare var finalDtsContent: string; 13 | declare var finalJsContent: string; 14 | -------------------------------------------------------------------------------- /code/compiler/node_modules/ntypescript/extensions/addExtensions.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | var EOL = require('os').EOL; 3 | function readFile(filePath) { 4 | return fs.readFileSync(__dirname + '/' + filePath, 'utf8'); 5 | } 6 | function writeFile(filePath, content) { 7 | fs.writeFileSync(__dirname + '/' + filePath, content); 8 | } 9 | var dtsWithGlobal = readFile('../bin/typescriptServices.d.ts'); 10 | var dtsExtensionsGlobal = readFile('./extensions.d.ts'); 11 | var jsOriginal = readFile('../bin/typescript.js'); 12 | var jsExtensions = readFile('./extensions.js'); 13 | var finalDtsLocation = '../bin/ntypescript.d.ts'; 14 | var finalJsLocation = '../bin/ntypescript.js'; 15 | var finalDtsContent = dtsWithGlobal + EOL + dtsExtensionsGlobal + EOL + "\ndeclare module \"ntypescript\" {\n export = ts;\n}\n"; 16 | var finalJsContent = jsOriginal + EOL + jsExtensions; 17 | writeFile(finalDtsLocation, finalDtsContent); 18 | writeFile(finalJsLocation, finalJsContent); 19 | -------------------------------------------------------------------------------- /code/compiler/node_modules/ntypescript/extensions/addExtensions.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This script is responsible for making required modifications to our version of TypeScript 3 | */ 4 | declare var require, __dirname; 5 | var fs = require('fs'); 6 | var EOL: string = require('os').EOL; 7 | function readFile(filePath: string): string { 8 | return fs.readFileSync(__dirname + '/' + filePath, 'utf8'); 9 | } 10 | function writeFile(filePath: string, content: string) { 11 | fs.writeFileSync(__dirname + '/' + filePath, content); 12 | } 13 | var dtsWithGlobal = readFile('../bin/typescriptServices.d.ts'); 14 | var dtsExtensionsGlobal = readFile('./extensions.d.ts'); 15 | 16 | var jsOriginal = readFile('../bin/typescript.js'); 17 | var jsExtensions = readFile('./extensions.js'); 18 | 19 | var finalDtsLocation = '../bin/ntypescript.d.ts'; 20 | var finalJsLocation = '../bin/ntypescript.js'; 21 | 22 | var finalDtsContent = dtsWithGlobal + EOL + dtsExtensionsGlobal + EOL + ` 23 | declare module "ntypescript" { 24 | export = ts; 25 | } 26 | `; 27 | var finalJsContent = jsOriginal + EOL + jsExtensions; 28 | 29 | writeFile(finalDtsLocation, finalDtsContent); 30 | writeFile(finalJsLocation, finalJsContent); 31 | -------------------------------------------------------------------------------- /code/compiler/node_modules/ntypescript/extensions/extensions.d.ts: -------------------------------------------------------------------------------- 1 | declare module ts { 2 | function syntaxKindToName(kind: ts.SyntaxKind): string; 3 | } 4 | -------------------------------------------------------------------------------- /code/compiler/node_modules/ntypescript/extensions/extensions.js: -------------------------------------------------------------------------------- 1 | var ts; 2 | (function (ts) { 3 | function syntaxKindToName(kind) { 4 | return ts.SyntaxKind[kind]; 5 | } 6 | ts.syntaxKindToName = syntaxKindToName; 7 | })(ts || (ts = {})); 8 | if (typeof global !== "undefined") { 9 | global.ts = ts; 10 | } 11 | if (typeof window !== "undefined") { 12 | window.ts = ts; 13 | } 14 | -------------------------------------------------------------------------------- /code/compiler/node_modules/ntypescript/extensions/extensions.ts: -------------------------------------------------------------------------------- 1 | module ts { 2 | export function syntaxKindToName(kind: ts.SyntaxKind): string { 3 | return (ts).SyntaxKind[kind]; 4 | } 5 | } 6 | if (typeof global !== "undefined") { 7 | (global as any).ts = ts; 8 | } 9 | if (typeof window !== "undefined") { 10 | (window as any).ts = ts; 11 | } 12 | -------------------------------------------------------------------------------- /code/compiler/node_modules/ntypescript/extensions/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.5.0-beta", 3 | "compilerOptions": { 4 | "target": "es5", 5 | "module": "commonjs", 6 | "isolatedModules": false, 7 | "jsx": "react", 8 | "experimentalDecorators": true, 9 | "emitDecoratorMetadata": true, 10 | "declaration": true, 11 | "noImplicitAny": false, 12 | "removeComments": true, 13 | "noLib": false, 14 | "preserveConstEnums": true, 15 | "suppressImplicitAnyIndexErrors": true 16 | }, 17 | "filesGlob": [ 18 | "./**/*.ts", 19 | "./**/*.tsx", 20 | "!./node_modules/**/*", 21 | "../bin/typescriptServices.d.ts", 22 | "!./extensions.d.ts", 23 | "!./addExtensions.d.ts" 24 | ], 25 | "files": [ 26 | "./addExtensions.ts", 27 | "./extensions.ts", 28 | "../bin/typescriptServices.d.ts" 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /code/compiler/node_modules/ntypescript/kicktravis: -------------------------------------------------------------------------------- 1 | 2015-07-14 [ci skip] Version: 1.201507141013.1+649e40b1711096de54eb325a702597d3ee62e9ef 2 | -------------------------------------------------------------------------------- /code/compiler/node_modules/ntypescript/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ntypescript", 3 | "version": "1.201507141013.1", 4 | "description": "Latest code from microsoft/typescript packaged and released", 5 | "main": "./bin/ntypescript.js", 6 | "bin": { 7 | "ntsc": "./bin/tsc", 8 | "ntsserver": "./bin/tsserver", 9 | "ntse": "./bin/tse" 10 | }, 11 | "typescript": { 12 | "definition": "./bin/ntypescript.d.ts" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "git+https://github.com/basarat/ntypescript.git" 17 | }, 18 | "keywords": [ 19 | "typescript", 20 | "gruntplugin" 21 | ], 22 | "author": { 23 | "name": "basaratali@gmail.com" 24 | }, 25 | "license": "MIT", 26 | "bugs": { 27 | "url": "https://github.com/basarat/ntypescript/issues" 28 | }, 29 | "homepage": "https://github.com/basarat/ntypescript#readme", 30 | "devDependencies": { 31 | "grunt": "^0.4.5" 32 | }, 33 | "gitHead": "d14e0bfcc2679bd611f94358d838782477c61a07", 34 | "_id": "ntypescript@1.201507141013.1", 35 | "scripts": {}, 36 | "_shasum": "62c6d9cc066383a6e5709ae7c879948de060dcfc", 37 | "_from": "ntypescript@1.201507141013.1", 38 | "_npmVersion": "2.12.1", 39 | "_nodeVersion": "2.3.4", 40 | "_npmUser": { 41 | "name": "basarat", 42 | "email": "basaratali@gmail.com" 43 | }, 44 | "maintainers": [ 45 | { 46 | "name": "basarat", 47 | "email": "basaratali@gmail.com" 48 | } 49 | ], 50 | "dist": { 51 | "shasum": "62c6d9cc066383a6e5709ae7c879948de060dcfc", 52 | "tarball": "http://registry.npmjs.org/ntypescript/-/ntypescript-1.201507141013.1.tgz" 53 | }, 54 | "directories": {}, 55 | "_resolved": "https://registry.npmjs.org/ntypescript/-/ntypescript-1.201507141013.1.tgz", 56 | "readme": "ERROR: No README data found!" 57 | } 58 | -------------------------------------------------------------------------------- /code/compiler/node_modules/ntypescript/prepare.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | 5 | git submodule update --recursive --init 6 | 7 | # Official Microsoft/TypeScript clone 8 | typeScriptDirectory='./TypeScript' 9 | 10 | cd $typeScriptDirectory 11 | 12 | git clean -xfd 13 | git fetch origin 14 | git reset --hard origin/master 15 | 16 | # Fix jakefile to expose the internal APIs to service 17 | < Jakefile.js > Jakefile.new.js sed -E "s/\*stripInternal\*\/ true/\*stripInternal\*\/ false/" 18 | mv Jakefile.new.js Jakefile.js 19 | 20 | # Install jake 21 | npm install jake 22 | 23 | # Build once with LKG 24 | ./node_modules/.bin/jake release tsc --trace 25 | cp ./built/local/* ./bin/ 26 | 27 | # Rebuild with itself 28 | ./node_modules/.bin/jake release clean local --trace 29 | 30 | # Copy output 31 | cp ./built/local/* ./bin/tsc ./bin/tsserver ../bin/ 32 | 33 | # Reset sub typescript 34 | git reset --hard origin/master 35 | 36 | # add custom extension 37 | node ../extensions/addExtensions.js 38 | -------------------------------------------------------------------------------- /code/compiler/node_modules/ntypescript/quick.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | ./prepare.sh 6 | 7 | ./release.sh 8 | 9 | npm publish -------------------------------------------------------------------------------- /code/compiler/node_modules/ntypescript/register.js: -------------------------------------------------------------------------------- 1 | /// 2 | var t = require('./bin/typescript.js'); 3 | var fileExtension = ['.ts', '.tsx']; 4 | exports.isTypeScript = function (file) { return /\.(ts|tsx)$/.test(file); }; 5 | var fs = require('fs'); 6 | function loadFile(module, filename) { 7 | var js = t.transpile(fs.readFileSync(filename, 'utf8')); 8 | module._compile(js, filename); 9 | } 10 | exports.loadFile = loadFile; 11 | if (require.extensions) { 12 | for (var _i = 0; _i < fileExtension.length; _i++) { 13 | var ext = fileExtension[_i]; 14 | require.extensions[ext] = loadFile; 15 | } 16 | } 17 | var child_process = require('child_process'); 18 | if (child_process) { 19 | var fork = child_process.fork; 20 | var binary = require.resolve('./bin/tse'); 21 | child_process.fork = function (path, args, options) { 22 | if (exports.isTypeScript(path)) { 23 | if (!Array.isArray(args)) { 24 | options = args || {}; 25 | args = []; 26 | } 27 | args = [path].concat(args); 28 | path = binary; 29 | } 30 | fork(path, args, options); 31 | }; 32 | } 33 | -------------------------------------------------------------------------------- /code/compiler/node_modules/ntypescript/register.ts: -------------------------------------------------------------------------------- 1 | /// 2 | var t: typeof ts = require('./bin/typescript.js'); 3 | 4 | /** Determine if a filename represents a TypeScript file. */ 5 | var fileExtension = ['.ts', '.tsx']; 6 | export var isTypeScript = (file) => /\.(ts|tsx)$/.test(file); 7 | 8 | /** Load and runt TypeScript for Node */ 9 | import fs = require('fs'); 10 | export function loadFile(module, filename) { 11 | var js = t.transpile(fs.readFileSync(filename,'utf8')); 12 | module._compile(js, filename); 13 | } 14 | 15 | /** If the installed version of Node supports require.extensions, register TypeScript as an extension. */ 16 | if (require.extensions) { 17 | for (var ext of fileExtension) { 18 | require.extensions[ext] = loadFile; 19 | } 20 | } 21 | 22 | /** If we’re on Node, patch child_process.fork so that TypeScript is able to fork both TypeScript files, and JavaScript files, directly. */ 23 | import child_process = require('child_process'); 24 | if (child_process) { 25 | var {fork} = child_process; 26 | var binary = require.resolve('./bin/tse'); 27 | child_process.fork = function(path, args?, options?) { 28 | if (isTypeScript(path)) { 29 | if (!Array.isArray(args)) { 30 | options = args || {} 31 | args = [] 32 | } 33 | args = [path].concat(args) 34 | path = binary 35 | } 36 | fork(path, args, options) 37 | } 38 | } -------------------------------------------------------------------------------- /code/compiler/node_modules/ntypescript/release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | # Get the git commit hash 5 | typeScriptDirectory='./TypeScript' 6 | cd $typeScriptDirectory 7 | commitHash=`git rev-parse HEAD` 8 | cd .. 9 | 10 | # Version of this script 11 | toolsVersion="1" 12 | 13 | commitVersion="1.$(date +%Y%m%d%H%M).$toolsVersion+$commitHash" 14 | commitName="$(date +%Y-%m-%d) [ci skip] Version: $commitVersion" 15 | 16 | # Kick travis 17 | echo $commitName > kicktravis 18 | 19 | # Update package.json 20 | < package.json > package.json.new sed -E "s/(\s+\"version\": \")[^\"]+(\",)/\1$commitVersion\2/" 21 | mv package.json.new package.json 22 | echo "Adding to git" 23 | git add -A 24 | git checkout master 25 | git status 26 | 27 | # Commit,tag,push,publish 28 | echo "Committing" 29 | git commit -m "$commitName" 30 | git merge HEAD@{1} 31 | echo "Pushing commit" 32 | git push 33 | 34 | echo "Tagging" 35 | git tag $commitVersion 36 | echo "Pushing tags" 37 | git push --tags 38 | -------------------------------------------------------------------------------- /code/compiler/node_modules/ntypescript/tasks/ntypescript.js: -------------------------------------------------------------------------------- 1 | /* 2 | * ntypescript 3 | * https://github.com/basarat/ntypescript 4 | * 5 | * Copyright (c) 2015 Basarat Syed 6 | * Licensed under the MIT license. 7 | */ 8 | var path = require("path"); 9 | function gruntPlugin(grunt) { 10 | grunt.registerMultiTask('ntypescript', 'TypeScript grunt plugin', function () { 11 | var options = { 12 | project: '.', 13 | }; 14 | options = this.options(options); 15 | if (!options.project) { 16 | console.error('tsconfig must be specified using options'); 17 | return false; 18 | } 19 | var project = path.resolve(options.project); 20 | var args = [__dirname + '/../bin/tsc', '-p', project]; 21 | var done = this.async(); 22 | grunt.util.spawn({ 23 | cmd: process.execPath, 24 | args: args 25 | }, function (error, result, code) { 26 | console.log(result.stdout || result.stderr); 27 | done(!code); 28 | }); 29 | }); 30 | } 31 | ; 32 | module.exports = gruntPlugin; 33 | -------------------------------------------------------------------------------- /code/compiler/node_modules/ntypescript/tasks/ntypescript.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * ntypescript 3 | * https://github.com/basarat/ntypescript 4 | * 5 | * Copyright (c) 2015 Basarat Syed 6 | * Licensed under the MIT license. 7 | */ 8 | 9 | import * as path from "path"; 10 | 11 | function gruntPlugin(grunt) { 12 | grunt.registerMultiTask('ntypescript', 'TypeScript grunt plugin', function() { 13 | // Merge task-specific and/or target-specific options with these defaults. 14 | var options = { 15 | project: '.', 16 | }; 17 | options = this.options(options); 18 | 19 | if (!options.project) { 20 | console.error('tsconfig must be specified using options'); 21 | return false; 22 | } 23 | 24 | const project: string = path.resolve(options.project); 25 | const args = [__dirname + '/../bin/tsc', '-p', project]; 26 | // console.log(args); // Debug 27 | 28 | var done = this.async(); 29 | grunt.util.spawn({ 30 | cmd: process.execPath, 31 | args: args 32 | }, (error, result, code: number) => { 33 | console.log(result.stdout || result.stderr); 34 | done(!code); 35 | }); 36 | }); 37 | }; 38 | 39 | export = gruntPlugin; -------------------------------------------------------------------------------- /code/compiler/node_modules/ntypescript/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.5.0-alpha", 3 | "compilerOptions": { 4 | "target": "es5", 5 | "module": "commonjs", 6 | "jsx": "react", 7 | "declaration": false, 8 | "noImplicitAny": false, 9 | "removeComments": true, 10 | "noLib": false, 11 | "preserveConstEnums": true, 12 | "suppressImplicitAnyIndexErrors": true 13 | }, 14 | "filesGlob": [ 15 | "./**/*.ts", 16 | "./**/*.tsx", 17 | "!./bin/**/*", 18 | "!./TypeScript/**/*", 19 | "!./node_modules/**/*", 20 | "!./tests/grunt/**/*.ts" 21 | ], 22 | "files": [ 23 | "./extensions/addExtensions.d.ts", 24 | "./extensions/addExtensions.ts", 25 | "./extensions/extensions.d.ts", 26 | "./extensions/extensions.ts", 27 | "./register.ts", 28 | "./tasks/ntypescript.ts", 29 | "./tests/tse/1start.ts", 30 | "./tests/tse/2iwillfork.ts", 31 | "./tests/tse/3iwilllogargs.ts", 32 | "./tse.ts", 33 | "./typings/gruntjs/gruntjs.d.ts", 34 | "./typings/node/node.d.ts", 35 | "./typings/tsd.d.ts" 36 | ] 37 | } 38 | -------------------------------------------------------------------------------- /code/compiler/node_modules/ntypescript/tsd.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "v4", 3 | "repo": "borisyankov/DefinitelyTyped", 4 | "ref": "master", 5 | "path": "typings", 6 | "bundle": "typings/tsd.d.ts", 7 | "installed": { 8 | "node/node.d.ts": { 9 | "commit": "c7b1128cc9a8f5797bade826e7632b36b06a856c" 10 | }, 11 | "gruntjs/gruntjs.d.ts": { 12 | "commit": "c7b1128cc9a8f5797bade826e7632b36b06a856c" 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /code/compiler/node_modules/ntypescript/tse.js: -------------------------------------------------------------------------------- 1 | /// 2 | var t = require('./bin/typescript.js'); 3 | var node = process.argv[0]; 4 | var script = process.argv[2]; 5 | process.argv = [node].concat(process.argv.slice(2)); 6 | if (!script) { 7 | process.exit(0); 8 | } 9 | var fs = require('fs'); 10 | var jsContent = t.transpile(fs.readFileSync(script, 'utf8')); 11 | var dir = fs.realpathSync('.'); 12 | var mainModule = require.main; 13 | mainModule.paths = require('module')._nodeModulePaths(dir); 14 | mainModule._compile(jsContent, mainModule.filename); 15 | -------------------------------------------------------------------------------- /code/compiler/node_modules/ntypescript/tse.ts: -------------------------------------------------------------------------------- 1 | // This transpiles the file and then executes it 2 | /// 3 | var t: typeof ts = require('./bin/typescript.js'); 4 | var node = process.argv[0]; 5 | var script = process.argv[2]; 6 | // Remove `tse` from the argv 7 | process.argv = [node].concat(process.argv.slice(2)); 8 | 9 | if (!script) { 10 | process.exit(0); 11 | } 12 | 13 | // Register globally: 14 | import register = require("./register"); 15 | 16 | 17 | import vm = require('vm'); 18 | import fs = require('fs'); 19 | import path = require('path'); 20 | var jsContent = t.transpile(fs.readFileSync(script, 'utf8')); 21 | 22 | // https://github.com/jashkenas/coffeescript/blob/master/lib/coffee-script/command.js#L114 23 | // `compilePath` triggered because of `opts.run` 24 | // Then : https://github.com/jashkenas/coffeescript/blob/342b395b0a7c135dfea1fe5f66fa536794d114fe/src/coffee-script.coffee#L109 25 | 26 | // Assign paths for node_modules loading 27 | var dir = fs.realpathSync('.'); 28 | var mainModule = require.main; 29 | mainModule.paths = require('module')._nodeModulePaths(dir); 30 | mainModule._compile(jsContent, mainModule.filename); 31 | 32 | 33 | -------------------------------------------------------------------------------- /code/compiler/node_modules/ntypescript/typings/tsd.d.ts: -------------------------------------------------------------------------------- 1 | 2 | /// 3 | /// 4 | -------------------------------------------------------------------------------- /code/compiler/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "compiler", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "runScanner.js", 6 | "dependencies": { 7 | "ntypescript": "1.201507141013.1" 8 | }, 9 | "devDependencies": {}, 10 | "scripts": { 11 | "test": "echo \"Error: no test specified\" && exit 1" 12 | }, 13 | "author": "", 14 | "license": "ISC" 15 | } 16 | -------------------------------------------------------------------------------- /code/compiler/parser/runParser.js: -------------------------------------------------------------------------------- 1 | var ts = require("ntypescript"); 2 | function printAllChildren(node, depth) { 3 | if (depth === void 0) { depth = 0; } 4 | console.log(new Array(depth + 1).join('----'), ts.syntaxKindToName(node.kind), node.pos, node.end); 5 | depth++; 6 | node.getChildren().forEach(function (c) { return printAllChildren(c, depth); }); 7 | } 8 | var sourceCode = "\nvar foo = 123;\n".trim(); 9 | var sourceFile = ts.createSourceFile('foo.ts', sourceCode, 1, true); 10 | printAllChildren(sourceFile); 11 | -------------------------------------------------------------------------------- /code/compiler/parser/runParser.ts: -------------------------------------------------------------------------------- 1 | import * as ts from "ntypescript"; 2 | 3 | function printAllChildren(node: ts.Node, depth = 0) { 4 | console.log(new Array(depth + 1).join('----'), ts.syntaxKindToName(node.kind), node.pos, node.end); 5 | depth++; 6 | node.getChildren().forEach(c=> printAllChildren(c, depth)); 7 | } 8 | 9 | var sourceCode = ` 10 | var foo = 123; 11 | `.trim(); 12 | 13 | var sourceFile = ts.createSourceFile('foo.ts', sourceCode, ts.ScriptTarget.ES5, true); 14 | printAllChildren(sourceFile); -------------------------------------------------------------------------------- /code/compiler/scanner/runScanner.js: -------------------------------------------------------------------------------- 1 | var ts = require("ntypescript"); 2 | var scanner = ts.createScanner(2, true); 3 | function initializeState(text) { 4 | scanner.setText(text); 5 | scanner.setOnError(function (message, length) { 6 | console.error(message); 7 | }); 8 | scanner.setScriptTarget(1); 9 | scanner.setLanguageVariant(0); 10 | } 11 | initializeState("\nvar foo = 123;\n".trim()); 12 | var token = scanner.scan(); 13 | while (token != 1) { 14 | console.log(ts.syntaxKindToName(token)); 15 | token = scanner.scan(); 16 | } 17 | -------------------------------------------------------------------------------- /code/compiler/scanner/runScanner.ts: -------------------------------------------------------------------------------- 1 | import * as ts from "ntypescript"; 2 | 3 | // TypeScript has a singelton scanner 4 | const scanner = ts.createScanner(ts.ScriptTarget.Latest, /*skipTrivia*/ true); 5 | 6 | // That is initialized using a function `initializeState` similar to 7 | function initializeState(text: string) { 8 | scanner.setText(text); 9 | scanner.setOnError((message: ts.DiagnosticMessage, length: number) => { 10 | console.error(message); 11 | }); 12 | scanner.setScriptTarget(ts.ScriptTarget.ES5); 13 | scanner.setLanguageVariant(ts.LanguageVariant.Standard); 14 | } 15 | 16 | // Sample usage 17 | initializeState(` 18 | var foo = 123; 19 | `.trim()); 20 | 21 | // Start the scanning 22 | var token = scanner.scan(); 23 | while (token != ts.SyntaxKind.EndOfFileToken) { 24 | console.log(ts.syntaxKindToName(token)); 25 | token = scanner.scan(); 26 | } 27 | -------------------------------------------------------------------------------- /code/compiler/scanner/runScannerWithPositions.js: -------------------------------------------------------------------------------- 1 | var ts = require("ntypescript"); 2 | var scanner = ts.createScanner(2, true); 3 | function initializeState(text) { 4 | scanner.setText(text); 5 | scanner.setOnError(function (message, length) { 6 | console.error(message); 7 | }); 8 | scanner.setScriptTarget(1); 9 | scanner.setLanguageVariant(0); 10 | } 11 | initializeState("\nvar foo = 123;\n".trim()); 12 | var token = scanner.scan(); 13 | while (token != 1) { 14 | var currentToken = ts.syntaxKindToName(token); 15 | var tokenStart = scanner.getStartPos(); 16 | token = scanner.scan(); 17 | var tokenEnd = scanner.getStartPos(); 18 | console.log(currentToken, tokenStart, tokenEnd); 19 | } 20 | -------------------------------------------------------------------------------- /code/compiler/scanner/runScannerWithPositions.ts: -------------------------------------------------------------------------------- 1 | import * as ts from "ntypescript"; 2 | 3 | // TypeScript has a singelton scanner 4 | const scanner = ts.createScanner(ts.ScriptTarget.Latest, /*skipTrivia*/ true); 5 | 6 | // That is initialized using a function `initializeState` similar to 7 | function initializeState(text: string) { 8 | scanner.setText(text); 9 | scanner.setOnError((message: ts.DiagnosticMessage, length: number) => { 10 | console.error(message); 11 | }); 12 | scanner.setScriptTarget(ts.ScriptTarget.ES5); 13 | scanner.setLanguageVariant(ts.LanguageVariant.Standard); 14 | } 15 | 16 | // Sample usage 17 | initializeState(` 18 | var foo = 123; 19 | `.trim()); 20 | 21 | // Start the scanning 22 | var token = scanner.scan(); 23 | while (token != ts.SyntaxKind.EndOfFileToken) { 24 | let currentToken = ts.syntaxKindToName(token); 25 | let tokenStart = scanner.getStartPos(); 26 | token = scanner.scan(); 27 | let tokenEnd = scanner.getStartPos(); 28 | console.log(currentToken, tokenStart, tokenEnd); 29 | } 30 | -------------------------------------------------------------------------------- /code/compiler/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.5.0-beta", 3 | "compilerOptions": { 4 | "target": "es5", 5 | "module": "commonjs", 6 | "isolatedModules": false, 7 | "jsx": "react", 8 | "experimentalDecorators": true, 9 | "emitDecoratorMetadata": true, 10 | "declaration": false, 11 | "noImplicitAny": false, 12 | "removeComments": true, 13 | "noLib": false, 14 | "preserveConstEnums": true, 15 | "suppressImplicitAnyIndexErrors": true 16 | }, 17 | "filesGlob": [ 18 | "./**/*.ts", 19 | "./**/*.tsx", 20 | "!./node_modules/**/*" 21 | ], 22 | "files": [ 23 | "./parser/runParser.ts", 24 | "./scanner/runScanner.ts", 25 | "./scanner/runScannerWithPositions.ts", 26 | "./typings/node/node.d.ts", 27 | "./typings/tsd.d.ts" 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /code/compiler/tsd.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "v4", 3 | "repo": "borisyankov/DefinitelyTyped", 4 | "ref": "master", 5 | "path": "typings", 6 | "bundle": "typings/tsd.d.ts", 7 | "installed": { 8 | "node/node.d.ts": { 9 | "commit": "38c6ccfde0e67ff10d7408e0ee8b7720b3f21d3b" 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /code/compiler/typings/tsd.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /code/declarationspaces/declarationspace.js: -------------------------------------------------------------------------------- 1 | var first; 2 | (function (first) { 3 | var Foo = (function () { 4 | function Foo() { 5 | } 6 | return Foo; 7 | })(); 8 | var foo; 9 | var bar; 10 | var bas; 11 | })(first = exports.first || (exports.first = {})); 12 | var second; 13 | (function (second) { 14 | ; 15 | var bar = Bar; 16 | })(second || (second = {})); 17 | var third; 18 | (function (third) { 19 | var Foo = (function () { 20 | function Foo() { 21 | } 22 | return Foo; 23 | })(); 24 | var someVar = Foo; 25 | var someOtherVar = 123; 26 | })(third || (third = {})); 27 | var fourn; 28 | (function (fourn) { 29 | var foo = 123; 30 | var bar; 31 | })(fourn || (fourn = {})); 32 | var meh; 33 | (function (meh) { 34 | var something = {}; 35 | })(meh || (meh = {})); 36 | var utility; 37 | (function (utility) { 38 | function log(msg) { 39 | console.log(msg); 40 | } 41 | utility.log = log; 42 | function error(msg) { 43 | console.error(msg); 44 | } 45 | utility.error = error; 46 | })(utility || (utility = {})); 47 | utility.log('Call me'); 48 | utility.error('maybe!'); 49 | var importing; 50 | (function (importing) { 51 | var Foo = (function () { 52 | function Foo() { 53 | } 54 | return Foo; 55 | })(); 56 | var Bar = Foo; 57 | var bar; 58 | })(importing || (importing = {})); 59 | var importing; 60 | (function (importing) { 61 | var Foo = (function () { 62 | function Foo() { 63 | } 64 | return Foo; 65 | })(); 66 | importing.Foo = Foo; 67 | })(importing || (importing = {})); 68 | var Bar = importing.Foo; 69 | var bar; 70 | var typeofAnnotation; 71 | (function (typeofAnnotation) { 72 | var foo = 123; 73 | var bar; 74 | bar = 456; 75 | bar = '789'; 76 | })(typeofAnnotation || (typeofAnnotation = {})); 77 | -------------------------------------------------------------------------------- /code/declarationspaces/declarationspace.ts: -------------------------------------------------------------------------------- 1 | export module first { 2 | class Foo { } 3 | interface Bar { } 4 | type Bas = {} 5 | 6 | var foo: Foo; 7 | var bar: Bar; 8 | var bas: Bas; 9 | } 10 | 11 | namespace second { 12 | interface Bar { }; 13 | var bar = Bar; // ERROR: "cannot find name 'Bar'" 14 | } 15 | 16 | namespace third { 17 | class Foo { } 18 | var someVar = Foo; 19 | var someOtherVar = 123; 20 | } 21 | 22 | namespace fourn { 23 | var foo = 123; 24 | var bar: foo; // ERROR: "cannot find name 'foo'" 25 | } 26 | 27 | 28 | namespace meh { 29 | var something = {}; 30 | // (function(something) { 31 | // something.foo = 123; 32 | // })(something || something = {}) 33 | } 34 | 35 | namespace utility { 36 | export function log(msg) { 37 | console.log(msg); 38 | } 39 | export function error(msg) { 40 | console.error(msg); 41 | } 42 | } 43 | 44 | // usage 45 | utility.log('Call me'); 46 | utility.error('maybe!'); 47 | 48 | 49 | module importing { 50 | class Foo { } 51 | var Bar = Foo; 52 | var bar: Bar; // ERROR: "cannot find name 'Bar'" 53 | } 54 | 55 | namespace importing { 56 | export class Foo { } 57 | } 58 | 59 | import Bar = importing.Foo; 60 | var bar: Bar; // Okay 61 | 62 | namespace typeofAnnotation { 63 | var foo = 123; 64 | var bar: typeof foo; // `bar` has the same type as `foo` (here `number`) 65 | bar = 456; // Okay 66 | bar = '789'; // ERROR: Type `string` is not `assignable` to type `number` 67 | } -------------------------------------------------------------------------------- /code/dynamic-import-expressions/dynamicImportExpression.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | function myApp() { 3 | import(/* webpackChunkName: "momentjs" */ "moment") 4 | .then(function (moment) { 5 | // lazyModule has all of the proper types, autocomplete works, 6 | // type checking works, code references work \o/ 7 | var time = moment().format(); 8 | console.log("TypeScript >= 2.4.0 Dynamic Import Expression:"); 9 | console.log(time); 10 | }) 11 | .catch(function (err) { 12 | console.log("Failed to load moment", err); 13 | }); 14 | } 15 | -------------------------------------------------------------------------------- /code/dynamic-import-expressions/dynamicImportExpression.ts: -------------------------------------------------------------------------------- 1 | 2 | function myApp() { 3 | import(/* webpackChunkName: "momentjs" */ "moment") 4 | .then((moment) => { 5 | // lazyModule has all of the proper types, autocomplete works, 6 | // type checking works, code references work \o/ 7 | const time = moment().format(); 8 | console.log("TypeScript >= 2.4.0 Dynamic Import Expression:"); 9 | console.log(time); 10 | }) 11 | .catch((err) => { 12 | console.log("Failed to load moment", err); 13 | }); 14 | } 15 | -------------------------------------------------------------------------------- /code/dynamic-import-expressions/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dynamic-import-expressions", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "dynamicImportExpression.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "Jose Quinto Zamora - https://blog.josequinto.com", 10 | "license": "ISC", 11 | "devDependencies": { 12 | "typescript": "^2.4.1" 13 | }, 14 | "dependencies": { 15 | "moment": "^2.18.1" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /code/dynamic-import-expressions/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "esnext", 5 | "lib": [ 6 | "dom", 7 | "es5", 8 | "scripthost", 9 | "es2015.promise" 10 | ], 11 | "strict": true, 12 | "moduleResolution": "node" 13 | }, 14 | "files": [ 15 | "./dynamicImportExpression.ts" 16 | ] 17 | } -------------------------------------------------------------------------------- /code/errors/common-errors.ts: -------------------------------------------------------------------------------- 1 | ga(); 2 | 3 | import {debounce} from "underscore"; 4 | -------------------------------------------------------------------------------- /code/errors/interpreting-errors.ts: -------------------------------------------------------------------------------- 1 | export const module = 123; 2 | 3 | type SomethingComplex = { 4 | foo: number, 5 | bar: string 6 | } 7 | function takeSomethingComplex(arg: SomethingComplex) { 8 | } 9 | function getBar(): string { 10 | return 'some bar'; 11 | } 12 | 13 | ////////////////////////////////// 14 | // Example error production 15 | ////////////////////////////////// 16 | const fail = { 17 | foo: 123, 18 | bar: getBar 19 | }; 20 | 21 | takeSomethingComplex(fail); // TS ERROR HAPPENS HERE 22 | -------------------------------------------------------------------------------- /code/errors/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "noEmit": true 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /code/es6/classes/abstract.js: -------------------------------------------------------------------------------- 1 | exports.foo = 123; 2 | var Restable = (function () { 3 | function Restable() { 4 | this.abstract = toJSON(); 5 | } 6 | return Restable; 7 | })(); 8 | -------------------------------------------------------------------------------- /code/es6/classes/abstract.ts: -------------------------------------------------------------------------------- 1 | export var foo = 123; 2 | 3 | class Restable { 4 | abstract toJSON() : any; 5 | } 6 | 7 | -------------------------------------------------------------------------------- /code/es6/classes/class.js: -------------------------------------------------------------------------------- 1 | var __extends = this.__extends || function (d, b) { 2 | for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; 3 | function __() { this.constructor = d; } 4 | __.prototype = b.prototype; 5 | d.prototype = new __(); 6 | }; 7 | var Point = (function () { 8 | function Point(x, y) { 9 | this.x = x; 10 | this.y = y; 11 | } 12 | Point.prototype.add = function (point) { 13 | return new Point(this.x + point.x, this.y + point.y); 14 | }; 15 | return Point; 16 | })(); 17 | var p1 = new Point(0, 10); 18 | var p2 = new Point(10, 20); 19 | var p3 = p1.add(p2); 20 | var Point3D = (function (_super) { 21 | __extends(Point3D, _super); 22 | function Point3D(x, y, z) { 23 | _super.call(this, x, y); 24 | this.z = z; 25 | } 26 | Point3D.prototype.add = function (point) { 27 | var point2D = _super.prototype.add.call(this, point); 28 | return new Point3D(point2D.x, point2D.y, this.z + point.z); 29 | }; 30 | return Point3D; 31 | })(Point); 32 | var Something = (function () { 33 | function Something() { 34 | Something.instances++; 35 | } 36 | Something.instances = 0; 37 | return Something; 38 | })(); 39 | var s1 = new Something(); 40 | var s2 = new Something(); 41 | console.log(Something.instances); 42 | -------------------------------------------------------------------------------- /code/es6/classes/class.ts: -------------------------------------------------------------------------------- 1 | class Point { 2 | x: number; 3 | y: number; 4 | constructor(x: number, y: number) { 5 | this.x = x; 6 | this.y = y; 7 | } 8 | add(point: Point) { 9 | return new Point(this.x + point.x, this.y + point.y); 10 | } 11 | } 12 | 13 | var p1 = new Point(0, 10); 14 | var p2 = new Point(10, 20); 15 | var p3 = p1.add(p2); // {x:10,y:30} 16 | 17 | class Point3D extends Point { 18 | z: number; 19 | constructor(x: number, y: number, z: number) { 20 | super(x, y); 21 | this.z = z; 22 | } 23 | add(point: Point3D) { 24 | var point2D = super.add(point); 25 | return new Point3D(point2D.x, point2D.y, this.z + point.z); 26 | } 27 | } 28 | 29 | class Something { 30 | static instances = 0; 31 | constructor() { 32 | Something.instances++; 33 | } 34 | } 35 | 36 | var s1 = new Something(); 37 | var s2 = new Something(); 38 | console.log(Something.instances); // 2 39 | -------------------------------------------------------------------------------- /code/es6/classes/super.js: -------------------------------------------------------------------------------- 1 | var __extends = (this && this.__extends) || function (d, b) { 2 | for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; 3 | function __() { this.constructor = d; } 4 | d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); 5 | }; 6 | exports.foo = 123; 7 | var asdf; 8 | (function (asdf) { 9 | var Base = (function () { 10 | function Base() { 11 | } 12 | Base.prototype.log = function () { console.log('hello world'); }; 13 | return Base; 14 | })(); 15 | var Child = (function (_super) { 16 | __extends(Child, _super); 17 | function Child() { 18 | _super.apply(this, arguments); 19 | } 20 | Child.prototype.logWorld = function () { _super.prototype.log.call(this); }; 21 | ; 22 | return Child; 23 | })(Base); 24 | })(asdf || (asdf = {})); 25 | var bse; 26 | (function (bse) { 27 | var Base = (function () { 28 | function Base() { 29 | this.log = function () { console.log('hello world'); }; 30 | } 31 | return Base; 32 | })(); 33 | var Child = (function (_super) { 34 | __extends(Child, _super); 35 | function Child() { 36 | _super.apply(this, arguments); 37 | } 38 | Child.prototype.logWorld = function () { this.log(); }; 39 | ; 40 | return Child; 41 | })(Base); 42 | })(bse || (bse = {})); 43 | var quz; 44 | (function (quz) { 45 | var Base = (function () { 46 | function Base() { 47 | this.log = function () { console.log('hello world'); }; 48 | } 49 | return Base; 50 | })(); 51 | var Child = (function (_super) { 52 | __extends(Child, _super); 53 | function Child() { 54 | _super.apply(this, arguments); 55 | } 56 | Child.prototype.logWorld = function () { _super.prototype.log.call(this); }; 57 | ; 58 | return Child; 59 | })(Base); 60 | })(quz || (quz = {})); 61 | -------------------------------------------------------------------------------- /code/es6/classes/super.ts: -------------------------------------------------------------------------------- 1 | export var foo = 123; 2 | 3 | module asdf { 4 | class Base { 5 | log() { console.log('hello world'); } 6 | } 7 | 8 | class Child extends Base { 9 | logWorld() { super.log() }; 10 | } 11 | } 12 | 13 | module bse { 14 | class Base { 15 | log = () => { console.log('hello world'); } 16 | } 17 | 18 | class Child extends Base { 19 | logWorld() { this.log() }; 20 | } 21 | } 22 | 23 | module quz { 24 | class Base { 25 | log = () => { console.log('hello world'); } 26 | } 27 | 28 | class Child extends Base { 29 | logWorld() { super.log() }; // ERROR : only `public` and `protected` methods of base class are accessible via `super` 30 | } 31 | } -------------------------------------------------------------------------------- /code/es6/classes/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.4.1", 3 | "compilerOptions": { 4 | "target": "es5", 5 | "module": "commonjs", 6 | "declaration": false, 7 | "noImplicitAny": false, 8 | "removeComments": true, 9 | "noLib": false 10 | }, 11 | "filesGlob": [ 12 | "./**/*.ts", 13 | "!./node_modules/**/*.ts" 14 | ], 15 | "files": [ 16 | "./abstract.ts", 17 | "./class.ts", 18 | "./super.ts" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /code/es6/const.js: -------------------------------------------------------------------------------- 1 | exports.asdfasdfasfadf = 123; 2 | var mustbeinit; 3 | (function (mustbeinit) { 4 | var foo; 5 | })(mustbeinit || (mustbeinit = {})); 6 | var cantbechanged; 7 | (function (cantbechanged) { 8 | var foo = 123; 9 | foo = 456; 10 | })(cantbechanged || (cantbechanged = {})); 11 | var block; 12 | (function (block) { 13 | var foo = 123; 14 | if (true) { 15 | var foo_1 = 456; 16 | } 17 | })(block || (block = {})); 18 | var protectvariablereference; 19 | (function (protectvariablereference) { 20 | var foo = { bar: 123 }; 21 | foo = { bar: 456 }; 22 | })(protectvariablereference || (protectvariablereference = {})); 23 | var noProtectDeep; 24 | (function (noProtectDeep) { 25 | var foo = { bar: 123 }; 26 | foo.bar = 456; 27 | })(noProtectDeep || (noProtectDeep = {})); 28 | -------------------------------------------------------------------------------- /code/es6/const.ts: -------------------------------------------------------------------------------- 1 | export var asdfasdfasfadf = 123; 2 | 3 | 4 | namespace mustbeinit { 5 | const foo; 6 | } 7 | 8 | namespace cantbechanged { 9 | const foo = 123; 10 | foo = 456; 11 | } 12 | 13 | 14 | namespace block { 15 | const foo = 123; 16 | if (true) { 17 | const foo = 456; // Allowed as its a new variable limited to this `if` block 18 | } 19 | } 20 | 21 | 22 | namespace protectvariablereference { 23 | const foo = { bar: 123 }; 24 | foo = { bar: 456 }; // ERROR : Left hand side of an assignment expression cannot be a constant 25 | } 26 | 27 | 28 | namespace noProtectDeep { 29 | const foo = { bar: 123 }; 30 | foo.bar = 456; // Allowed! 31 | } 32 | -------------------------------------------------------------------------------- /code/es6/destructuring.js: -------------------------------------------------------------------------------- 1 | exports.destructuring = true; 2 | var m1; 3 | (function (m1) { 4 | var x = 1, y = 2; 5 | _a = [ 6 | y, 7 | x 8 | ], x = _a[0], y = _a[1]; 9 | console.log(x, y); 10 | var _a; 11 | })(m1 || (m1 = {})); 12 | var m2; 13 | (function (m2) { 14 | var rect = { 15 | x: 0, 16 | y: 10, 17 | width: 15, 18 | height: 20 19 | }; 20 | var x = rect.x, y = rect.y, width = rect.width, height = rect.height; 21 | console.log(x, y, width, height); 22 | })(m2 || (m2 = {})); 23 | var m3; 24 | (function (m3) { 25 | var _a = [ 26 | 1, 27 | 2, 28 | 3, 29 | 4 30 | ], x = _a[0], y = _a[1], remaining = _a.slice(2); 31 | console.log(x, y, remaining); 32 | })(m3 || (m3 = {})); 33 | var m3; 34 | (function (m3) { 35 | var _a = [ 36 | 1, 37 | 2, 38 | 3, 39 | 4 40 | ], x = _a[0], remaining = _a.slice(2); 41 | console.log(x, remaining); 42 | })(m3 || (m3 = {})); 43 | -------------------------------------------------------------------------------- /code/es6/destructuring.ts: -------------------------------------------------------------------------------- 1 | export var destructuring = true; 2 | 3 | 4 | module m1 { 5 | var x = 1, y = 2; 6 | [x, y] = [y, x]; 7 | console.log(x, y); // 1,2 8 | } 9 | 10 | module m2 { 11 | var rect = { x: 0, y: 10, width: 15, height: 20 }; 12 | var {x, y, width, height} = rect; 13 | console.log(x, y, width, height); // 0,10,15,20 14 | } 15 | 16 | module m3 { 17 | var [x, y, ...remaining] = [1, 2, 3, 4]; 18 | console.log(x, y, remaining); // 1, 2, [3,4] 19 | } 20 | 21 | module m3 { 22 | var [x, , ...remaining] = [1, 2, 3, 4]; 23 | console.log(x, remaining); // 1, [3,4] 24 | } 25 | -------------------------------------------------------------------------------- /code/es6/enums.ts: -------------------------------------------------------------------------------- 1 | export const foo = 123; 2 | 3 | enum Color { 4 | Red, 5 | Green, 6 | Blue 7 | } 8 | 9 | enum Color { 10 | DarkRed = 3, 11 | DarkGreen, 12 | DarkBlue 13 | } 14 | 15 | var col = Color.Red; 16 | col = 0; // Effectively same as Color.Red 17 | 18 | 19 | enum Tristate { 20 | False, 21 | True, 22 | Unknown 23 | } 24 | 25 | var lie = Tristate.False; 26 | 27 | /*enum AnimalFlags { 28 | None = 0, 29 | HasClaws = 1 << 0, 30 | CanFly = 1 << 1, 31 | EatsFish = 1 << 2, 32 | Endangered = 1 << 3 33 | }*/ 34 | 35 | enum AnimalFlags { 36 | None = 0, 37 | HasClaws = 1 << 0, 38 | CanFly = 1 << 1, 39 | } 40 | 41 | function printAnimalAbilities(animal) { 42 | var animalFlags = animal.flags; 43 | if (animalFlags & AnimalFlags.HasClaws) { 44 | console.log('animal has claws'); 45 | } 46 | if (animalFlags & AnimalFlags.CanFly) { 47 | console.log('animal can fly'); 48 | } 49 | if (animalFlags == AnimalFlags.None){ 50 | console.log('nothing'); 51 | } 52 | } 53 | 54 | var animal = { flags: AnimalFlags.None }; 55 | printAnimalAbilities(animal); // nothing 56 | animal.flags |= AnimalFlags.HasClaws; 57 | printAnimalAbilities(animal); // animal has claws 58 | animal.flags &= ~AnimalFlags.HasClaws; 59 | printAnimalAbilities(animal); // nothing 60 | animal.flags |= AnimalFlags.HasClaws | AnimalFlags.CanFly; 61 | printAnimalAbilities(animal); // animal has claws, animal can fly 62 | 63 | 64 | namespace EnumsWithStatics { 65 | enum Weekday { 66 | Monday, 67 | Tuesday, 68 | Wednesday, 69 | Thursday, 70 | Friday, 71 | Saturday, 72 | Sunday 73 | } 74 | namespace Weekday { 75 | export function isBusinessDay(day: Weekday) { 76 | switch (day) { 77 | case Weekday.Saturday: 78 | case Weekday.Sunday: 79 | return false; 80 | default: 81 | return true; 82 | } 83 | } 84 | } 85 | 86 | const mon = Weekday.Monday; 87 | const sun = Weekday.Sunday; 88 | console.log(Weekday.isBusinessDay(mon)); // true 89 | console.log(Weekday.isBusinessDay(sun)); // false 90 | } 91 | -------------------------------------------------------------------------------- /code/es6/for..of.js: -------------------------------------------------------------------------------- 1 | exports.forof = true; 2 | var m0; 3 | (function (m0) { 4 | var someArray = [ 5 | 9, 6 | 2, 7 | 5 8 | ]; 9 | for (var item in someArray) { 10 | console.log(item); 11 | } 12 | })(m0 || (m0 = {})); 13 | var m1; 14 | (function (m1) { 15 | var someArray = [ 16 | 9, 17 | 2, 18 | 5 19 | ]; 20 | for (var _i = 0; _i < someArray.length; _i++) { 21 | var item = someArray[_i]; 22 | console.log(item); 23 | } 24 | })(m1 || (m1 = {})); 25 | var m2; 26 | (function (m2) { 27 | var hello = "is it me you're looking for?"; 28 | for (var _i = 0; _i < hello.length; _i++) { 29 | var char = hello[_i]; 30 | console.log(char); 31 | } 32 | })(m2 || (m2 = {})); 33 | var m2; 34 | (function (m2) { 35 | var articleParagraphs = document.querySelectorAll("article > p"); 36 | for (var _i = 0; _i < articleParagraphs.length; _i++) { 37 | var paragraph = articleParagraphs[_i]; 38 | paragraph.classList.add("read"); 39 | } 40 | })(m2 || (m2 = {})); 41 | -------------------------------------------------------------------------------- /code/es6/for..of.ts: -------------------------------------------------------------------------------- 1 | export var forof = true; 2 | 3 | module m0 { 4 | var someArray = [9, 2, 5]; 5 | for (var item in someArray) { 6 | console.log(item); 7 | } 8 | } 9 | 10 | module m1 { 11 | var someArray = [9, 2, 5]; 12 | for (var item of someArray) { 13 | console.log(item); 14 | } 15 | } 16 | 17 | module m2 { 18 | var hello = "is it me you're looking for?"; 19 | for (var char of hello) { 20 | console.log(char); // is it me you're looking for? 21 | } 22 | } 23 | 24 | module m2 { 25 | let articleParagraphs = document.querySelectorAll("article > p"); 26 | // Error: Nodelist is not an array type or a string type 27 | for (let paragraph of articleParagraphs) { 28 | paragraph.classList.add("read"); 29 | } 30 | } -------------------------------------------------------------------------------- /code/es6/forof.js: -------------------------------------------------------------------------------- 1 | exports.forof = true; 2 | var m0; 3 | (function (m0) { 4 | var someArray = [ 5 | 9, 6 | 2, 7 | 5 8 | ]; 9 | for (var item in someArray) { 10 | console.log(item); 11 | } 12 | })(m0 || (m0 = {})); 13 | var m1; 14 | (function (m1) { 15 | var someArray = [ 16 | 9, 17 | 2, 18 | 5 19 | ]; 20 | for (var _i = 0; _i < someArray.length; _i++) { 21 | var item = someArray[_i]; 22 | console.log(item); 23 | } 24 | })(m1 || (m1 = {})); 25 | var m2; 26 | (function (m2) { 27 | var hello = "is it me you're looking for?"; 28 | for (var _i = 0; _i < hello.length; _i++) { 29 | var char = hello[_i]; 30 | console.log(char); 31 | } 32 | })(m2 || (m2 = {})); 33 | var m2; 34 | (function (m2) { 35 | var articleParagraphs = document.querySelectorAll("article > p"); 36 | for (var _i = 0; _i < articleParagraphs.length; _i++) { 37 | var paragraph = articleParagraphs[_i]; 38 | paragraph.classList.add("read"); 39 | } 40 | })(m2 || (m2 = {})); 41 | -------------------------------------------------------------------------------- /code/es6/iterators.js: -------------------------------------------------------------------------------- 1 | var Component = (function () { 2 | function Component(name) { 3 | this.name = name; 4 | } 5 | return Component; 6 | }()); 7 | var Frame = (function () { 8 | function Frame(name, components) { 9 | this.name = name; 10 | this.components = components; 11 | this.pointer = 0; 12 | } 13 | Frame.prototype.next = function () { 14 | if (this.pointer < this.components.length) { 15 | return { 16 | done: false, 17 | value: this.components[this.pointer++] 18 | }; 19 | } 20 | else 21 | return { 22 | done: true 23 | }; 24 | }; 25 | return Frame; 26 | }()); 27 | var frame = new Frame("Door", [new Component("top"), new Component("bottom"), new Component("left"), new Component("right")]); 28 | var iteratorResult1 = frame.next(); 29 | var iteratorResult2 = frame.next(); 30 | var iteratorResult3 = frame.next(); 31 | var iteratorResult4 = frame.next(); 32 | var iteratorResult5 = frame.next(); 33 | var component = iteratorResult1.value; 34 | -------------------------------------------------------------------------------- /code/es6/iterators.ts: -------------------------------------------------------------------------------- 1 | // The book's chapter describes usage of Iterators with ES6 target 2 | // This example showing usage of iterators with ES5 target 3 | // 4 | // The example from the chapter should work in moderen browsers and Node 5 | // with target ES5 if you add es6.d.ts to the project 6 | 7 | class Component { 8 | constructor (public name: string) {} 9 | } 10 | 11 | class Frame { 12 | 13 | private pointer = 0; 14 | 15 | constructor(public name: string, public components: Component[]) {} 16 | 17 | public next(): {done: boolean, value?: Component} { 18 | if (this.pointer < this.components.length) { 19 | return { 20 | done: false, 21 | value: this.components[this.pointer++] 22 | } 23 | } else return { 24 | done: true 25 | } 26 | } 27 | 28 | } 29 | 30 | let frame = new Frame("Door", [new Component("top"), new Component("bottom"), new Component("left"), new Component("right")]); 31 | let iteratorResult1 = frame.next(); //{ done: false, value: Component { name: 'top' } } 32 | let iteratorResult2 = frame.next(); //{ done: false, value: Component { name: 'bottom' } } 33 | let iteratorResult3 = frame.next(); //{ done: false, value: Component { name: 'left' } } 34 | let iteratorResult4 = frame.next(); //{ done: false, value: Component { name: 'right' } } 35 | let iteratorResult5 = frame.next(); //{ done: true } 36 | 37 | //It is possible to access the value of iterator result via the value property: 38 | let component = iteratorResult1.value; //Component { name: 'top' } 39 | -------------------------------------------------------------------------------- /code/es6/let.js: -------------------------------------------------------------------------------- 1 | exports.asdfasdfasfadf = 123; 2 | var first; 3 | (function (first) { 4 | var something = [ 5 | 1, 6 | 2, 7 | 3 8 | ]; 9 | })(first || (first = {})); 10 | var second; 11 | (function (second) { 12 | var foo = 123; 13 | if (true) { 14 | var foo = 456; 15 | } 16 | console.log(foo); 17 | })(second || (second = {})); 18 | var third; 19 | (function (third) { 20 | var foo = 123; 21 | function test() { 22 | var foo = 456; 23 | } 24 | test(); 25 | console.log(foo); 26 | })(third || (third = {})); 27 | var fourth; 28 | (function (fourth) { 29 | var index = 0; 30 | var array = [ 31 | 1, 32 | 2, 33 | 3 34 | ]; 35 | for (var _index = 0; _index < array.length; _index++) { 36 | console.log(array[_index]); 37 | } 38 | console.log(index); 39 | })(fourth || (fourth = {})); 40 | var fifth; 41 | (function (fifth) { 42 | if (true) { 43 | var foo = 123; 44 | } 45 | })(fifth || (fifth = {})); 46 | var fifth; 47 | (function (fifth) { 48 | var foo = '123'; 49 | if (true) { 50 | var _foo = 123; 51 | } 52 | })(fifth || (fifth = {})); 53 | var closures; 54 | (function (closures) { 55 | var funcs = []; 56 | for (var i = 0; i < 3; i++) { 57 | funcs.push(function () { 58 | console.log(i); 59 | }); 60 | } 61 | for (var j = 0; j < 3; j++) { 62 | funcs[j](); 63 | } 64 | })(closures || (closures = {})); 65 | var closures2; 66 | (function (closures2) { 67 | var funcs = []; 68 | for (var i = 0; i < 3; i++) { 69 | (function () { 70 | var local = i; 71 | funcs.push(function () { 72 | console.log(local); 73 | }); 74 | })(); 75 | } 76 | for (var j = 0; j < 3; j++) { 77 | funcs[j](); 78 | } 79 | })(closures2 || (closures2 = {})); 80 | var closures3; 81 | (function (closures3) { 82 | var funcs = []; 83 | for (var i = 0; i < 3; i++) { 84 | funcs.push(function () { 85 | console.log(i); 86 | }); 87 | } 88 | for (var j = 0; j < 3; j++) { 89 | funcs[j](); 90 | } 91 | })(closures3 || (closures3 = {})); 92 | -------------------------------------------------------------------------------- /code/es6/let.ts: -------------------------------------------------------------------------------- 1 | export var asdfasdfasfadf = 123; 2 | 3 | module first { 4 | let something = [1, 2, 3]; 5 | 6 | 7 | } 8 | 9 | module second { 10 | var foo = 123; 11 | if (true) { 12 | var foo = 456; 13 | } 14 | console.log(foo); // 456 15 | } 16 | 17 | module third { 18 | var foo = 123; 19 | function test() { 20 | var foo = 456; 21 | } 22 | test(); 23 | console.log(foo); // 123 24 | } 25 | 26 | module fourth { 27 | var index = 0; 28 | var array = [1, 2, 3]; 29 | for (let index = 0; index < array.length; index++) { 30 | console.log(array[index]); 31 | } 32 | console.log(index); // 0 33 | } 34 | 35 | module fifth { 36 | if (true) { 37 | let foo = 123; 38 | } 39 | } 40 | 41 | module fifth { 42 | var foo = '123'; 43 | if (true) { 44 | let foo = 123; 45 | } 46 | } 47 | 48 | module closures { 49 | var funcs = []; 50 | // create a bunch of functions 51 | for (var i = 0; i < 3; i++) { 52 | funcs.push(function() { 53 | console.log(i); 54 | }) 55 | } 56 | // call them 57 | for (var j = 0; j < 3; j++) { 58 | funcs[j](); 59 | } 60 | } 61 | 62 | module closures2 { 63 | var funcs = []; 64 | // create a bunch of functions 65 | for (var i = 0; i < 3; i++) { 66 | (function() { 67 | var local = i; 68 | funcs.push(function() { 69 | console.log(local); 70 | }) 71 | })(); 72 | } 73 | // call them 74 | for (var j = 0; j < 3; j++) { 75 | funcs[j](); 76 | } 77 | } 78 | 79 | module closures3 { 80 | var funcs = []; 81 | // create a bunch of functions 82 | for (let i = 0; i < 3; i++) { // Error : loop contains 83 | funcs.push(function() { 84 | console.log(i); 85 | }) 86 | } 87 | // call them 88 | for (var j = 0; j < 3; j++) { 89 | funcs[j](); 90 | } 91 | } -------------------------------------------------------------------------------- /code/es6/rest-parameters.js: -------------------------------------------------------------------------------- 1 | var rest; 2 | (function (rest) { 3 | function iTakeItAll(first, second) { 4 | var allOthers = []; 5 | for (var _i = 2; _i < arguments.length; _i++) { 6 | allOthers[_i - 2] = arguments[_i]; 7 | } 8 | console.log(allOthers); 9 | } 10 | iTakeItAll('foo', 'bar'); 11 | iTakeItAll('foo', 'bar', 'bas', 'qux'); 12 | })(rest = exports.rest || (exports.rest = {})); 13 | -------------------------------------------------------------------------------- /code/es6/rest-parameters.ts: -------------------------------------------------------------------------------- 1 | export module rest { 2 | function iTakeItAll(first, second, ...allOthers) { 3 | console.log(allOthers); 4 | } 5 | iTakeItAll('foo', 'bar'); // [] 6 | iTakeItAll('foo', 'bar', 'bas', 'qux'); // ['bas','qux'] 7 | } -------------------------------------------------------------------------------- /code/es6/spread-operator.js: -------------------------------------------------------------------------------- 1 | var spread; 2 | (function (spread) { 3 | var list = [ 4 | 1, 5 | 2 6 | ]; 7 | list = list.concat([3, 4]); 8 | })(spread = exports.spread || (exports.spread = {})); 9 | -------------------------------------------------------------------------------- /code/es6/spread-operator.ts: -------------------------------------------------------------------------------- 1 | export module spread { 2 | var list = [1, 2]; 3 | list = [...list, 3, 4]; 4 | } -------------------------------------------------------------------------------- /code/es6/template-strings.js: -------------------------------------------------------------------------------- 1 | exports.templateStrings = '123'; 2 | var m1; 3 | (function (m1) { 4 | var lyrics = "Never gonna give you up \ 5 | \nNever gonna let you down"; 6 | console.log(lyrics); 7 | })(m1 || (m1 = {})); 8 | var m2; 9 | (function (m2) { 10 | var lyrics = "Never gonna give you up\nNever gonna let you down"; 11 | console.log(lyrics); 12 | })(m2 || (m2 = {})); 13 | var m3; 14 | (function (m3) { 15 | var lyrics = 'Never gonna give you up'; 16 | var html = '
' + lyrics + '
'; 17 | })(m3 || (m3 = {})); 18 | var m4; 19 | (function (m4) { 20 | var lyrics = 'Never gonna give you up'; 21 | var html = "
" + lyrics + "
"; 22 | })(m4 || (m4 = {})); 23 | var m5; 24 | (function (m5) { 25 | console.log("1 and 1 one make " + (1 + 1)); 26 | })(m5 || (m5 = {})); 27 | var m6; 28 | (function (m6) { 29 | var say = "a bird in hand > two in the bush"; 30 | var html = (_a = ["
I would just like to say : ", "
"], _a.raw = ["
I would just like to say : ", "
"], htmlEscape(_a, say)); 31 | function htmlEscape(literals) { 32 | var placeholders = []; 33 | for (var _i = 1; _i < arguments.length; _i++) { 34 | placeholders[_i - 1] = arguments[_i]; 35 | } 36 | var result = ""; 37 | for (var i = 0; i < placeholders.length; i++) { 38 | result += literals[i]; 39 | result += placeholders[i].replace(/&/g, '&').replace(/"/g, '"').replace(/'/g, ''').replace(//g, '>'); 40 | } 41 | result += literals[literals.length - 1]; 42 | return result; 43 | } 44 | console.log(html); 45 | var _a; 46 | })(m6 || (m6 = {})); 47 | -------------------------------------------------------------------------------- /code/es6/template-strings.ts: -------------------------------------------------------------------------------- 1 | export var templateStrings = '123'; 2 | 3 | module m1 { 4 | var lyrics = "Never gonna give you up \ 5 | \nNever gonna let you down"; 6 | console.log(lyrics); 7 | } 8 | 9 | module m2 { 10 | var lyrics = `Never gonna give you up 11 | Never gonna let you down`; 12 | console.log(lyrics); 13 | } 14 | 15 | module m3 { 16 | var lyrics = 'Never gonna give you up'; 17 | var html = '
' + lyrics + '
'; 18 | } 19 | 20 | module m4 { 21 | var lyrics = 'Never gonna give you up'; 22 | var html = `
${lyrics}
`; 23 | } 24 | 25 | module m5 { 26 | console.log(`1 and 1 one make ${1 + 1}`); 27 | } 28 | 29 | module m6 { 30 | var say = "a bird in hand > two in the bush"; 31 | var html = htmlEscape `
I would just like to say : ${say}
` 32 | 33 | // a sample tag function 34 | function htmlEscape(literals, ...placeholders) { 35 | let result = ""; 36 | 37 | // Interleave the literals with the placeholders 38 | for (let i = 0; i < placeholders.length; i++) { 39 | result += literals[i]; 40 | result += placeholders[i] 41 | .replace(/&/g, '&') 42 | .replace(/"/g, '"') 43 | .replace(/'/g, ''') 44 | .replace(//g, '>'); 46 | } 47 | 48 | // add the last literal 49 | result += literals[literals.length - 1]; 50 | return result; 51 | } 52 | console.log(html); 53 | } -------------------------------------------------------------------------------- /code/es6/test.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/basarat/typescript-book/e31fe92c3afeea1bbcac4381d290e75e5b3ab6e3/code/es6/test.js -------------------------------------------------------------------------------- /code/es6/test.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/basarat/typescript-book/e31fe92c3afeea1bbcac4381d290e75e5b3ab6e3/code/es6/test.ts -------------------------------------------------------------------------------- /code/es6/tsconfig.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /code/javascript/closure.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | function outerFunction(arg) { 3 | var variableInOuterFunction = arg; 4 | function bar() { 5 | console.log(variableInOuterFunction); 6 | } 7 | bar(); 8 | } 9 | outerFunction("hello closure"); 10 | var another; 11 | (function (another) { 12 | function outerFunction(arg) { 13 | var variableInOuterFunction = arg; 14 | return function () { 15 | console.log(variableInOuterFunction); 16 | }; 17 | } 18 | var innerFunction = outerFunction("hello closure!"); 19 | innerFunction(); 20 | })(another = exports.another || (exports.another = {})); 21 | var revealing; 22 | (function (revealing) { 23 | function createCounter() { 24 | var val = 0; 25 | return { 26 | increment: function () { val++; }, 27 | getVal: function () { return val; } 28 | }; 29 | } 30 | var counter = createCounter(); 31 | counter.increment(); 32 | console.log(counter.getVal()); 33 | })(revealing = exports.revealing || (exports.revealing = {})); 34 | var server; 35 | (function (server) { 36 | server.on(function handler(req, res) { 37 | loadData(req.id).then(function (data) { 38 | res.send(data); 39 | }); 40 | }); 41 | })(server = exports.server || (exports.server = {})); 42 | -------------------------------------------------------------------------------- /code/javascript/closure.ts: -------------------------------------------------------------------------------- 1 | function outerFunction(arg) { 2 | var variableInOuterFunction = arg; 3 | 4 | function bar() { 5 | console.log(variableInOuterFunction); // Access a variable from the outer scope 6 | } 7 | 8 | // Call the local function to demonstrate that it has access to arg 9 | bar(); 10 | } 11 | 12 | outerFunction("hello closure"); // logs hello closure! 13 | 14 | 15 | export namespace another { 16 | function outerFunction(arg) { 17 | var variableInOuterFunction = arg; 18 | return function() { 19 | console.log(variableInOuterFunction); 20 | } 21 | } 22 | 23 | var innerFunction = outerFunction("hello closure!"); 24 | 25 | // Note the outerFunction has returned 26 | innerFunction(); // logs hello closure! 27 | } 28 | 29 | 30 | export namespace revealing { 31 | function createCounter() { 32 | let val = 0; 33 | return { 34 | increment() { val++ }, 35 | getVal() { return val } 36 | } 37 | } 38 | 39 | let counter = createCounter(); 40 | counter.increment(); 41 | console.log(counter.getVal()); // 1 42 | } 43 | 44 | export namespace server { 45 | server.on(function handler(req, res) { 46 | loadData(req.id).then(function(data) { 47 | // the `res` has been closed over and is available 48 | res.send(data); 49 | }) 50 | }); 51 | } 52 | -------------------------------------------------------------------------------- /code/javascript/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "commonjs", 5 | "moduleResolution": "node", 6 | "isolatedModules": false, 7 | "jsx": "react", 8 | "experimentalDecorators": true, 9 | "emitDecoratorMetadata": true, 10 | "declaration": false, 11 | "noImplicitAny": false, 12 | "noImplicitUseStrict": false, 13 | "removeComments": true, 14 | "noLib": false, 15 | "preserveConstEnums": true, 16 | "suppressImplicitAnyIndexErrors": true 17 | }, 18 | "exclude": [ 19 | "node_modules", 20 | "typings/browser", 21 | "typings/browser.d.ts" 22 | ], 23 | "compileOnSave": true, 24 | "buildOnSave": false, 25 | "atom": { 26 | "rewriteTsconfig": false 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /code/tips/bindIsBad.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var Adder = (function () { 3 | function Adder(a) { 4 | this.a = a; 5 | } 6 | Adder.prototype.add = function (b) { 7 | return this.a + b; 8 | }; 9 | return Adder; 10 | })(); 11 | function useAdd(add) { 12 | return add(456); 13 | } 14 | var adder = new Adder('mary had a little 🐑'); 15 | useAdd(adder.add.bind(adder)); 16 | useAdd(function (x) { return adder.add(x); }); 17 | function twoParams(a, b) { 18 | return a + b; 19 | } 20 | var curryOne = twoParams.bind(null, 123); 21 | curryOne(456); 22 | curryOne('456'); 23 | var betterCurry; 24 | (function (betterCurry) { 25 | function twoParams(a, b) { 26 | return a + b; 27 | } 28 | var curryOne = function (x) { return twoParams(123, x); }; 29 | curryOne(456); 30 | curryOne('456'); 31 | })(betterCurry || (betterCurry = {})); 32 | -------------------------------------------------------------------------------- /code/tips/bindIsBad.ts: -------------------------------------------------------------------------------- 1 | export var _asdfasdfsadf; 2 | 3 | class Adder { 4 | constructor(public a: string) { } 5 | 6 | add(b: string): string { 7 | return this.a + b; 8 | } 9 | } 10 | 11 | function useAdd(add: (x: number) => number) { 12 | return add(456); 13 | } 14 | 15 | let adder = new Adder('mary had a little 🐑'); 16 | useAdd(adder.add.bind(adder)); // No compile error! 17 | useAdd((x) => adder.add(x)); // Error: number is not assignable to string 18 | 19 | 20 | function twoParams(a: number, b: number) { 21 | return a + b; 22 | } 23 | let curryOne = twoParams.bind(null, 123); 24 | curryOne(456); // Okay but is not type checked! 25 | curryOne('456'); // Allowed because it wasn't type checked 26 | 27 | namespace betterCurry { 28 | function twoParams(a: number, b: number) { 29 | return a + b; 30 | } 31 | let curryOne = (x: number) => twoParams(123, x); 32 | curryOne(456); // Okay and type checked! 33 | curryOne('456'); // Error! 34 | } 35 | -------------------------------------------------------------------------------- /code/tips/currying.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var add = function (x) { return function (y) { return x + y; }; }; 3 | add(123)(456); 4 | var add123 = add(123); 5 | add123(456); 6 | -------------------------------------------------------------------------------- /code/tips/currying.ts: -------------------------------------------------------------------------------- 1 | export var _asdfasdfasdf; 2 | 3 | 4 | // A function that supports currying 5 | let add = (x: number) => (y: number) => x + y; 6 | 7 | // Simple usage 8 | add(123)(456); 9 | 10 | // curried 11 | let add123 = add(123); 12 | 13 | // use the curried function 14 | add123(456); 15 | -------------------------------------------------------------------------------- /code/tips/lazyObjectLiteralInitialization.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var JS; 3 | (function (JS) { 4 | var foo = {}; 5 | foo.bar = 123; 6 | foo.bas = "Hello World"; 7 | })(JS = exports.JS || (exports.JS = {})); 8 | var TS; 9 | (function (TS) { 10 | var foo = { 11 | bar: 123, 12 | bas: "Hello World", 13 | }; 14 | })(TS = exports.TS || (exports.TS = {})); 15 | var TSQuick; 16 | (function (TSQuick) { 17 | var foo = {}; 18 | foo.bar = 123; 19 | foo.bas = "Hello World"; 20 | })(TSQuick = exports.TSQuick || (exports.TSQuick = {})); 21 | var TSMiddle; 22 | (function (TSMiddle) { 23 | var foo = {}; 24 | foo.bar = 123; 25 | foo.bas = "Hello World"; 26 | foo.bar = 'Hello Stranger'; 27 | })(TSMiddle = exports.TSMiddle || (exports.TSMiddle = {})); 28 | -------------------------------------------------------------------------------- /code/tips/lazyObjectLiteralInitialization.ts: -------------------------------------------------------------------------------- 1 | export namespace JS { 2 | let foo = {}; 3 | foo.bar = 123; 4 | foo.bas = "Hello World"; 5 | } 6 | 7 | export namespace TS { 8 | let foo = { 9 | bar: 123, 10 | bas: "Hello World", 11 | }; 12 | } 13 | 14 | export namespace TSQuick { 15 | let foo = {} as any; 16 | foo.bar = 123; 17 | foo.bas = "Hello World"; 18 | } 19 | 20 | export namespace TSMiddle { 21 | interface Foo { 22 | bar: number 23 | bas: string 24 | } 25 | 26 | let foo = {} as Foo; 27 | foo.bar = 123; 28 | foo.bas = "Hello World"; 29 | 30 | // later in the codebase: 31 | foo.bar = 'Hello Stranger'; // Error: You probably misspelled `bas` as `bar`, cannot assign string to number 32 | } 33 | -------------------------------------------------------------------------------- /code/tips/mixins.js: -------------------------------------------------------------------------------- 1 | var __extends = (this && this.__extends) || function (d, b) { 2 | for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; 3 | function __() { this.constructor = d; } 4 | d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); 5 | }; 6 | var Disposable = (function () { 7 | function Disposable() { 8 | } 9 | Disposable.prototype.dispose = function () { 10 | this.isDisposed = true; 11 | }; 12 | return Disposable; 13 | })(); 14 | var Activatable = (function () { 15 | function Activatable() { 16 | } 17 | Activatable.prototype.activate = function () { 18 | this.isActive = true; 19 | }; 20 | Activatable.prototype.deactivate = function () { 21 | this.isActive = false; 22 | }; 23 | return Activatable; 24 | })(); 25 | var ActivatibleDisposible = (function () { 26 | Disposable.apply(this); 27 | ActivatibleDisposible.apply(this); 28 | return this; 29 | }); 30 | var SmartObject = (function (_super) { 31 | __extends(SmartObject, _super); 32 | function SmartObject() { 33 | var _this = this; 34 | _super.call(this); 35 | setInterval(function () { return console.log(_this.isActive + " : " + _this.isDisposed); }, 500); 36 | } 37 | SmartObject.prototype.interact = function () { 38 | this.activate(); 39 | }; 40 | return SmartObject; 41 | })(ActivatibleDisposible); 42 | applyMixins(SmartObject, [Disposable, Activatable]); 43 | var smartObj = new SmartObject(); 44 | setTimeout(function () { return smartObj.interact(); }, 1000); 45 | function applyMixins(derivedCtor, baseCtors) { 46 | baseCtors.forEach(function (baseCtor) { 47 | Object.getOwnPropertyNames(baseCtor.prototype).forEach(function (name) { 48 | derivedCtor.prototype[name] = baseCtor.prototype[name]; 49 | }); 50 | }); 51 | } 52 | -------------------------------------------------------------------------------- /code/tips/mixins.ts: -------------------------------------------------------------------------------- 1 | // Disposable Mixin 2 | class Disposable { 3 | isDisposed: boolean; 4 | dispose() { 5 | this.isDisposed = true; 6 | } 7 | 8 | } 9 | 10 | // Activatable Mixin 11 | class Activatable { 12 | isActive: boolean; 13 | activate() { 14 | this.isActive = true; 15 | } 16 | deactivate() { 17 | this.isActive = false; 18 | } 19 | } 20 | 21 | interface ActivatibleDisposible extends Disposable, Activatable { 22 | new (): ActivatibleDisposible; 23 | } 24 | 25 | var ActivatibleDisposible: ActivatibleDisposible = (function(){ 26 | Disposable.apply(this); 27 | ActivatibleDisposible.apply(this); 28 | return this; 29 | }) 30 | 31 | class SmartObject extends ActivatibleDisposible { 32 | constructor() { 33 | super(); 34 | setInterval(() => console.log(this.isActive + " : " + this.isDisposed), 500); 35 | } 36 | 37 | interact() { 38 | this.activate(); 39 | } 40 | } 41 | applyMixins(SmartObject, [Disposable, Activatable]) 42 | 43 | var smartObj = new SmartObject(); 44 | setTimeout(() => smartObj.interact(), 1000); 45 | 46 | //////////////////////////////////////// 47 | // In your runtime library somewhere 48 | //////////////////////////////////////// 49 | 50 | function applyMixins(derivedCtor: any, baseCtors: any[]) { 51 | baseCtors.forEach(baseCtor => { 52 | Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => { 53 | derivedCtor.prototype[name] = baseCtor.prototype[name]; 54 | }) 55 | }); 56 | } -------------------------------------------------------------------------------- /code/tips/nominalTyping.js: -------------------------------------------------------------------------------- 1 | var EnumDriven; 2 | (function (EnumDriven) { 3 | var FooIdBrand; 4 | (function (FooIdBrand) { 5 | })(FooIdBrand || (FooIdBrand = {})); 6 | var BarIdBrand; 7 | (function (BarIdBrand) { 8 | })(BarIdBrand || (BarIdBrand = {})); 9 | var fooId; 10 | var barId; 11 | fooId = barId; 12 | barId = fooId; 13 | fooId = 'foo'; 14 | barId = 'bar'; 15 | var str; 16 | str = fooId; 17 | str = barId; 18 | })(EnumDriven || (EnumDriven = {})); 19 | var Interface; 20 | (function (Interface) { 21 | var fooId; 22 | var barId; 23 | fooId = barId; 24 | barId = fooId; 25 | fooId = barId; 26 | barId = fooId; 27 | fooId = 'foo'; 28 | barId = 'bar'; 29 | var str; 30 | str = fooId; 31 | str = barId; 32 | })(Interface || (Interface = {})); 33 | -------------------------------------------------------------------------------- /code/tips/nominalTyping.ts: -------------------------------------------------------------------------------- 1 | namespace Literal { 2 | /** Generic Id type */ 3 | type Id = { 4 | type: T, 5 | value: string, 6 | } 7 | 8 | /** Specific Id types */ 9 | type FooId = Id<'foo'>; 10 | type BarId = Id<'bar'>; 11 | 12 | /** Optional: contructors functions */ 13 | const createFoo = (value: string): FooId => ({ type: 'foo', value }); 14 | const createBar = (value: string): BarId => ({ type: 'bar', value }); 15 | 16 | let foo = createFoo('sample') 17 | let bar = createBar('sample'); 18 | 19 | foo = bar; // Error 20 | foo = foo; // Okay 21 | } 22 | 23 | namespace EnumDriven { 24 | // FOO 25 | enum FooIdBrand { } 26 | type FooId = FooIdBrand & string; 27 | 28 | // BAR 29 | enum BarIdBrand { } 30 | type BarId = BarIdBrand & string; 31 | 32 | /** 33 | * Usage Demo 34 | */ 35 | var fooId: FooId; 36 | var barId: BarId; 37 | 38 | // Safety! 39 | fooId = barId; // error 40 | barId = fooId; // error 41 | 42 | // Newing up 43 | fooId = 'foo' as FooId; 44 | barId = 'bar' as BarId; 45 | 46 | // Both types are compatible with the base 47 | var str: string; 48 | str = fooId; 49 | str = barId; 50 | } 51 | 52 | namespace Interface { 53 | 54 | // FOO 55 | interface FooId extends String { 56 | _fooIdBrand: string; // To prevent type errors 57 | } 58 | 59 | // BAR 60 | interface BarId extends String { 61 | _barIdBrand: string; // To prevent type errors 62 | } 63 | 64 | /** 65 | * Usage Demo 66 | */ 67 | var fooId: FooId; 68 | var barId: BarId; 69 | 70 | // Safety! 71 | fooId = barId; // error 72 | barId = fooId; // error 73 | fooId = barId; // error 74 | barId = fooId; // error 75 | 76 | // Newing up 77 | fooId = 'foo' as any; 78 | barId = 'bar' as any; 79 | 80 | // If you need the base string 81 | var str: string; 82 | str = fooId as any; 83 | str = barId as any; 84 | } 85 | -------------------------------------------------------------------------------- /code/tips/statefulFunctions.js: -------------------------------------------------------------------------------- 1 | var called = (new (function () { 2 | function class_1() { 3 | var _this = this; 4 | this.count = 0; 5 | this.called = function () { 6 | _this.count++; 7 | console.log("Called : " + _this.count); 8 | }; 9 | } 10 | return class_1; 11 | })()).called; 12 | called(); 13 | called(); 14 | -------------------------------------------------------------------------------- /code/tips/statefulFunctions.ts: -------------------------------------------------------------------------------- 1 | let {called} = new class { 2 | count = 0; 3 | called = () => { 4 | this.count++; 5 | console.log(`Called : ${this.count}`); 6 | } 7 | }; 8 | 9 | called(); // Called : 1 10 | called(); // Called : 2 11 | -------------------------------------------------------------------------------- /code/tips/stringEnums.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var Simple; 3 | (function (Simple) { 4 | var Tristate = { 5 | False: '', 6 | True: '', 7 | Unknown: '' 8 | }; 9 | Object.keys(Tristate).map(function (key) { return Tristate[key] = key; }); 10 | var state = Tristate.True; 11 | if (state === Tristate.True) { 12 | } 13 | })(Simple = exports.Simple || (exports.Simple = {})); 14 | var Fancy; 15 | (function (Fancy) { 16 | var state; 17 | state = 'False'; 18 | })(Fancy = exports.Fancy || (exports.Fancy = {})); 19 | -------------------------------------------------------------------------------- /code/tips/stringEnums.ts: -------------------------------------------------------------------------------- 1 | export namespace Simple { 2 | let Tristate = { 3 | False: '', 4 | True: '', 5 | Unknown: '' 6 | }; 7 | 8 | // make values same as keys 9 | Object.keys(Tristate).map((key) => Tristate[key] = key); 10 | 11 | 12 | /** 13 | * Usage 14 | */ 15 | 16 | // Assigning 17 | let state = Tristate.True; 18 | 19 | // Checking if it matches 20 | if (state === Tristate.True) { 21 | 22 | } 23 | } 24 | 25 | 26 | export namespace Fancy { 27 | type TriState = 'False' | 'True' | 'Unknown'; 28 | 29 | let state: TriState; 30 | state = 'False'; 31 | } 32 | -------------------------------------------------------------------------------- /code/tips/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "commonjs", 5 | "declaration": false, 6 | "noImplicitAny": false, 7 | "removeComments": true, 8 | "moduleResolution": "node", 9 | "isolatedModules": false, 10 | "jsx": "react", 11 | "experimentalDecorators": true, 12 | "emitDecoratorMetadata": true, 13 | "noLib": false, 14 | "preserveConstEnums": true, 15 | "suppressImplicitAnyIndexErrors": true 16 | }, 17 | "filesGlob": [ 18 | "**/*.ts", 19 | "**/*.tsx", 20 | "!node_modules/**" 21 | ], 22 | "files": [ 23 | "bindIsBad.ts", 24 | "currying.ts", 25 | "lazyObjectLiteralInitialization.ts", 26 | "mixins.ts", 27 | "nominalTyping.ts", 28 | "statefulFunctions.ts", 29 | "stringEnums.ts" 30 | ], 31 | "exclude": [], 32 | "atom": { 33 | "rewriteTsconfig": true 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /code/types/assertion.js: -------------------------------------------------------------------------------- 1 | exports.asdf = 123; 2 | var porting; 3 | (function (porting) { 4 | var foo = {}; 5 | foo.bar = 123; 6 | foo.bas = 'hello'; 7 | })(porting || (porting = {})); 8 | var assert; 9 | (function (assert) { 10 | var foo = {}; 11 | foo.bar = 123; 12 | foo.bas = 'hello'; 13 | })(assert || (assert = {})); 14 | var sdfsdfsdf; 15 | (function (sdfsdfsdf) { 16 | var foo; 17 | var bar = foo; 18 | })(sdfsdfsdf || (sdfsdfsdf = {})); 19 | var doubleAssertion; 20 | (function (doubleAssertion) { 21 | function handler1(event) { 22 | var mouseEvent = event; 23 | } 24 | function handler2(event) { 25 | var element = event; 26 | } 27 | function handler(event) { 28 | var element = event; 29 | } 30 | })(doubleAssertion || (doubleAssertion = {})); 31 | -------------------------------------------------------------------------------- /code/types/assertion.ts: -------------------------------------------------------------------------------- 1 | export var asdf = 123; 2 | 3 | module porting { 4 | var foo = {}; 5 | foo.bar = 123; // error : property 'bar' does not exist on `{}` 6 | foo.bas = 'hello'; // error : property 'bas' does not exist on `{}` 7 | } 8 | 9 | module assert { 10 | interface Foo { 11 | bar: number; 12 | bas: string; 13 | } 14 | var foo = {} as Foo; 15 | foo.bar = 123; 16 | foo.bas = 'hello'; 17 | } 18 | 19 | module sdfsdfsdf { 20 | var foo: any; 21 | var bar = foo; // bar is now of type "string" 22 | } 23 | 24 | 25 | namespace doubleAssertion { 26 | 27 | function handler1(event: Event) { 28 | let mouseEvent = event as MouseEvent; 29 | } 30 | 31 | function handler2(event: Event) { 32 | let element = event as HTMLElement; // Error : Neither 'Event' not type 'HTMLElement' is assignable to the other 33 | } 34 | 35 | function handler(event: Event) { 36 | let element = event as any as HTMLElement; // Okay! 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /code/types/callable.ts: -------------------------------------------------------------------------------- 1 | export namespace asdfasdfasdfasdflkjasdflkjasdflkjasdflkjasdf { 2 | } 3 | 4 | namespace A { 5 | interface ReturnString { 6 | (): string 7 | } 8 | declare const foo: ReturnString; 9 | const bar = foo(); // bar is inferred as a string 10 | } 11 | 12 | namespace Complex { 13 | interface Complex { 14 | (foo: string, bar?: number, ...others: boolean[]): number; 15 | } 16 | 17 | interface Overloaded { 18 | (foo: string): string 19 | (foo: number): number 20 | } 21 | 22 | // example implementation 23 | const overloaded: Overloaded = (foo) => foo; 24 | 25 | // example usage 26 | const str = overloaded(''); // str is inferred string 27 | const number = overloaded(123); // num is inferred number 28 | } 29 | 30 | namespace Direct { 31 | const overloaded: { 32 | (foo: string): string 33 | (foo: number): number 34 | } = (foo) => foo; 35 | 36 | const simple: (foo: number) => string 37 | = (foo) => foo.toString(); 38 | 39 | interface CallMeWithNewToGetString { 40 | new(): string 41 | } 42 | // Usage 43 | declare const Foo: CallMeWithNewToGetString; 44 | const bar = new Foo(); // bar is inferred to be of type string 45 | } 46 | 47 | -------------------------------------------------------------------------------- /code/types/freshness/freshness.js: -------------------------------------------------------------------------------- 1 | exports.foo = 123; 2 | var first; 3 | (function (first) { 4 | function logName(something) { 5 | console.log(something.name); 6 | } 7 | var person = { name: 'matt', job: 'being awesome' }; 8 | var animal = { name: 'cow', diet: 'vegan, but has milk of own species' }; 9 | var random = { note: "I don't have a name property" }; 10 | logName(person); 11 | logName(animal); 12 | logName(random); 13 | })(first || (first = {})); 14 | var second; 15 | (function (second) { 16 | function logName(something) { 17 | console.log(something.name); 18 | } 19 | logName({ name: 'matt' }); 20 | logName({ name: 'matt', job: 'being awesome' }); 21 | })(second || (second = {})); 22 | var second; 23 | (function (second) { 24 | function logIfHasName(something) { 25 | if (something.name) { 26 | console.log(something.name); 27 | } 28 | } 29 | var person = { name: 'matt', job: 'being awesome' }; 30 | var animal = { name: 'cow', diet: 'vegan, but has milk of own species' }; 31 | var random = { note: "I don't have a name property" }; 32 | logIfHasName(person); 33 | logIfHasName(animal); 34 | logIfHasName(random); 35 | logIfHasName({ neme: 'I just misspelled name to neme' }); 36 | })(second || (second = {})); 37 | -------------------------------------------------------------------------------- /code/types/freshness/index-signatures.js: -------------------------------------------------------------------------------- 1 | var a; 2 | (function (a) { 3 | var foo = {}; 4 | foo['Hello'] = 'World'; 5 | console.log(foo['Hello']); 6 | })(a || (a = {})); 7 | var b; 8 | (function (b) { 9 | var Foo = (function () { 10 | function Foo(message) { 11 | this.message = message; 12 | } 13 | ; 14 | Foo.prototype.log = function () { 15 | console.log(this.message); 16 | }; 17 | return Foo; 18 | }()); 19 | var foo = {}; 20 | foo['Hello'] = new Foo('World'); 21 | foo['Hello'].log(); 22 | })(b || (b = {})); 23 | var c; 24 | (function (c) { 25 | var obj = { 26 | toString: function () { 27 | console.log('toString called'); 28 | return 'Hello'; 29 | } 30 | }; 31 | var foo = {}; 32 | foo[obj] = 'World'; 33 | console.log(foo[obj]); 34 | console.log(foo['Hello']); 35 | })(c || (c = {})); 36 | var d; 37 | (function (d) { 38 | var foo = ['World']; 39 | console.log(foo[0]); 40 | })(d || (d = {})); 41 | var e; 42 | (function (e) { 43 | var obj = { 44 | toString: function () { 45 | return 'Hello'; 46 | } 47 | }; 48 | var foo = {}; 49 | foo[obj] = 'World'; 50 | foo[obj.toString()] = 'World'; 51 | })(e || (e = {})); 52 | var f; 53 | (function (f) { 54 | var obj = { message: 'Hello' }; 55 | var foo = {}; 56 | foo[obj] = 'World'; 57 | console.log(foo["[object Object]"]); 58 | })(f || (f = {})); 59 | var f; 60 | (function (f) { 61 | console.log((1).toString()); 62 | console.log((2).toString()); 63 | })(f || (f = {})); 64 | var g; 65 | (function (g) { 66 | var foo = {}; 67 | foo['a'] = { message: 'some message' }; 68 | foo['a'] = { messages: 'some message' }; 69 | foo['a'].message; 70 | foo['a'].messages; 71 | })(g || (g = {})); 72 | var mustConform2; 73 | (function (mustConform2) { 74 | var foo = { x: 1, y: 2 }; 75 | foo['x']; 76 | var x = 'x'; 77 | foo[x]; 78 | })(mustConform2 || (mustConform2 = {})); 79 | -------------------------------------------------------------------------------- /code/types/freshness/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.5.0-beta", 3 | "compilerOptions": { 4 | "target": "es5", 5 | "module": "commonjs", 6 | "isolatedModules": false, 7 | "jsx": "react", 8 | "experimentalDecorators": true, 9 | "emitDecoratorMetadata": true, 10 | "declaration": false, 11 | "noImplicitAny": false, 12 | "removeComments": true, 13 | "noLib": false, 14 | "preserveConstEnums": true, 15 | "suppressImplicitAnyIndexErrors": true 16 | }, 17 | "filesGlob": [ 18 | "./**/*.ts", 19 | "./**/*.tsx", 20 | "!./node_modules/**/*" 21 | ], 22 | "files": [ 23 | "./freshness.ts", 24 | "./index-signatures.ts" 25 | ], 26 | "atom": { 27 | "rewriteTsconfig": true 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /code/types/functions.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var parameter; 3 | (function (parameter) { 4 | var sampleVariable; 5 | function foo(sampleParameter) { } 6 | })(parameter || (parameter = {})); 7 | var returnType; 8 | (function (returnType) { 9 | function foo(sample) { 10 | return sample; 11 | } 12 | })(returnType || (returnType = {})); 13 | var inferred; 14 | (function (inferred) { 15 | function foo(sample) { 16 | return sample; 17 | } 18 | })(inferred || (inferred = {})); 19 | var misspelled; 20 | (function (misspelled) { 21 | function foo() { 22 | return { fou: 'John Doe' }; 23 | } 24 | sendAsJSON(foo()); 25 | })(misspelled || (misspelled = {})); 26 | var optional; 27 | (function (optional) { 28 | function foo(bar, bas) { 29 | } 30 | foo(123); 31 | foo(123, 'hello'); 32 | })(optional || (optional = {})); 33 | var optionalDefault; 34 | (function (optionalDefault) { 35 | function foo(bar, bas) { 36 | if (bas === void 0) { bas = 'world'; } 37 | console.log(bar, bas); 38 | } 39 | foo(123); 40 | foo(123, 'hello'); 41 | })(optionalDefault || (optionalDefault = {})); 42 | var overloads; 43 | (function (overloads) { 44 | function padding(a, b, c, d) { 45 | if (b === undefined && c === undefined && d === undefined) { 46 | b = c = d = a; 47 | } 48 | else if (c === undefined && d === undefined) { 49 | c = a; 50 | d = b; 51 | } 52 | return { 53 | top: a, 54 | right: b, 55 | bottom: c, 56 | left: d 57 | }; 58 | } 59 | overloads.padding = padding; 60 | })(overloads || (overloads = {})); 61 | var overloadsDone; 62 | (function (overloadsDone) { 63 | function padding(a, b, c, d) { 64 | if (b === undefined && c === undefined && d === undefined) { 65 | b = c = d = a; 66 | } 67 | else if (c === undefined && d === undefined) { 68 | c = a; 69 | d = b; 70 | } 71 | return { 72 | top: a, 73 | right: b, 74 | bottom: c, 75 | left: d 76 | }; 77 | } 78 | overloadsDone.padding = padding; 79 | })(overloadsDone || (overloadsDone = {})); 80 | -------------------------------------------------------------------------------- /code/types/functions.ts: -------------------------------------------------------------------------------- 1 | export namespace asdfasdfasdfasdflkjasdflkjasdflkjasdflkjasdf { 2 | } 3 | 4 | namespace parameter { 5 | // variable annotation 6 | var sampleVariable: { bar: number } 7 | 8 | // function parameter 9 | function foo(sampleParameter: { bar: number }) { } 10 | } 11 | 12 | namespace returnType { 13 | interface Foo { 14 | foo: string; 15 | } 16 | 17 | // Return type annotated as `: Foo` 18 | function foo(sample: Foo) { 19 | return sample; 20 | } 21 | } 22 | 23 | namespace inferred { 24 | interface Foo { 25 | foo: string; 26 | } 27 | 28 | function foo(sample: Foo) { 29 | return sample; // inferred return type 'Foo' 30 | } 31 | } 32 | 33 | namespace misspelled { 34 | function foo() { 35 | return { fou: 'John Doe' }; // You might not find this misspelling `foo` till its too late 36 | } 37 | 38 | sendAsJSON(foo()); 39 | } 40 | 41 | namespace optional { 42 | function foo(bar: number, bas?: string): void { 43 | // .. 44 | } 45 | 46 | foo(123); 47 | foo(123, 'hello'); 48 | } 49 | 50 | namespace optionalDefault { 51 | function foo(bar: number, bas: string = 'world') { 52 | console.log(bar, bas); 53 | } 54 | 55 | foo(123); // 123, world 56 | foo(123, 'hello'); // 123, hello 57 | } 58 | 59 | namespace overloads { 60 | export function padding(a: number, b?: number, c?: number, d?: any) { 61 | if (b === undefined && c === undefined && d === undefined) { 62 | b = c = d = a; 63 | } 64 | else if (c === undefined && d === undefined) { 65 | c = a; 66 | d = b; 67 | } 68 | return { 69 | top: a, 70 | right: b, 71 | bottom: c, 72 | left: d 73 | }; 74 | } 75 | } 76 | 77 | namespace overloadsDone { 78 | export function padding(all: number); 79 | export function padding(topAndBottom: number, leftAndRight: number); 80 | export function padding(top: number, right: number, bottom: number, left: number); 81 | export function padding(a: number, b?: number, c?: number, d?: number) { 82 | if (b === undefined && c === undefined && d === undefined) { 83 | b = c = d = a; 84 | } 85 | else if (c === undefined && d === undefined) { 86 | c = a; 87 | d = b; 88 | } 89 | return { 90 | top: a, 91 | right: b, 92 | bottom: c, 93 | left: d 94 | }; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /code/types/generics.js: -------------------------------------------------------------------------------- 1 | var aaa; 2 | (function (aaa) { 3 | var Queue = (function () { 4 | function Queue() { 5 | var _this = this; 6 | this.data = []; 7 | this.push = function (item) { return _this.data.push(item); }; 8 | this.pop = function () { return _this.data.shift(); }; 9 | } 10 | return Queue; 11 | }()); 12 | var queue = new Queue(); 13 | queue.push(0); 14 | queue.push("1"); 15 | console.log(queue.pop().toPrecision(1)); 16 | console.log(queue.pop().toPrecision(1)); 17 | })(aaa || (aaa = {})); 18 | var bbb; 19 | (function (bbb) { 20 | var QueueNumber = (function () { 21 | function QueueNumber() { 22 | var _this = this; 23 | this.data = []; 24 | this.push = function (item) { return _this.data.push(item); }; 25 | this.pop = function () { return _this.data.shift(); }; 26 | } 27 | return QueueNumber; 28 | }()); 29 | var queue = new QueueNumber(); 30 | queue.push(0); 31 | queue.push("1"); 32 | })(bbb || (bbb = {})); 33 | var ccc; 34 | (function (ccc) { 35 | var Queue = (function () { 36 | function Queue() { 37 | var _this = this; 38 | this.data = []; 39 | this.push = function (item) { return _this.data.push(item); }; 40 | this.pop = function () { return _this.data.shift(); }; 41 | } 42 | return Queue; 43 | }()); 44 | var queue = new Queue(); 45 | queue.push(0); 46 | queue.push("1"); 47 | })(ccc || (ccc = {})); 48 | -------------------------------------------------------------------------------- /code/types/generics.ts: -------------------------------------------------------------------------------- 1 | module aaa { 2 | class Queue { 3 | private data = []; 4 | push = (item) => this.data.push(item); 5 | pop = () => this.data.shift(); 6 | } 7 | 8 | const queue = new Queue(); 9 | queue.push(0); 10 | queue.push("1"); // Oops a mistake 11 | 12 | // a developer walks into a bar 13 | console.log(queue.pop().toPrecision(1)); 14 | console.log(queue.pop().toPrecision(1)); // RUNTIME ERROR 15 | } 16 | 17 | module bbb { 18 | class QueueNumber { 19 | private data = []; 20 | push = (item: number) => this.data.push(item); 21 | pop = (): number => this.data.shift(); 22 | } 23 | 24 | const queue = new QueueNumber(); 25 | queue.push(0); 26 | queue.push("1"); // ERROR : cannot push a string. Only numbers allowed 27 | 28 | // ^ if that error is fixed the rest would be fine too 29 | } 30 | 31 | module ccc { 32 | /** A class definition with a generic parameter */ 33 | class Queue { 34 | private data = []; 35 | push = (item: T) => this.data.push(item); 36 | pop = (): T => this.data.shift(); 37 | } 38 | 39 | /** Again sample usage */ 40 | const queue = new Queue(); 41 | queue.push(0); 42 | queue.push("1"); // ERROR : cannot push a string. Only numbers allowed 43 | 44 | // ^ if that error is fixed the rest would be fine too 45 | } 46 | 47 | namespace ddd { 48 | const getJSON = (config: { 49 | url: string, 50 | headers?: { [key: string]: string }, 51 | }): Promise => { 52 | const fetchConfig = ({ 53 | method: 'GET', 54 | 'Accept': 'application/json', 55 | 'Content-Type': 'application/json', 56 | ...(config.headers || {}) 57 | }); 58 | return fetch(config.url, fetchConfig) 59 | .then(response => response.json()); 60 | } 61 | 62 | type LoadUsersResponse = { 63 | users: { 64 | name: string; 65 | email: string; 66 | }[]; 67 | }; 68 | function loadUsers() { 69 | return getJSON({ url: 'https://example.com/users' }); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /code/types/interfaces.js: -------------------------------------------------------------------------------- 1 | var Implement; 2 | (function (Implement) { 3 | var MyPoint = (function () { 4 | function MyPoint() { 5 | } 6 | return MyPoint; 7 | }()); 8 | })(Implement || (Implement = {})); 9 | var ErrorIt; 10 | (function (ErrorIt) { 11 | var MyPoint = (function () { 12 | function MyPoint() { 13 | } 14 | return MyPoint; 15 | }()); 16 | })(ErrorIt || (ErrorIt = {})); 17 | -------------------------------------------------------------------------------- /code/types/interfaces.ts: -------------------------------------------------------------------------------- 1 | namespace Implement { 2 | interface Point { 3 | x: number; y: number; 4 | } 5 | 6 | class MyPoint implements Point { 7 | x: number; y: number; // Same as Point 8 | } 9 | } 10 | 11 | namespace ErrorIt { 12 | interface Point { 13 | x: number; y: number; 14 | z: number; // New member 15 | } 16 | 17 | class MyPoint implements Point { // ERROR : missing member `z` 18 | x: number; y: number; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /code/types/keyof.ts: -------------------------------------------------------------------------------- 1 | namespace Test { 2 | const colors = { 3 | red: 'red', 4 | blue: 'blue' 5 | } 6 | type Colors = keyof typeof colors; 7 | 8 | let color: Colors; 9 | color = 'red'; // okay 10 | color = 'blue'; // okay 11 | color = 'blue'; // Error 12 | } -------------------------------------------------------------------------------- /code/types/lib/exclude/nolibd.js: -------------------------------------------------------------------------------- 1 | var foo = 123; 2 | var bar = foo.toString(); 3 | -------------------------------------------------------------------------------- /code/types/lib/exclude/nolibd.ts: -------------------------------------------------------------------------------- 1 | var foo = 123; 2 | var bar = foo.toString(); // Property 'toString' does not exist on type 'number'. -------------------------------------------------------------------------------- /code/types/lib/exclude/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions":{ 3 | "noLib": true 4 | } 5 | } -------------------------------------------------------------------------------- /code/types/lib/usage/libd.js: -------------------------------------------------------------------------------- 1 | var foo = 123; 2 | var bar = foo.toString(); 3 | var test = window; 4 | window.helloWorld = function () { return console.log('hello world'); }; 5 | window.helloWorld(); 6 | Math.seedrandom(); 7 | Date.parse; 8 | String.prototype.endsWith = function (suffix) { 9 | var str = this; 10 | return str && str.indexOf(suffix, str.length - suffix.length) !== -1; 11 | }; 12 | console.log('foo bar'.endsWith('bas')); 13 | console.log('foo bas'.endsWith('bas')); 14 | -------------------------------------------------------------------------------- /code/types/lib/usage/libd.ts: -------------------------------------------------------------------------------- 1 | var foo = 123; 2 | var bar = foo.toString(); 3 | 4 | var test = window; 5 | 6 | interface Window { 7 | helloWorld(): void; 8 | } 9 | 10 | // Add it at runtime 11 | window.helloWorld = () => console.log('hello world'); 12 | // Call it 13 | window.helloWorld(); 14 | // Misuse it and you get an error: 15 | // window.helloWorld('gracius'); // Error: Supplied parameters do not match the signature of the call target 16 | 17 | 18 | interface Math { 19 | seedrandom(seed?: string); 20 | } 21 | 22 | Math.seedrandom(); 23 | 24 | Date.parse 25 | interface Date { 26 | 27 | } 28 | 29 | interface String { 30 | endsWith(suffix: string): boolean; 31 | } 32 | 33 | String.prototype.endsWith = function(suffix: string): boolean { 34 | var str: string = this; 35 | return str && str.indexOf(suffix, str.length - suffix.length) !== -1; 36 | } 37 | 38 | console.log('foo bar'.endsWith('bas')); // false 39 | console.log('foo bas'.endsWith('bas')); // true -------------------------------------------------------------------------------- /code/types/lib/usage/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions":{ 3 | } 4 | } -------------------------------------------------------------------------------- /code/types/libd.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/basarat/typescript-book/e31fe92c3afeea1bbcac4381d290e75e5b3ab6e3/code/types/libd.js -------------------------------------------------------------------------------- /code/types/literal-types.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var Simple; 3 | (function (Simple) { 4 | var foo; 5 | foo = 'Bar'; 6 | })(Simple = exports.Simple || (exports.Simple = {})); 7 | var Union; 8 | (function (Union) { 9 | function move(distance, direction) { 10 | } 11 | move(1, "North"); 12 | move(1, "Nurth"); 13 | })(Union = exports.Union || (exports.Union = {})); 14 | -------------------------------------------------------------------------------- /code/types/literal-types.ts: -------------------------------------------------------------------------------- 1 | export namespace Simple { 2 | let foo: 'Hello'; 3 | foo = 'Bar'; // Error: "Bar" is not assignable to type "Hello" 4 | } 5 | 6 | 7 | export namespace Union { 8 | type CardinalDirection = 9 | "North" 10 | | "East" 11 | | "South" 12 | | "West"; 13 | 14 | function move(distance: number, direction: CardinalDirection) { 15 | // ... 16 | } 17 | 18 | move(1, "North"); // Okay 19 | move(1, "Nurth"); // Error! 20 | } 21 | 22 | namespace StringEnum { 23 | 24 | /** Utility function to create a K:V from a list of strings */ 25 | function strEnum(o: Array): {[K in T]: K} { 26 | return o.reduce((res, key) => { 27 | res[key] = key; 28 | return res; 29 | }, Object.create(null)); 30 | } 31 | 32 | /** 33 | * Sample create a string enum 34 | */ 35 | 36 | /** Create a K:V */ 37 | const Direction = strEnum([ 38 | 'North', 39 | 'South', 40 | 'East', 41 | 'West' 42 | ]) 43 | /** Create a Type */ 44 | type Direction = keyof typeof Direction; 45 | 46 | /** 47 | * Sample using a string enum 48 | */ 49 | let sample: Direction; 50 | 51 | sample = Direction.North; // Okay 52 | sample = 'North'; // Okay 53 | sample = 'AnythingElse'; // ERROR! 54 | } -------------------------------------------------------------------------------- /code/types/migrating/migrating.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/basarat/typescript-book/e31fe92c3afeea1bbcac4381d290e75e5b3ab6e3/code/types/migrating/migrating.js -------------------------------------------------------------------------------- /code/types/migrating/migrating.ts: -------------------------------------------------------------------------------- 1 | declare var $: any; 2 | declare type JQuery = any; -------------------------------------------------------------------------------- /code/types/migrating/tsconfig.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /code/types/stringLiteralType.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var Simple; 3 | (function (Simple) { 4 | var foo; 5 | foo = 'Bar'; 6 | })(Simple = exports.Simple || (exports.Simple = {})); 7 | var Union; 8 | (function (Union) { 9 | function move(distance, direction) { 10 | } 11 | move(1, "North"); 12 | move(1, "Nurth"); 13 | })(Union = exports.Union || (exports.Union = {})); 14 | -------------------------------------------------------------------------------- /code/types/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "commonjs", 5 | "moduleResolution": "node", 6 | "isolatedModules": false, 7 | "jsx": "react", 8 | "experimentalDecorators": true, 9 | "emitDecoratorMetadata": true, 10 | "declaration": false, 11 | "noImplicitAny": false, 12 | "removeComments": true, 13 | "noLib": false, 14 | "preserveConstEnums": true, 15 | "suppressImplicitAnyIndexErrors": true 16 | }, 17 | "include": [ 18 | "./**/*.ts", 19 | "./**/*.tsx" 20 | ], 21 | "atom": { 22 | "rewriteTsconfig": false 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /code/types/typeGuard.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var quick; 3 | (function (quick) { 4 | function doSomething(x) { 5 | if (typeof x === 'string') { 6 | console.log(x.subtr(1)); 7 | console.log(x.substr(1)); 8 | } 9 | x.substr(1); 10 | } 11 | })(quick = exports.quick || (exports.quick = {})); 12 | var instance; 13 | (function (instance) { 14 | var Foo = (function () { 15 | function Foo() { 16 | this.foo = 123; 17 | this.common = '123'; 18 | } 19 | return Foo; 20 | }()); 21 | var Bar = (function () { 22 | function Bar() { 23 | this.bar = 123; 24 | this.common = '123'; 25 | } 26 | return Bar; 27 | }()); 28 | function doStuff(arg) { 29 | if (arg instanceof Foo) { 30 | console.log(arg.foo); 31 | console.log(arg.bar); 32 | } 33 | if (arg instanceof Bar) { 34 | console.log(arg.foo); 35 | console.log(arg.bar); 36 | } 37 | console.log(arg.common); 38 | console.log(arg.foo); 39 | console.log(arg.bar); 40 | } 41 | doStuff(new Foo()); 42 | doStuff(new Bar()); 43 | })(instance = exports.instance || (exports.instance = {})); 44 | var instanceElse; 45 | (function (instanceElse) { 46 | var Foo = (function () { 47 | function Foo() { 48 | this.foo = 123; 49 | } 50 | return Foo; 51 | }()); 52 | var Bar = (function () { 53 | function Bar() { 54 | this.bar = 123; 55 | } 56 | return Bar; 57 | }()); 58 | function doStuff(arg) { 59 | if (arg instanceof Foo) { 60 | console.log(arg.foo); 61 | console.log(arg.bar); 62 | } 63 | else { 64 | console.log(arg.foo); 65 | console.log(arg.bar); 66 | } 67 | } 68 | doStuff(new Foo()); 69 | doStuff(new Bar()); 70 | })(instanceElse = exports.instanceElse || (exports.instanceElse = {})); 71 | var userDefined; 72 | (function (userDefined) { 73 | function isFoo(arg) { 74 | return arg.foo !== undefined; 75 | } 76 | function doStuff(arg) { 77 | if (isFoo(arg)) { 78 | console.log(arg.foo); 79 | console.log(arg.bar); 80 | } 81 | else { 82 | console.log(arg.foo); 83 | console.log(arg.bar); 84 | } 85 | } 86 | doStuff({ foo: 123, common: '123' }); 87 | doStuff({ bar: 123, common: '123' }); 88 | })(userDefined = exports.userDefined || (exports.userDefined = {})); 89 | -------------------------------------------------------------------------------- /cover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/basarat/typescript-book/e31fe92c3afeea1bbcac4381d290e75e5b3ab6e3/cover.jpg -------------------------------------------------------------------------------- /docs/compiler-options.md: -------------------------------------------------------------------------------- 1 | // mention Pinned comments 2 | 3 | ```ts 4 | /*! 5 | * License 6 | */ 7 | ``` 8 | -------------------------------------------------------------------------------- /docs/compiler/ast-tip-children.md: -------------------------------------------------------------------------------- 1 | ### AST Tip: Visit Children 2 | 3 | There is a utility function `ts.forEachChild` that allows you to visit all the child nodes of any Node in the AST. 4 | 5 | Here is simplified snippet of the source code to demonstrate how it functions: 6 | 7 | ```ts 8 | 9 | export function forEachChild(node: Node, cbNode: (node: Node) => T, cbNodeArray?: (nodes: Node[]) => T): T { 10 | if (!node) { 11 | return; 12 | } 13 | switch (node.kind) { 14 | case SyntaxKind.BinaryExpression: 15 | return visitNode(cbNode, (node).left) || 16 | visitNode(cbNode, (node).operatorToken) || 17 | visitNode(cbNode, (node).right); 18 | case SyntaxKind.IfStatement: 19 | return visitNode(cbNode, (node).expression) || 20 | visitNode(cbNode, (node).thenStatement) || 21 | visitNode(cbNode, (node).elseStatement); 22 | 23 | // .... lots more 24 | ``` 25 | 26 | Basically, it checks `node.kind` and based on that assumes an interface offered by the `node` and calls the `cbNode` on the children. However, note that this function doesn't call `visitNode` for *all* children (e.g. SyntaxKind.SemicolonToken). If you want *all* the children of a node in the AST just call `.getChildren` member function of the `Node`. 27 | 28 | E.g. here is a function that prints the verbose `AST` of a node: 29 | 30 | ```ts 31 | function printAllChildren(node: ts.Node, depth = 0) { 32 | console.log(new Array(depth+1).join('----'), ts.syntaxKindToName(node.kind), node.pos, node.end); 33 | depth++; 34 | node.getChildren().forEach(c=> printAllChildren(c, depth)); 35 | } 36 | ``` 37 | 38 | We will see a sample usage of this function when we discuss the parser further. 39 | -------------------------------------------------------------------------------- /docs/compiler/ast-tip-syntaxkind.md: -------------------------------------------------------------------------------- 1 | ### AST Tip: SyntaxKind 2 | 3 | `SyntaxKind` is defined as a `const enum`, here is a sample: 4 | 5 | ```ts 6 | export const enum SyntaxKind { 7 | Unknown, 8 | EndOfFileToken, 9 | SingleLineCommentTrivia, 10 | // ... LOTS more 11 | ``` 12 | 13 | It's a `const enum` (a concept [we covered previously](../enums.md)) so that it gets *inlined* (e.g. `ts.SyntaxKind.EndOfFileToken` becomes `1`) and we don't get a dereferencing cost when working with the AST. However, the compiler is compiled with `--preserveConstEnums` compiler flag so that the enum *is still available at runtime*. So in JavaScript you can use `ts.SyntaxKind.EndOfFileToken` if you want. Additionally you can convert these enum members to display strings using the following function: 14 | 15 | ```ts 16 | export function syntaxKindToName(kind: ts.SyntaxKind) { 17 | return (ts).SyntaxKind[kind]; 18 | } 19 | ``` 20 | -------------------------------------------------------------------------------- /docs/compiler/ast-trivia.md: -------------------------------------------------------------------------------- 1 | ### Trivia 2 | Trivia (called that because it's `trivial`) represent the parts of the source text that are largely insignificant for normal understanding of the code. For example; whitespace, comments, and even conflict markers. Trivia is *not stored* in the AST (to keep it lightweight). However, it can be fetched *on demand* using a few `ts.*` APIs. 3 | 4 | Before we show them you need to understand the following: 5 | 6 | #### Trivia Ownership 7 | In General: 8 | * A token owns any trivia after it on the *same* line *upto* the next token. 9 | * Any comment *after that line* is associated with the following token. 10 | 11 | For leading and ending comments in a file: 12 | * The first token in the source file gets all the initial trivia. 13 | * The last sequence of trivia in the file is tacked onto the end-of-file token, which otherwise has zero width. 14 | 15 | #### Trivia APIs 16 | For most basic uses, comments are the "interesting" trivia. The comments that belong to a Node can be fetched through the following functions: 17 | 18 | Function | Description 19 | ---------|------------ 20 | `ts.getLeadingCommentRanges` | Given the source text and position within that text, returns ranges of comments between the first line break following the given position and the token itself (probably most useful with `ts.Node.getFullStart`). 21 | `ts.getTrailingCommentRanges` | Given the source text and position within that text, returns ranges of comments until the first line break following the given position (probably most useful with `ts.Node.getEnd`). 22 | 23 | As an example, imagine this portion of a source file: 24 | 25 | ```ts 26 | debugger;/*hello*/ 27 | //bye 28 | /*hi*/ function 29 | ``` 30 | 31 | `getLeadingCommentRanges` for the `function` will only return the last 2 comments `//bye` and `/*hi*/`. 32 | 33 | Appropriately, calling `getTrailingCommentRanges` on the end of the debugger statement will extract the `/*hello*/` comment. 34 | 35 | #### Token Start/Full Start 36 | Nodes have what is called a "token start" and a "full start". 37 | 38 | * Token Start: the more natural version, which is the position in file where the text of a token begins 39 | * Full Start: the point at which the scanner began scanning since the last significant token 40 | 41 | AST nodes have an API for `getStart` and `getFullStart`. In the following example: 42 | 43 | ```ts 44 | debugger;/*hello*/ 45 | //bye 46 | /*hi*/ function 47 | ``` 48 | for `function` the token start is at `function` whereas *full* start is at `/*hello*/`. Note that full start even includes the trivia that would otherwise be owned by the previous node. 49 | -------------------------------------------------------------------------------- /docs/compiler/ast.md: -------------------------------------------------------------------------------- 1 | ## Node 2 | The basic building block of the Abstract Syntax Tree (AST). In general a `Node` represents non-terminals in the language grammar; however, some terminals are kept in the tree such as identifiers and literals. 3 | 4 | Two key things make up an AST node's documentation. The node's `SyntaxKind` which identifies its type within the AST, and its `interface`, the API the node provides when instantiated into the AST. 5 | 6 | Here are a few key `interface Node` members: 7 | * `TextRange` members that identify the node's `start` and `end` in the source file. 8 | * `parent?: Node` the parent of the node in the AST. 9 | 10 | There are other additional members for `Node` flags and modifiers etc. that you can lookup by searching `interface Node` in the source code but the ones we mentioned are vital for node traversal. 11 | 12 | ## SourceFile 13 | 14 | * `SyntaxKind.SourceFile` 15 | * `interface SourceFile`. 16 | 17 | Each `SourceFile` is a top-level AST node that is contained in the `Program`. 18 | -------------------------------------------------------------------------------- /docs/compiler/binder-declarations.md: -------------------------------------------------------------------------------- 1 | ### Symbols and Declarations 2 | Linking between a `node` and a `symbol` is performed by a few functions. One function that is used to bind the `SourceFile` node to the source file Symbol (in case of an external module) is the `addDeclarationToSymbol` function 3 | 4 | Note : the `Symbol` for an external module source file is setup as `flags : SymbolFlags.ValueModule` and `name: '"' + removeFileExtension(file.fileName) + '"'`). 5 | 6 | ```ts 7 | function addDeclarationToSymbol(symbol: Symbol, node: Declaration, symbolFlags: SymbolFlags) { 8 | symbol.flags |= symbolFlags; 9 | 10 | node.symbol = symbol; 11 | 12 | if (!symbol.declarations) { 13 | symbol.declarations = []; 14 | } 15 | symbol.declarations.push(node); 16 | 17 | if (symbolFlags & SymbolFlags.HasExports && !symbol.exports) { 18 | symbol.exports = {}; 19 | } 20 | 21 | if (symbolFlags & SymbolFlags.HasMembers && !symbol.members) { 22 | symbol.members = {}; 23 | } 24 | 25 | if (symbolFlags & SymbolFlags.Value && !symbol.valueDeclaration) { 26 | symbol.valueDeclaration = node; 27 | } 28 | } 29 | ``` 30 | 31 | The important linking portions: 32 | * Creates a link to the Symbol from the AST node (`node.symbol`). 33 | * Adds the node as *one of* the declarations of the Symbol (`symbol.declarations`). 34 | 35 | #### Declaration 36 | Declaration is just a `node` with an optional name. In `types.ts` 37 | 38 | ```ts 39 | interface Declaration extends Node { 40 | _declarationBrand: any; 41 | name?: DeclarationName; 42 | } 43 | ``` 44 | -------------------------------------------------------------------------------- /docs/compiler/binder-diagnostics.md: -------------------------------------------------------------------------------- 1 | ### Binder Error Reporting 2 | 3 | Binding errors are added to the sourceFile's list of `bindDiagnostics`. 4 | 5 | An example error detected during binding is the use of `eval` or `arguments` as a variable name in `use strict` scenario. The relevant code is presented in its entirety below (`checkStrictModeEvalOrArguments` is called from multiple places, call stacks originating from `bindWorker` which calls different functions for different node `SyntaxKind`): 6 | 7 | ```ts 8 | function checkStrictModeEvalOrArguments(contextNode: Node, name: Node) { 9 | if (name && name.kind === SyntaxKind.Identifier) { 10 | let identifier = name; 11 | if (isEvalOrArgumentsIdentifier(identifier)) { 12 | // We check first if the name is inside class declaration or class expression; if so give explicit message 13 | // otherwise report generic error message. 14 | let span = getErrorSpanForNode(file, name); 15 | file.bindDiagnostics.push(createFileDiagnostic(file, span.start, span.length, 16 | getStrictModeEvalOrArgumentsMessage(contextNode), identifier.text)); 17 | } 18 | } 19 | } 20 | 21 | function isEvalOrArgumentsIdentifier(node: Node): boolean { 22 | return node.kind === SyntaxKind.Identifier && 23 | ((node).text === "eval" || (node).text === "arguments"); 24 | } 25 | 26 | function getStrictModeEvalOrArgumentsMessage(node: Node) { 27 | // Provide specialized messages to help the user understand why we think they're in 28 | // strict mode. 29 | if (getContainingClass(node)) { 30 | return Diagnostics.Invalid_use_of_0_Class_definitions_are_automatically_in_strict_mode; 31 | } 32 | 33 | if (file.externalModuleIndicator) { 34 | return Diagnostics.Invalid_use_of_0_Modules_are_automatically_in_strict_mode; 35 | } 36 | 37 | return Diagnostics.Invalid_use_of_0_in_strict_mode; 38 | } 39 | ``` 40 | -------------------------------------------------------------------------------- /docs/compiler/binder-functions.md: -------------------------------------------------------------------------------- 1 | ### Binder function 2 | Two critical binder functions are `bindSourceFile` and `mergeSymbolTable`. We will take a look at these next. 3 | 4 | #### `bindSourceFile` 5 | Basically checks if `file.locals` is defined, if not it hands over to (a local function) `bind`. 6 | 7 | Note: `locals` is defined on `Node` and is of type `SymbolTable`. Note that `SourceFile` is also a `Node` (in fact a root node in the AST). 8 | 9 | TIP: local functions are used heavily within the TypeScript compiler. A local function very likely uses variables from the parent function (captured by closure). In the case of `bind` (a local function within `bindSourceFile`) it (or a function it calls) will setup the `symbolCount` and `classifiableNames` among others, that are then stored on the returned `SourceFile`. 10 | 11 | #### `bind` 12 | Bind takes any `Node` (not just `SourceFile`). First thing it does is assign the `node.parent` (if `parent` variable has been setup ... which again is something the binder does during its processing within the `bindChildren` function), then hands off to `bindWorker` which does the *heavy* lifting. Finally it calls `bindChildren` (a function that simply stores the binder state e.g. current `parent` within its function local vars, then calls `bind` on each child, and then restores the binder state). Now let's look at `bindWorker` which is the more interesting function. 13 | 14 | #### `bindWorker` 15 | This function switches on `node.kind` (of type `SyntaxKind`) and delegates work to the appropriate `bindFoo` function (also defined within `binder.ts`). For example if the `node` is a `SourceFile` it calls (eventually and only if its an external file module) `bindAnonymousDeclaration` 16 | 17 | #### `bindFoo` functions 18 | There are a few patterns common to `bindFoo` functions as well as some utility functions that these use. One function that is almost always used is the `createSymbol` function. It is presented in its entirety below: 19 | 20 | ```ts 21 | function createSymbol(flags: SymbolFlags, name: string): Symbol { 22 | symbolCount++; 23 | return new Symbol(flags, name); 24 | } 25 | ``` 26 | As you can see it is simply keeping the `symbolCount` (a local to `bindSourceFile`) up to date and creating the symbol with the specified parameters. 27 | -------------------------------------------------------------------------------- /docs/compiler/binder.md: -------------------------------------------------------------------------------- 1 | ## Binder 2 | Most JavaScript transpilers out there are simpler than TypeScript because they provide little in the way of code analysis. The typical JavaScript transpilers only have the following flow: 3 | 4 | ```ts 5 | SourceCode ~~Scanner~~> Tokens ~~Parser~~> AST ~~Emitter~~> JavaScript 6 | ``` 7 | 8 | While the above architecture is true as a simplified understanding of TypeScript js generation, a key feature of TypeScript is its *Semantic* system. In order to assist type checking (performed by the `checker`), the `binder` (in `binder.ts`) is used to connect the various parts of the source code into a coherent type system that can then be used by the `checker`. The main responsibility of the binder is to create _Symbols_. 9 | 10 | ### Symbol 11 | Symbols connect declaration nodes in the AST to other declarations contributing to the same entity. Symbols are the basic building blocks of the Semantic system. The symbol constructor is defined in `core.ts` (and `binder` actually uses the `objectAllocator.getSymbolConstructor` to get its hands on it). Here is the symbol constructor: 12 | 13 | ```ts 14 | function Symbol(flags: SymbolFlags, name: string) { 15 | this.flags = flags; 16 | this.name = name; 17 | this.declarations = undefined; 18 | } 19 | ``` 20 | 21 | `SymbolFlags` is a flag enum and is really used to identify additional classifications of the symbol (e.g. variable scope flags `FunctionScopedVariable` or `BlockScopedVariable` among others) 22 | 23 | ### Usage by Checker 24 | The `binder` is actually used internally by the type `checker` which in turn is used by the `program`. The simplified call stack looks like: 25 | ``` 26 | program.getTypeChecker -> 27 | ts.createTypeChecker (in checker)-> 28 | initializeTypeChecker (in checker) -> 29 | for each SourceFile `ts.bindSourceFile` (in binder) 30 | // followed by 31 | for each SourceFile `ts.mergeSymbolTable` (in checker) 32 | ``` 33 | The unit of work for the binder is a SourceFile. The `binder.ts` is driven by `checker.ts`. 34 | -------------------------------------------------------------------------------- /docs/compiler/checker-diagnostics.md: -------------------------------------------------------------------------------- 1 | ### Checker error reporting 2 | The checker uses the local `error` function to report errors. Here is the function: 3 | 4 | ```ts 5 | function error(location: Node, message: DiagnosticMessage, arg0?: any, arg1?: any, arg2?: any): void { 6 | let diagnostic = location 7 | ? createDiagnosticForNode(location, message, arg0, arg1, arg2) 8 | : createCompilerDiagnostic(message, arg0, arg1, arg2); 9 | diagnostics.add(diagnostic); 10 | } 11 | ``` 12 | -------------------------------------------------------------------------------- /docs/compiler/checker-global.md: -------------------------------------------------------------------------------- 1 | ### Global Namespace Merging 2 | Within `initializeTypeChecker` the following code exists: 3 | 4 | ```ts 5 | // Initialize global symbol table 6 | forEach(host.getSourceFiles(), file => { 7 | if (!isExternalModule(file)) { 8 | mergeSymbolTable(globals, file.locals); 9 | } 10 | }); 11 | ``` 12 | 13 | Which basically merges all the `global` symbols into the `let globals: SymbolTable = {};` (in `createTypeChecker`) SymbolTable. `mergeSymbolTable` primarily calls `mergeSymbol`. 14 | -------------------------------------------------------------------------------- /docs/compiler/checker.md: -------------------------------------------------------------------------------- 1 | ## Checker 2 | Like we mentioned before *checker* is the thing that makes TypeScript uniquely more powerful than *just another JavaScript transpiler*. The checker is located in `checker.ts` and at this moment it is 23k+ lines of TypeScript (largest part of the compiler). 3 | 4 | ### Usage by Program 5 | The `checker` is initialized by `program`. The following is a sampling of the call stack (we showed the same one when looking at `binder`): 6 | 7 | ``` 8 | program.getTypeChecker -> 9 | ts.createTypeChecker (in checker)-> 10 | initializeTypeChecker (in checker) -> 11 | for each SourceFile `ts.bindSourceFile` (in binder) 12 | // followed by 13 | for each SourceFile `ts.mergeSymbolTable` (in checker) 14 | ``` 15 | 16 | ### Association with Emitter 17 | True type checking happens once a call is made to `getDiagnostics`. This function is called e.g. once a request is made to `Program.emit`, in which case the checker returns an `EmitResolver` (program calls the checkers `getEmitResolver` function) which is just a set of functions local to `createTypeChecker`. We will mention this again when we look at the emitter. 18 | 19 | Here is the call stack right down to `checkSourceFile` (a function local to `createTypeChecker`). 20 | 21 | ``` 22 | program.emit -> 23 | emitWorker (program local) -> 24 | createTypeChecker.getEmitResolver -> 25 | // First call the following functions local to createTypeChecker 26 | call getDiagnostics -> 27 | getDiagnosticsWorker -> 28 | checkSourceFile 29 | 30 | // then 31 | return resolver 32 | (already initialized in createTypeChecker using a call to local createResolver()) 33 | ``` 34 | -------------------------------------------------------------------------------- /docs/compiler/emitter.md: -------------------------------------------------------------------------------- 1 | ## Emitter 2 | There are two `emitters` provided with the TypeScript compiler: 3 | 4 | * `emitter.ts`: this is the emitter you are most likely to be interested in. Its the TS -> JavaScript emitter. 5 | * `declarationEmitter.ts`: this is the emitter used to create a *declaration file* (a `.d.ts`) for a *TypeScript source file* (a `.ts` file). 6 | 7 | We will look at `emitter.ts` in this section. 8 | 9 | ### Usage by `program` 10 | Program provides an `emit` function. This function primarily delegates to `emitFiles` function in `emitter.ts`. Here is the call stack: 11 | 12 | ``` 13 | Program.emit -> 14 | `emitWorker` (local in program.ts createProgram) -> 15 | `emitFiles` (function in emitter.ts) 16 | ``` 17 | One thing that the `emitWorker` provides to the emitter (via an argument to `emitFiles`) is an `EmitResolver`. `EmitResolver` is provided by the program's TypeChecker, basically it is a subset of *local* functions from `createChecker`. 18 | -------------------------------------------------------------------------------- /docs/compiler/make-global.md: -------------------------------------------------------------------------------- 1 | ## Make TypeScript Global 2 | 3 | TypeScript is written using a `namespace ts`. And then the whole compiler is compiled into a single `typescript.js` file. If you want to copy over parts of the source code for exploration a great way to do that is to copy over the portions that you are exploring and then expose them to the global variable `ts`. 4 | 5 | A great way to play around with the TypeScript compiler is just to copy the TypeScript compiler source into a folder and then reference it as a `global` variable. 6 | -------------------------------------------------------------------------------- /docs/compiler/program.md: -------------------------------------------------------------------------------- 1 | ## Program 2 | 3 | Defined in `program.ts`. The compilation context ([a concept we covered previously](../project/compilation-context.md)) is represented within the TypeScript compiler as a `Program`. It consists of `SourceFile`s and compiler options. 4 | 5 | 6 | ### Usage of `CompilerHost` 7 | Its interaction mechanism with the OE: 8 | 9 | `Program` *-uses->* `CompilerHost` *-uses->* `System` 10 | 11 | The reason for having a `CompilerHost` as a point of indirection is that it allows its interface to be more finely tuned for `Program` needs and not bother with OE needs (e.g. the `Program` doesn't care about `fileExists` a function provided by `System`). 12 | 13 | There are other users of `System` as well (e.g. tests). 14 | 15 | ### SourceFile 16 | 17 | The program provides an API to get the Source Files `getSourceFiles(): SourceFile[];`. Each is represented as a root-level node for an AST (called `SourceFile`). 18 | -------------------------------------------------------------------------------- /docs/const.md: -------------------------------------------------------------------------------- 1 | ### const 2 | 3 | `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`: 4 | 5 | ```ts 6 | const foo = 123; 7 | ``` 8 | 9 | > 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. 10 | 11 | `const` is a good practice for both readability and maintainability and avoids using *magic literals* e.g. 12 | 13 | ```ts 14 | // Low readability 15 | if (x > 10) { 16 | } 17 | 18 | // Better! 19 | const maxRows = 10; 20 | if (x > maxRows) { 21 | } 22 | ``` 23 | 24 | #### const declarations must be initialized 25 | The following is a compiler error: 26 | 27 | ```ts 28 | const foo; // ERROR: const declarations must be initialized 29 | ``` 30 | 31 | #### Left hand side of assignment cannot be a constant 32 | Constants are immutable after creation, so if you try to assign them to a new value it is a compiler error: 33 | 34 | ```ts 35 | const foo = 123; 36 | foo = 456; // ERROR: Left-hand side of an assignment expression cannot be a constant 37 | ``` 38 | 39 | #### Block Scoped 40 | A `const` is block scoped like we saw with [`let`](./let.md): 41 | 42 | ```ts 43 | const foo = 123; 44 | if (true) { 45 | const foo = 456; // Allowed as its a new variable limited to this `if` block 46 | } 47 | ``` 48 | 49 | #### Deep immutability 50 | A `const` works with object literals as well, as far as protecting the variable *reference* is concerned: 51 | 52 | ```ts 53 | const foo = { bar: 123 }; 54 | foo = { bar: 456 }; // ERROR : Left hand side of an assignment expression cannot be a constant 55 | ``` 56 | 57 | However, it still allows sub properties of objects to be mutated, as shown below: 58 | 59 | ```ts 60 | const foo = { bar: 123 }; 61 | foo.bar = 456; // Allowed! 62 | console.log(foo); // { bar: 456 } 63 | ``` 64 | 65 | #### Prefer const 66 | 67 | Always use `const`, unless you plan to either lazily initialization of a variable, or do a reassignment (use `let` for those cases). 68 | -------------------------------------------------------------------------------- /docs/declaration.md: -------------------------------------------------------------------------------- 1 | analogy with c headers 2 | -------------------------------------------------------------------------------- /docs/errors/common-errors.md: -------------------------------------------------------------------------------- 1 | # Common Errors 2 | In this section we explain a number of common error codes that users experience in the real world. 3 | 4 | ## TS2304 5 | Samples: 6 | > `Cannot find name ga` 7 | > `Cannot find name $` 8 | > `Cannot find module jquery` 9 | 10 | You are probably using a third party library (e.g. google analytics) and don't have it `declare`d. TypeScript tries to save you from *spelling mistakes* and *using variables without declaring them* so you need to be explicit on anything that is *available at runtime* because of you including some external library ([more on how to fix it][ambient]). 11 | 12 | ## TS2307 13 | Samples: 14 | > `Cannot find module 'underscore'` 15 | 16 | You are probably using a third party library (e.g. underscore) as a *module* ([more on modules][modules]) and don't have the ambient declaration file for it ([more on ambient declarations][ambient]). 17 | 18 | ## TS1148 19 | Sample: 20 | > Cannot compile modules unless the '--module' flag is provided 21 | 22 | Checkout the [section on modules][modules]. 23 | 24 | ## Catch clause variable cannot have a type annotation 25 | Sample: 26 | ```js 27 | try { something(); } 28 | catch (e: Error) { // Catch clause variable cannot have a type annotation 29 | } 30 | ``` 31 | TypeScript is protecting you from JavaScript code in the wild being wrong. Use a type guard instead: 32 | ```js 33 | try { something(); } 34 | catch (e) { 35 | if (e instanceof Error){ 36 | // Here you go. 37 | } 38 | } 39 | ``` 40 | 41 | ## Interface `ElementClass` cannot simultaneously extend types `Component` and `Component` 42 | This happens when you have two `react.d.ts` (`@types/react/index.d.ts`) in the compilation context. 43 | 44 | **Fix**: 45 | * Delete `node_modules` and any `package-lock` (or yarn lock) and `npm install` again. 46 | * If it doesn't work, find the invalid module (all modules used by your project should have `react.d.ts` as a `peerDependency` and not a hard `dependency`) and report it on their project. 47 | 48 | 49 | [ambient]: ../types/ambient/d.ts.md 50 | [modules]: ../project/modules.md 51 | -------------------------------------------------------------------------------- /docs/errors/main.md: -------------------------------------------------------------------------------- 1 | # Errors 2 | In this section we discuss how to read and understand TypeScript errors. We follow this with common errors and their solutions. 3 | -------------------------------------------------------------------------------- /docs/future-javascript.md: -------------------------------------------------------------------------------- 1 | # Future JavaScript: Now 2 | 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. 3 | 4 | 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 ;) 5 | -------------------------------------------------------------------------------- /docs/getting-started.md: -------------------------------------------------------------------------------- 1 | * [Getting Started with TypeScript](#getting-started-with-typescript) 2 | * [TypeScript Version](#typescript-version) 3 | 4 | # Getting Started With TypeScript 5 | 6 | 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: 7 | 8 | * TypeScript compiler (OSS available [in source](https://github.com/Microsoft/TypeScript/) and on [NPM](https://www.npmjs.com/package/typescript)) 9 | * 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)) 10 | 11 | 12 | ## TypeScript Version 13 | 14 | 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**. 15 | 16 | You can install it on the command line as 17 | 18 | ``` 19 | npm install -g typescript@next 20 | ``` 21 | 22 | And now the command line `tsc` will be the latest and greatest. Various IDEs support it too, e.g. 23 | 24 | * You can ask vscode to use this version by creating `.vscode/settings.json` with the following contents: 25 | 26 | ```json 27 | { 28 | "typescript.tsdk": "./node_modules/typescript/lib" 29 | } 30 | ``` 31 | 32 | ## Getting the Source Code 33 | The source for this book is available in the books github repository 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. 34 | 35 | `this/will/be/the/link/to/the/code.ts` 36 | ```ts 37 | // This will be the code under discussion 38 | ``` 39 | 40 | With a dev setup out of the way let's jump into TypeScript syntax. 41 | -------------------------------------------------------------------------------- /docs/javascript/closure.md: -------------------------------------------------------------------------------- 1 | ## Closure 2 | 3 | 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: 4 | 5 | ```ts 6 | function outerFunction(arg) { 7 | var variableInOuterFunction = arg; 8 | 9 | function bar() { 10 | console.log(variableInOuterFunction); // Access a variable from the outer scope 11 | } 12 | 13 | // Call the local function to demonstrate that it has access to arg 14 | bar(); 15 | } 16 | 17 | outerFunction("hello closure"); // logs hello closure! 18 | ``` 19 | 20 | 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. 21 | 22 | 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: 23 | 24 | ```ts 25 | function outerFunction(arg) { 26 | var variableInOuterFunction = arg; 27 | return function() { 28 | console.log(variableInOuterFunction); 29 | } 30 | } 31 | 32 | var innerFunction = outerFunction("hello closure!"); 33 | 34 | // Note the outerFunction has returned 35 | innerFunction(); // logs hello closure! 36 | ``` 37 | 38 | ### Reason why it's awesome 39 | It allows you to compose objects easily e.g. the revealing module pattern: 40 | 41 | ```ts 42 | function createCounter() { 43 | let val = 0; 44 | return { 45 | increment() { val++ }, 46 | getVal() { return val } 47 | } 48 | } 49 | 50 | let counter = createCounter(); 51 | counter.increment(); 52 | console.log(counter.getVal()); // 1 53 | counter.increment(); 54 | console.log(counter.getVal()); // 2 55 | ``` 56 | 57 | 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 🌹): 58 | 59 | ```ts 60 | // Pseudo code to explain the concept 61 | server.on(function handler(req, res) { 62 | loadData(req.id).then(function(data) { 63 | // the `res` has been closed over and is available 64 | res.send(data); 65 | }) 66 | }); 67 | ``` 68 | -------------------------------------------------------------------------------- /docs/javascript/equality.md: -------------------------------------------------------------------------------- 1 | ## Equality 2 | 3 | One thing to be careful about in JavaScript is the difference between `==` and `===`. As JavaScript tries to 4 | be resilient against programming errors `==` tries to do type coercion between two variables e.g. converts a 5 | string to a number so that you can compare with a number as shown below: 6 | 7 | ```js 8 | console.log(5 == "5"); // true , TS Error 9 | console.log(5 === "5"); // false , TS Error 10 | ``` 11 | 12 | However, the choices JavaScript makes are not always ideal. For example, in the below example the first statement is false 13 | because `""` and `"0"` are both strings and are clearly not equal. However, in the second case both `0` and the 14 | empty string (`""`) are falsy (i.e. behave like `false`) and are therefore equal with respect to `==`. Both statements 15 | are false when you use `===`. 16 | 17 | ```js 18 | console.log("" == "0"); // false 19 | console.log(0 == ""); // true 20 | 21 | console.log("" === "0"); // false 22 | console.log(0 === ""); // false 23 | ``` 24 | 25 | > Note that `string == number` and `string === number` are both compile time errors in TypeScript, so you don't normally need to worry about this. 26 | 27 | Similar to `==` vs. `===`, there is `!=` vs. `!==` 28 | 29 | So ProTip: Always use `===` and `!==` except for null checks, which we cover later. 30 | 31 | ## Structural Equality 32 | If you want to compare two objects for structural equality `==`/`===` are ***not*** sufficient. e.g. 33 | 34 | ```js 35 | console.log({a:123} == {a:123}); // False 36 | console.log({a:123} === {a:123}); // False 37 | ``` 38 | To do such checks use the [deep-equal](https://www.npmjs.com/package/deep-equal) npm package e.g. 39 | 40 | ```js 41 | import * as deepEqual from "deep-equal"; 42 | 43 | console.log(deepEqual({a:123},{a:123})); // True 44 | ``` 45 | 46 | However, quite commonly you don't need deep checks and all you really need is to check by some `id` e.g. 47 | 48 | ```ts 49 | type IdDisplay = { 50 | id: string, 51 | display: string 52 | } 53 | const list: IdDisplay[] = [ 54 | { 55 | id: 'foo', 56 | display: 'Foo Select' 57 | }, 58 | { 59 | id: 'bar', 60 | display: 'Bar Select' 61 | }, 62 | ] 63 | 64 | const fooIndex = list.map(i => i.id).indexOf('foo'); 65 | console.log(fooIndex); // 0 66 | ``` 67 | -------------------------------------------------------------------------------- /docs/javascript/recap.md: -------------------------------------------------------------------------------- 1 | # Your JavaScript is TypeScript 2 | 3 | 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: 4 | 5 | ![JavaScript is TypeScript](https://raw.githubusercontent.com/basarat/typescript-book/master/images/venn.png) 6 | 7 | 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. 8 | 9 | * Just giving you a new syntax doesn't help catch bugs - but might help you write cleaner / less bugs (e.g. CoffeeScript). 10 | * 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). 11 | 12 | TypeScript is just JavaScript with docs. 13 | 14 | > 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/). 15 | 16 | ## Making JavaScript Better 17 | 18 | TypeScript will try to protect you from portions of JavaScript that never worked (so you don't need to remember this stuff): 19 | 20 | ```ts 21 | [] + []; // JavaScript will give you "" (which makes little sense), TypeScript will error 22 | 23 | // 24 | // other things that are nonsensical in JavaScript 25 | // - don't give a runtime error (making debugging hard) 26 | // - but TypeScript will give a compile time error (making debugging unnecessary) 27 | // 28 | {} + []; // JS : 0, TS Error 29 | [] + {}; // JS : "[object Object]", TS Error 30 | {} + {}; // JS : NaN or [object Object][object Object] depending upon browser, TS Error 31 | "hello" - 1; // JS : NaN, TS Error 32 | 33 | function add(a,b) { 34 | return 35 | a + b; // JS : undefined, TS Error 'unreachable code detected' 36 | } 37 | ``` 38 | 39 | Essentially TypeScript is linting JavaScript. Just doing a better job at it than other linters that don't have *type information*. 40 | 41 | ## You still need to learn JavaScript 42 | 43 | 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. 44 | 45 | > Note: TypeScript is a superset of JavaScript. Just with documentation that can actually be used by compilers / IDEs ;) 46 | -------------------------------------------------------------------------------- /docs/javascript/references.md: -------------------------------------------------------------------------------- 1 | ## References 2 | 3 | Beyond literals, any Object in JavaScript (including functions, arrays, regexp etc) are references. This means the following 4 | 5 | ### Mutations are across all references 6 | 7 | ```js 8 | var foo = {}; 9 | var bar = foo; // bar is a reference to the same object 10 | 11 | foo.baz = 123; 12 | console.log(bar.baz); // 123 13 | ``` 14 | 15 | ### Equality is for references 16 | 17 | ```js 18 | var foo = {}; 19 | var bar = foo; // bar is a reference 20 | var baz = {}; // baz is a *new object* distinct from `foo` 21 | 22 | console.log(foo === bar); // true 23 | console.log(foo === baz); // false 24 | ``` 25 | -------------------------------------------------------------------------------- /docs/javascript/this.md: -------------------------------------------------------------------------------- 1 | ## this 2 | 3 | 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.” 4 | 5 | Here is an example: 6 | 7 | ```ts 8 | function foo() { 9 | console.log(this); 10 | } 11 | 12 | foo(); // logs out the global e.g. `window` in browsers 13 | let bar = { 14 | foo 15 | } 16 | bar.foo(); // Logs out `bar` as `foo` was called on `bar` 17 | ``` 18 | 19 | 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][arrow]. 20 | 21 | [arrow]:../arrow-functions.md 22 | -------------------------------------------------------------------------------- /docs/javascript/truthy.md: -------------------------------------------------------------------------------- 1 | ## Truthy 2 | 3 | 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. 4 | 5 | ```ts 6 | if (123) { // Will be treated like `true` 7 | console.log('Any number other than 0 is truthy'); 8 | } 9 | ``` 10 | 11 | Something that isn't truthy is called `falsy`. 12 | 13 | Here's a handy table for your reference. 14 | 15 | | Variable Type | When it is *falsy* | When it is *truthy* | 16 | |-----------------|--------------------------|--------------------------| 17 | | `boolean` | `false` | `true` | 18 | | `string` | `''` (empty string) | any other string | 19 | | `number` | `0` `NaN` | any other number | 20 | | `null` | always | never | 21 | | `undefined` | always | never | 22 | | Any other Object including empty ones like `{}`,`[]` | never | always | 23 | 24 | 25 | ### Being explicit 26 | 27 | > The `!!` pattern 28 | 29 | 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`). 30 | 31 | It is common to use this pattern in lots of places e.g. 32 | 33 | ```js 34 | // Direct variables 35 | const hasName = !!name; 36 | 37 | // As members of objects 38 | const someObj = { 39 | hasName: !!name 40 | } 41 | 42 | // e.g. in ReactJS JSX 43 | {!!someName &&
{someName}
} 44 | ``` 45 | -------------------------------------------------------------------------------- /docs/jsx/others.md: -------------------------------------------------------------------------------- 1 | # Non React JSX 2 | 3 | [![DesignTSX](https://raw.githubusercontent.com/basarat/typescript-book/master/images/designtsx-banner.png)](https://designtsx.com) 4 | 5 | TypeScript provides you with the ability to use something other than React with JSX in a type safe manner. The following lists the customizability points, but note that this is for advanced UI framework authors: 6 | 7 | * You can disable `react` style emit by using `"jsx" : "preserve"` option. This means that JSX is emitted *as is* and then you can use your own custom transpiler to transpile the JSX portions. 8 | * Using the `JSX` global module: 9 | * You can control what HTML tags are available and how they are type checked by customizing the `JSX.IntrinsicElements` interface members. 10 | * When using components: 11 | * You can control which `class` must be inherited by components by customizing the default `interface ElementClass extends React.Component { }` declaration. 12 | * You can control which property is used to type check the attributes (the default is `props`) by customizing the `declare module JSX { interface ElementAttributesProperty { props: {}; } }` declaration. 13 | 14 | ## `jsxFactory` 15 | 16 | Passing `--jsxFactory ` along with `--jsx react` allows for using a different JSX factory from the default `React`. 17 | 18 | The new factory name will be used to call `createElement` functions. 19 | 20 | ### Example 21 | 22 | ```ts 23 | import {jsxFactory} from "jsxFactory"; 24 | 25 | var div =
Hello JSX!
26 | ``` 27 | 28 | Compiled with: 29 | 30 | ```shell 31 | tsc --jsx react --reactNamespace jsxFactory --m commonJS 32 | ``` 33 | 34 | Results in: 35 | 36 | ```js 37 | "use strict"; 38 | var jsxFactory_1 = require("jsxFactory"); 39 | var div = jsxFactory_1.jsxFactory.createElement("div", null, "Hello JSX!"); 40 | ``` 41 | 42 | ## `jsx` pragma 43 | 44 | You can even specify a different `jsxFactory` per file using `jsxPragma` e.g. 45 | 46 | 47 | ```js 48 | /** @jsx jsxFactory */ 49 | import {jsxFactory} from "jsxFactory"; 50 | 51 | var div =
Hello JSX!
52 | ``` 53 | 54 | With `--jsx react` this file will emit to use the factory specfied in the jsx pragma: 55 | ```js 56 | "use strict"; 57 | var jsxFactory_1 = require("jsxFactory"); 58 | var div = jsxFactory_1.jsxFactory.createElement("div", null, "Hello JSX!"); 59 | ``` 60 | -------------------------------------------------------------------------------- /docs/jsx/tsx.md: -------------------------------------------------------------------------------- 1 | # JSX Support 2 | 3 | [![DesignTSX](https://raw.githubusercontent.com/basarat/typescript-book/master/images/designtsx-banner.png)](https://designtsx.com) 4 | 5 | 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/): 6 | 7 | > 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. 8 | 9 | The motivation behind JSX is to allow users to write HTML like views *in JavaScript* so that you can: 10 | 11 | * Have the view Type Checked by the same code that is going to check your JavaScript 12 | * Have the view be aware of the context it is going to operate under (i.e. strengthen the *controller-view* connection in traditional MVC). 13 | * Reuse JavaScript patterns for HTML maintenance e.g. `Array.prototype.map`, `?:`, `switch` etc instead of creating new (and probably poorly typed) alternatives. 14 | 15 | 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. 16 | -------------------------------------------------------------------------------- /docs/options/intro.md: -------------------------------------------------------------------------------- 1 | # Convenience vs. Soundness 2 | 3 | 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). 4 | 5 | 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. 6 | 7 | ## Boolean Options 8 | 9 | `compilerOptions` that are `boolean` can be specified as `compilerOptions` in `tsconfig.json`: 10 | 11 | ```json 12 | { 13 | "compilerOptions": { 14 | "someBooleanOption": true 15 | } 16 | } 17 | ``` 18 | 19 | or on the command line 20 | 21 | ```sh 22 | tsc --someBooleanOption 23 | ``` 24 | 25 | > All of these are `false` by default. 26 | 27 | Click [here](https://www.typescriptlang.org/docs/handbook/compiler-options.html) to see all compiler options. 28 | -------------------------------------------------------------------------------- /docs/options/noImplicitAny.md: -------------------------------------------------------------------------------- 1 | # noImplicitAny 2 | 3 | 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. 4 | 5 | ```ts 6 | function log(someArg) { 7 | sendDataToServer(someArg); 8 | } 9 | 10 | // What arg is valid and what isn't? 11 | log(123); 12 | log('hello world'); 13 | ``` 14 | 15 | 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. 16 | 17 | ```ts 18 | function log(someArg) { // Error : someArg has an implicit `any` type 19 | sendDataToServer(someArg); 20 | } 21 | ``` 22 | 23 | Of course you can then go ahead and annotate: 24 | 25 | ```ts 26 | function log(someArg: number) { 27 | sendDataToServer(someArg); 28 | } 29 | ``` 30 | 31 | And if you truly want *zero safety* you can mark it *explicitly* as `any`: 32 | 33 | ```ts 34 | function log(someArg: any) { 35 | sendDataToServer(someArg); 36 | } 37 | ``` 38 | -------------------------------------------------------------------------------- /docs/project/compilation-context.md: -------------------------------------------------------------------------------- 1 | ## Compilation Context 2 | The compilation context is basically just a fancy term for grouping of the files that TypeScript will parse and analyze to determine what is valid and what isn't. Along with the information about which files, the compilation context contains information about *which compiler options* are in use. A great way to define this logical grouping (we also like to use the term *project*) is using a `tsconfig.json` file. 3 | -------------------------------------------------------------------------------- /docs/project/declarationspaces.md: -------------------------------------------------------------------------------- 1 | ## Declaration Spaces 2 | 3 | There are two declaration spaces in TypeScript: the *variable* declaration space and the *type* declaration space. These concepts are explored below. 4 | 5 | ### Type Declaration Space 6 | The type declaration space contains stuff that can be used as a type annotation. E.g. the following are a few type declarations: 7 | 8 | ```ts 9 | class Foo {}; 10 | interface Bar {}; 11 | type Bas = {}; 12 | ``` 13 | This means that you can use `Foo`, `Bar`, `Bas`, etc. as a type annotation. E.g.: 14 | 15 | ```ts 16 | var foo: Foo; 17 | var bar: Bar; 18 | var bas: Bas; 19 | ``` 20 | 21 | Notice that even though you have `interface Bar`, *you can't use it as a variable* because it doesn't contribute to the *variable declaration space*. This is shown below: 22 | 23 | ```ts 24 | interface Bar {}; 25 | var bar = Bar; // ERROR: "cannot find name 'Bar'" 26 | ``` 27 | 28 | The reason why it says `cannot find name` is because the name `Bar` *is not defined* in the *variable* declaration space. That brings us to the next topic "Variable Declaration Space". 29 | 30 | ### Variable Declaration Space 31 | The variable declaration space contains stuff that you can use as a variable. We saw that having `class Foo` contributes a type `Foo` to the *type* declaration space. Guess what? It also contributes a *variable* `Foo` to the *variable* declaration space as shown below: 32 | 33 | ```ts 34 | class Foo {}; 35 | var someVar = Foo; 36 | var someOtherVar = 123; 37 | ``` 38 | This is great as sometimes you want to pass classes around as variables. Remember that: 39 | 40 | * we couldn't use something like an `interface` that is *only* in the *type* declaration space as a variable. 41 | 42 | Similarly something that you declare with `var`, is *only* in the *variable* declaration space and cannot be used as a type annotation: 43 | 44 | ```ts 45 | var foo = 123; 46 | var bar: foo; // ERROR: "cannot find name 'foo'" 47 | ``` 48 | The reason why it says `cannot find name` is because the name `foo` *is not defined* in the *type* declaration space. 49 | -------------------------------------------------------------------------------- /docs/project/files.md: -------------------------------------------------------------------------------- 1 | ## Which files? 2 | 3 | Use `include` and `exclude` to specify files / folders / globs. E.g.: 4 | 5 | 6 | ```json 7 | { 8 | "include":[ 9 | "./folder" 10 | ], 11 | "exclude":[ 12 | "./folder/**/*.spec.ts", 13 | "./folder/someSubFolder" 14 | ] 15 | } 16 | ``` 17 | 18 | ### Globs 19 | 20 | * 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`) 21 | 22 | ### `files` option 23 | Alternatively, you can use `files` to be explicit: 24 | 25 | ```json 26 | { 27 | "files":[ 28 | "./some/file.ts" 29 | ] 30 | } 31 | ``` 32 | 33 | But it is not recommended as you have to keep updating it. Instead use `include` to just add the containing folder. 34 | -------------------------------------------------------------------------------- /docs/project/globals.md: -------------------------------------------------------------------------------- 1 | # global.d.ts 2 | 3 | We discussed *global* vs. *file* modules when covering [projects](./modules.md) and recommended using file based modules and not polluting the global namespace. 4 | 5 | Nevertheless, if you have beginner TypeScript developers you can give them a `global.d.ts` file to put interfaces / types in the global namespace to make it easy to have some *types* just *magically* available for consumption in *all* your TypeScript code. 6 | 7 | Another use case for a `global.d.ts` file is to declare compile-time constants that are being injected into the source code by Webpack via the standard [DefinePlugin](https://webpack.js.org/plugins/define-plugin/) plugin. 8 | 9 | ```ts 10 | declare const BUILD_MODE_PRODUCTION: boolean; // can be used for conditional compiling 11 | declare const BUILD_VERSION: string; 12 | ``` 13 | 14 | > For any code that is going to generate *JavaScript* we highly recommend using *file modules*, and only use `global.d.ts` to declare compile-time constants and/or to extend standard type declarations declared in `lib.d.ts`. 15 | 16 | * Bonus: The `global.d.ts` file is also good for quick `declare module "some-library-you-dont-care-to-get-defs-for";` when doing JS to TS migrations. 17 | -------------------------------------------------------------------------------- /docs/project/modules.md: -------------------------------------------------------------------------------- 1 | ## Modules 2 | 3 | ### Global Module 4 | 5 | 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`: 6 | 7 | ```ts 8 | var foo = 123; 9 | ``` 10 | 11 | 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: 12 | 13 | ```ts 14 | var bar = foo; // allowed 15 | ``` 16 | 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. 17 | 18 | ### File Module 19 | 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): 20 | 21 | ```ts 22 | export var foo = 123; 23 | ``` 24 | 25 | We will no longer have `foo` in the global namespace. This can be demonstrated by creating a new file `bar.ts` as follows: 26 | 27 | ```ts 28 | var bar = foo; // ERROR: "cannot find name 'foo'" 29 | ``` 30 | 31 | 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: 32 | 33 | ```ts 34 | import { foo } from "./foo"; 35 | var bar = foo; // allowed 36 | ``` 37 | 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. 38 | 39 | What JavaScript is generated from a given TypeScript file that uses external modules is driven by the compiler flag called `module`. 40 | -------------------------------------------------------------------------------- /docs/project/namespaces.md: -------------------------------------------------------------------------------- 1 | ## Namespaces 2 | Namespaces provide you with a convenient syntax around a common pattern used in JavaScript: 3 | 4 | ```ts 5 | (function(something) { 6 | 7 | something.foo = 123; 8 | 9 | })(something || (something = {})) 10 | ``` 11 | 12 | Basically `something || (something = {})` allows an anonymous function `function(something) {}` to *add stuff to an existing object* (the `something ||` portion) or *start a new object then add stuff to that object* (the `|| (something = {})` portion). This means that you can have two such blocks split by some execution boundary: 13 | 14 | ```ts 15 | (function(something) { 16 | 17 | something.foo = 123; 18 | 19 | })(something || (something = {})) 20 | 21 | console.log(something); // {foo:123} 22 | 23 | (function(something) { 24 | 25 | something.bar = 456; 26 | 27 | })(something || (something = {})) 28 | 29 | console.log(something); // {foo:123, bar:456} 30 | 31 | ``` 32 | 33 | This is commonly used in the JavaScript land for making sure that stuff doesn't leak into the global namespace. With file based modules you don't need to worry about this, but the pattern is still useful for *logical grouping* of a bunch of functions. Therefore TypeScript provides the `namespace` keyword to group these e.g.: 34 | 35 | ```ts 36 | namespace Utility { 37 | export function log(msg) { 38 | console.log(msg); 39 | } 40 | export function error(msg) { 41 | console.error(msg); 42 | } 43 | } 44 | 45 | // usage 46 | Utility.log('Call me'); 47 | Utility.error('maybe!'); 48 | ``` 49 | 50 | The `namespace` keyword generates the same JavaScript that we saw earlier: 51 | 52 | ```ts 53 | (function (Utility) { 54 | 55 | // Add stuff to Utility 56 | 57 | })(Utility || (Utility = {})); 58 | ``` 59 | 60 | One thing to note is that namespaces can be nested so you can do stuff like `namespace Utility.Messaging` to nest a `Messaging` namespace under `Utility`. 61 | 62 | For most projects we recommend using external modules and using `namespace` for quick demos and porting old JavaScript code. 63 | -------------------------------------------------------------------------------- /docs/project/project.md: -------------------------------------------------------------------------------- 1 | # Project 2 | 3 | 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. 4 | -------------------------------------------------------------------------------- /docs/quick/nodejs.md: -------------------------------------------------------------------------------- 1 | # TypeScript with Node.js 2 | TypeScript has had *first class* support for Node.js since inception. Here's how to setup a quick Node.js project: 3 | 4 | > Note: many of these steps are actually just common practice Node.js setup steps 5 | 6 | 1. Setup a Node.js project `package.json`. Quick one : `npm init -y` 7 | 1. Add TypeScript (`npm install typescript --save-dev`) 8 | 1. Add `node.d.ts` (`npm install @types/node --save-dev`) 9 | 1. 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`) 10 | 11 | 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! 12 | 13 | All your TypeScript code goes in `src` and the generated JavaScript goes in `lib`. 14 | 15 | ## Bonus: Live compile + run 16 | * Add `ts-node` which we will use for live compile + run in node (`npm install ts-node --save-dev`) 17 | * Add `nodemon` which will invoke `ts-node` whenever a file is changed (`npm install nodemon --save-dev`) 18 | 19 | Now just add a `script` target to your `package.json` based on your application entry e.g. assuming its `index.ts`: 20 | 21 | ```json 22 | "scripts": { 23 | "start": "npm run build:live", 24 | "build": "tsc -p .", 25 | "build:live": "nodemon --watch 'src/**/*.ts' --exec \"ts-node\" src/index.ts" 26 | }, 27 | ``` 28 | 29 | So you can now run `npm start` and as you edit `index.ts`: 30 | 31 | * nodemon reruns its command (ts-node) 32 | * ts-node transpiles automatically picking up tsconfig.json and the installed TypeScript version, 33 | * ts-node runs the output JavaScript through Node.js. 34 | 35 | And when you are ready to deploy your JavaScript application run `npm run build`. 36 | 37 | 38 | ## Bonus points 39 | 40 | Such NPM modules work just fine with browserify (using tsify) or webpack (using ts-loader). 41 | -------------------------------------------------------------------------------- /docs/rest-parameters.md: -------------------------------------------------------------------------------- 1 | ### Rest Parameters 2 | 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. 3 | 4 | ```ts 5 | function iTakeItAll(first, second, ...allOthers) { 6 | console.log(allOthers); 7 | } 8 | iTakeItAll('foo', 'bar'); // [] 9 | iTakeItAll('foo', 'bar', 'bas', 'qux'); // ['bas','qux'] 10 | ``` 11 | 12 | Rest parameters can be used in any function be it `function`/`()=>`/`class member`. 13 | -------------------------------------------------------------------------------- /docs/staging/async-await.md: -------------------------------------------------------------------------------- 1 | ### Async - Await 2 | -------------------------------------------------------------------------------- /docs/staging/generators.md: -------------------------------------------------------------------------------- 1 | ### Generators 2 | Also called `function *`, generators allow you to create functions whose execution can be paused and then later resumed maintaining the state between pause-resume transitions. The value returned from a generator is called an `iterator` and can be used to control this `pause-resume` transition. 3 | 4 | Here is a simple example of a generator function that generates an *infinite* list of whole numbers. 5 | 6 | ```ts 7 | function* wholeNumbers() { 8 | var current = 0; 9 | while(true) { 10 | yield current++; 11 | } 12 | } 13 | ``` 14 | 15 | The `yield` contextual keyword is used to return control from a generator (effectively pausing function execution) along with an optional value (here `current`). You can get access to this value using the `iterator`'s `.next()` member function, this is shown below: 16 | 17 | ```ts 18 | function* wholeNumbers() { 19 | var current = 0; 20 | while(true) { 21 | yield current++; 22 | } 23 | } 24 | var iterator = wholeNumbers(); 25 | console.log(iterator.next()); // 0 26 | console.log(iterator.next()); // 1 27 | console.log(iterator.next()); // 2 28 | // so on till infinity.... 29 | ``` 30 | 31 | Now that you have seen `function*`, `yield` and `.next()` we can dig deeper. 32 | 33 | #### Catching Errors 34 | Any errors thrown (intentionally using `throw` or unintentionally due to error) from the generator can be caught using `try/catch` just like normal function executions. This is demonstrated below: 35 | 36 | ```ts 37 | function* wholeNumbers() { 38 | var current = 0; 39 | while(true) { 40 | if (current === 3) 41 | throw new Error('3 is the magic number'); 42 | else 43 | yield current++; 44 | } 45 | } 46 | var iterator = wholeNumbers(); 47 | console.log(iterator.next()); // 0 48 | console.log(iterator.next()); // 1 49 | console.log(iterator.next()); // 2 50 | try { 51 | console.log(iterator.next()); // Will throw an error 52 | } 53 | catch(ex) { 54 | console.log(ex.message); // 3 is the magic number 55 | } 56 | ``` 57 | 58 | #### Controlling function execution externally 59 | The iterator returned from the generator function can be used to control the state *inside* the generator function as well. 60 | 61 | // TODO: example 62 | -------------------------------------------------------------------------------- /docs/state/mobx.md: -------------------------------------------------------------------------------- 1 | ## MobX 2 | 3 | > [PRO Egghead course on MobX TypeScript React](https://egghead.io/courses/develop-react-applications-with-mobx-and-typescript) 4 | 5 | -------------------------------------------------------------------------------- /docs/styleguide/sample.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var formatting; 3 | (function (formatting) { 4 | var FooVar; 5 | function BarFunc() { } 6 | })(formatting || (formatting = {})); 7 | var asdfasdf; 8 | (function (asdfasdf) { 9 | var Foo = (function () { 10 | function Foo() { 11 | } 12 | Foo.prototype.baz = function () { }; 13 | return Foo; 14 | }()); 15 | })(asdfasdf || (asdfasdf = {})); 16 | -------------------------------------------------------------------------------- /docs/styleguide/sample.ts: -------------------------------------------------------------------------------- 1 | export var test; 2 | 3 | namespace formatting { 4 | var FooVar; 5 | function BarFunc() { } 6 | } 7 | 8 | namespace asdfasdf { 9 | class Foo { 10 | bar: number; 11 | baz() { } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /docs/styleguide/tsconfig.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /docs/testing/intro.md: -------------------------------------------------------------------------------- 1 | # Testing 2 | 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. 3 | 4 | That said, in this section look at options that we have enjoyed greatly 🌹 5 | -------------------------------------------------------------------------------- /docs/tips/barrel.md: -------------------------------------------------------------------------------- 1 | ## Barrel 2 | 3 | A barrel is a way to rollup exports from several modules into a single convenient module. The barrel itself is a module file that re-exports selected exports of other modules. 4 | 5 | Imagine the following class structure in a library: 6 | 7 | ```ts 8 | // demo/foo.ts 9 | export class Foo {} 10 | 11 | // demo/bar.ts 12 | export class Bar {} 13 | 14 | // demo/baz.ts 15 | export class Baz {} 16 | ``` 17 | 18 | Without a barrel, a consumer would need three import statements: 19 | 20 | ```ts 21 | import { Foo } from '../demo/foo'; 22 | import { Bar } from '../demo/bar'; 23 | import { Baz } from '../demo/baz'; 24 | ``` 25 | 26 | You can instead add a barrel `demo/index.ts` containing the following: 27 | 28 | ```ts 29 | // demo/index.ts 30 | export * from './foo'; // re-export all of its exports 31 | export * from './bar'; // re-export all of its exports 32 | export * from './baz'; // re-export all of its exports 33 | ``` 34 | 35 | Now the consumer can import what it needs from the barrel: 36 | 37 | ```ts 38 | import { Foo, Bar, Baz } from '../demo'; // demo/index.ts is implied 39 | ``` 40 | 41 | ### Named exports 42 | Instead of exporting `*`, you can choose to export the module in a name. E.g., assume that `baz.ts` has functions: 43 | 44 | ```ts 45 | // demo/foo.ts 46 | export class Foo {} 47 | 48 | // demo/bar.ts 49 | export class Bar {} 50 | 51 | // demo/baz.ts 52 | export function getBaz() {} 53 | export function setBaz() {} 54 | ``` 55 | 56 | If you would rather not export `getBaz` / `setBaz` from demo you can instead put them in a variable by importing them in a name and exporting that name as shown below: 57 | 58 | ```ts 59 | // demo/index.ts 60 | export * from './foo'; // re-export all of its exports 61 | export * from './bar'; // re-export all of its exports 62 | 63 | import * as baz from './baz'; // import as a name 64 | export { baz }; // export the name 65 | ``` 66 | 67 | And now the consumer would look like: 68 | 69 | ```ts 70 | import { Foo, Bar, baz } from '../demo'; // demo/index.ts is implied 71 | 72 | // usage 73 | baz.getBaz(); 74 | baz.setBaz(); 75 | // etc. ... 76 | ``` 77 | -------------------------------------------------------------------------------- /docs/tips/build-toggles.md: -------------------------------------------------------------------------------- 1 | ## Build Toggles 2 | 3 | It is common to switch in JavaScript projects based on where they are being run. You can do this quite easily with webpack as it supports *dead code elimination* based on environment variables. 4 | 5 | Add different targets in your `package.json` `scripts`: 6 | 7 | ```json 8 | "build:test": "webpack -p --config ./src/webpack.config.js", 9 | "build:prod": "webpack -p --define process.env.NODE_ENV='\"production\"' --config ./src/webpack.config.js", 10 | ``` 11 | 12 | Of course I am assuming you have `npm install webpack --save-dev`. Now you can run `npm run build:test` etc. 13 | 14 | Using this variable is super easy as well: 15 | 16 | ```ts 17 | /** 18 | * This interface makes sure we don't miss adding a property to both `prod` and `test` 19 | */ 20 | interface Config { 21 | someItem: string; 22 | } 23 | 24 | /** 25 | * We only export a single thing. The config. 26 | */ 27 | export let config: Config; 28 | 29 | /** 30 | * `process.env.NODE_ENV` definition is driven from webpack 31 | * 32 | * The whole `else` block will be removed in the emitted JavaScript 33 | * for a production build 34 | */ 35 | if (process.env.NODE_ENV === 'production') { 36 | config = { 37 | someItem: 'prod' 38 | } 39 | console.log('Running in prod'); 40 | } else { 41 | config = { 42 | someItem: 'test' 43 | } 44 | console.log('Running in test'); 45 | } 46 | ``` 47 | 48 | > We use `process.env.NODE_ENV` just because it is conventional in a lot of JavaScript libraries themselves e.g. `React`. 49 | -------------------------------------------------------------------------------- /docs/tips/classesAreUseful.md: -------------------------------------------------------------------------------- 1 | ## Classes Are Useful 2 | 3 | It is very common to have the following structure: 4 | 5 | ```ts 6 | function foo() { 7 | let someProperty; 8 | 9 | // Some other initialization code 10 | 11 | function someMethod() { 12 | // Do some stuff with `someProperty` 13 | // And potentially other things 14 | } 15 | // Maybe some other methods 16 | 17 | return { 18 | someMethod, 19 | // Maybe some other methods 20 | }; 21 | } 22 | ``` 23 | 24 | This is known as the *revealing module pattern* and quite common in JavaScript (taking advantage of JavaScript closure). 25 | 26 | If you use [*file modules* (which you really should as global scope is bad)](../project/modules.md) then *your file is effectively the same*. However, there are too many cases where people will write code like the following: 27 | 28 | ```ts 29 | let someProperty; 30 | 31 | function foo() { 32 | // Some initialization code 33 | } 34 | foo(); // some initialization code 35 | 36 | someProperty = 123; // some more initialization 37 | 38 | // Some utility function not exported 39 | 40 | // later 41 | export function someMethod() { 42 | 43 | } 44 | ``` 45 | 46 | Even though I am not a big fan of inheritance *I do find that letting people use classes helps them organize their code better*. The same developer would intuitively write the following: 47 | 48 | ```ts 49 | class Foo { 50 | public someProperty; 51 | 52 | constructor() { 53 | // some initialization 54 | } 55 | 56 | public someMethod() { 57 | // some code 58 | } 59 | 60 | private someUtility() { 61 | // some code 62 | } 63 | } 64 | 65 | export = new Foo(); 66 | ``` 67 | 68 | And its not just developers, creating dev tools that provide great visualizations over classes are much more common, and there is one less pattern your team needs to understand and maintain. 69 | 70 | > PS: There is nothing wrong in my opinion with *shallow* class hierarchies if they provide significant reuse and reduction in boiler plate. 71 | -------------------------------------------------------------------------------- /docs/tips/create-arrays.md: -------------------------------------------------------------------------------- 1 | ## Creating arrays 2 | 3 | Creating an empty array is super easy: 4 | 5 | ```ts 6 | const foo: string[] = []; 7 | ``` 8 | 9 | If you want an array to loop over: 10 | 11 | ```ts 12 | [...new Array(6)]; 13 | ``` 14 | 15 | If you want to create an array pre-filled with some content use the ES6 `Array.prototype.fill`: 16 | 17 | ```ts 18 | const foo: string[] = new Array(3).fill(''); 19 | console.log(foo); // ['','','']; 20 | ``` 21 | 22 | If you want to create an array of a predefined length with calls you can use the spread operator: 23 | 24 | ```ts 25 | const someNumbers = [...new Array(3)].map((_,i) => i * 10); 26 | console.log(someNumbers); // [0,10,20]; 27 | ``` 28 | -------------------------------------------------------------------------------- /docs/tips/currying.md: -------------------------------------------------------------------------------- 1 | ## Currying 2 | 3 | Just use a chain of fat arrow functions: 4 | 5 | ```ts 6 | // A curried function 7 | let add = (x: number) => (y: number) => x + y; 8 | 9 | // Simple usage 10 | add(123)(456); 11 | 12 | // partially applied 13 | let add123 = add(123); 14 | 15 | // fully apply the function 16 | add123(456); 17 | ``` 18 | -------------------------------------------------------------------------------- /docs/tips/functionParameters.md: -------------------------------------------------------------------------------- 1 | # Function Parameters 2 | 3 | If you have a function that takes too many parameters, or parameters of the same type, then you might want to consider changing the function to take an object instead. 4 | 5 | Consider the following function: 6 | 7 | ```ts 8 | function foo(flagA: boolean, flagB: boolean) { 9 | // your awesome function body 10 | } 11 | ``` 12 | 13 | With such a function definition it's quite easy to invoke it incorrectly e.g. `foo(flagB, flagA)` and you would get no help from the compiler. 14 | 15 | Instead, convert the function to take an object: 16 | 17 | ```ts 18 | function foo(config: {flagA: boolean, flagB: boolean}) { 19 | const {flagA, flagB} = config; 20 | // your awesome function body 21 | } 22 | ``` 23 | Now the function calls will look like `foo({flagA, flagB})` which makes it much easier to spot mistakes and code review. 24 | 25 | > Note : If your function is simple enough, and you don't expect much churn, then feel free to ignore this advice 🌹. 26 | -------------------------------------------------------------------------------- /docs/tips/jquery.md: -------------------------------------------------------------------------------- 1 | ## JQuery Tips 2 | 3 | Note: you need to install the `jquery.d.ts` file for these tips 4 | 5 | ### Quickly define a new plugin 6 | 7 | Just create `jquery-foo.d.ts` with: 8 | 9 | ```ts 10 | interface JQuery { 11 | foo: any; 12 | } 13 | ``` 14 | 15 | And now you can use `$('something').foo({whateverYouWant:'hello jquery plugin'})` 16 | -------------------------------------------------------------------------------- /docs/tips/lazyObjectLiteralInitialization.md: -------------------------------------------------------------------------------- 1 | ## Lazy Object Literal Initialization 2 | 3 | Quite commonly in JavaScript code bases you would initialize object literals in the following manner: 4 | 5 | ```ts 6 | let foo = {}; 7 | foo.bar = 123; 8 | foo.bas = "Hello World"; 9 | ``` 10 | 11 | As soon as you move the code to TypeScript you will start to get Errors like the following: 12 | 13 | ```ts 14 | let foo = {}; 15 | foo.bar = 123; // Error: Property 'bar' does not exist on type '{}' 16 | foo.bas = "Hello World"; // Error: Property 'bas' does not exist on type '{}' 17 | ``` 18 | 19 | This is because from the state `let foo = {}`, TypeScript *infers* the type of `foo` (left hand side of initializing assignment) to be the type of the right hand side `{}` (i.e. an object with no properties). So, it error if you try to assign to a property it doesn't know about. 20 | 21 | ### Ideal Fix 22 | 23 | The *proper* way to initialize an object in TypeScript is to do it in the assignment: 24 | 25 | ```ts 26 | let foo = { 27 | bar: 123, 28 | bas: "Hello World", 29 | }; 30 | ``` 31 | 32 | This is also great for code review and code maintainability purposes. 33 | 34 | > The quick fix and middle ground *lazy* initialization patterns described below suffer from *mistakenly forgetting to initialize a property*. 35 | 36 | ### Quick Fix 37 | 38 | If you have a large JavaScript code base that you are migrating to TypeScript the ideal fix might not be a viable solution for you. In that case you can carefully use a *type assertion* to silence the compiler: 39 | 40 | ```ts 41 | let foo = {} as any; 42 | foo.bar = 123; 43 | foo.bas = "Hello World"; 44 | ``` 45 | 46 | ### Middle Ground 47 | 48 | Of course using the `any` assertion can be very bad as it sort of defeats the safety of TypeScript. The middle ground fix is to create an `interface` to ensure 49 | 50 | * Good Docs 51 | * Safe assignment 52 | 53 | This is shown below: 54 | 55 | ```ts 56 | interface Foo { 57 | bar: number 58 | bas: string 59 | } 60 | 61 | let foo = {} as Foo; 62 | foo.bar = 123; 63 | foo.bas = "Hello World"; 64 | ``` 65 | 66 | Here is a quick example that shows the fact that using the interface can save you: 67 | 68 | ```ts 69 | interface Foo { 70 | bar: number 71 | bas: string 72 | } 73 | 74 | let foo = {} as Foo; 75 | foo.bar = 123; 76 | foo.bas = "Hello World"; 77 | 78 | // later in the codebase: 79 | foo.bar = 'Hello Stranger'; // Error: You probably misspelled `bas` as `bar`, cannot assign string to number 80 | ``` 81 | -------------------------------------------------------------------------------- /docs/tips/main.md: -------------------------------------------------------------------------------- 1 | # TIPs 2 | In this section we present a number of tips that we have collected over the course of using TypeScript in the real world. 3 | -------------------------------------------------------------------------------- /docs/tips/propertySetters.md: -------------------------------------------------------------------------------- 1 | ## Limit usage of property setters 2 | 3 | Prefer explicit set/get functions (e.g. `setBar` and `getBar` functions) over setters/getters. 4 | 5 | Consider the following code: 6 | 7 | ```ts 8 | foo.bar = { 9 | a: 123, 10 | b: 456 11 | }; 12 | ``` 13 | 14 | In the presence of setter/getters: 15 | 16 | ```ts 17 | class Foo { 18 | a: number; 19 | b: number; 20 | set bar(value:{a:number,b:number}) { 21 | this.a = value.a; 22 | this.b = value.b; 23 | } 24 | } 25 | let foo = new Foo(); 26 | ``` 27 | 28 | This is not a *good* use of property setters. The person reading the first code sample has no context about all the things that will change. Whereas someone calling `foo.setBar(value)` might have an idea that something might change on `foo`. 29 | 30 | > Bonus points: Find references works better if you have different functions. In TypeScript tools if you find references for a getter or a setter you get *both* whereas with explicit function calls you only get references to the relevant function. 31 | -------------------------------------------------------------------------------- /docs/tips/singleton.md: -------------------------------------------------------------------------------- 1 | # Singleton Pattern 2 | 3 | The conventional singleton pattern is really something that is used to overcome the fact that all code must be in a `class`. 4 | 5 | ```ts 6 | class Singleton { 7 | private static instance: Singleton; 8 | private constructor() { 9 | // do something construct... 10 | } 11 | static getInstance() { 12 | if (!Singleton.instance) { 13 | Singleton.instance = new Singleton(); 14 | // ... any one time initialization goes here ... 15 | } 16 | return Singleton.instance; 17 | } 18 | someMethod() { } 19 | } 20 | 21 | let something = new Singleton() // Error: constructor of 'Singleton' is private. 22 | 23 | let instance = Singleton.getInstance() // do something with the instance... 24 | ``` 25 | 26 | However, if you don't want lazy initialization you can instead just use a `namespace`: 27 | 28 | ```ts 29 | namespace Singleton { 30 | // ... any one time initialization goes here ... 31 | export function someMethod() { } 32 | } 33 | // Usage 34 | Singleton.someMethod(); 35 | ``` 36 | 37 | > Warning : Singleton is just a fancy name for [global](http://stackoverflow.com/a/142450/390330) 38 | 39 | For most projects `namespace` can additionally be replaced by a *module*. 40 | 41 | ```ts 42 | // someFile.ts 43 | // ... any one time initialization goes here ... 44 | export function someMethod() { } 45 | 46 | // Usage 47 | import {someMethod} from "./someFile"; 48 | ``` 49 | 50 | 51 | -------------------------------------------------------------------------------- /docs/tips/statefulFunctions.md: -------------------------------------------------------------------------------- 1 | ## Stateful Functions 2 | A common feature in other programming languages is usage of the `static` keyword to increase the *lifetime* (not *scope*) of a function variable to live beyond function invocations. Here is a `C` sample that achieves this: 3 | 4 | ```c 5 | void called() { 6 | static count = 0; 7 | count++; 8 | printf("Called : %d", count); 9 | } 10 | 11 | int main () { 12 | called(); // Called : 1 13 | called(); // Called : 2 14 | return 0; 15 | } 16 | ``` 17 | 18 | Since JavaScript (or TypeScript) doesn't have function statics you can achieve the same thing using various abstractions that wrap over a local variable e.g. using a `class` : 19 | 20 | ```ts 21 | const {called} = new class { 22 | count = 0; 23 | called = () => { 24 | this.count++; 25 | console.log(`Called : ${this.count}`); 26 | } 27 | }; 28 | 29 | called(); // Called : 1 30 | called(); // Called : 2 31 | ``` 32 | 33 | > C++ developers also try and achieve this using a pattern they call `functor` (a class that overrides the operator `()`). 34 | -------------------------------------------------------------------------------- /docs/tips/staticConstructor.md: -------------------------------------------------------------------------------- 1 | # Static Constructors in TypeScript 2 | 3 | TypeScript `class` (like JavaScript `class`) cannot have a static constructor. However, you can get the same effect quite easily by just calling it yourself: 4 | 5 | ```ts 6 | class MyClass { 7 | static initialize() { 8 | // Initialization 9 | } 10 | } 11 | MyClass.initialize(); 12 | ``` 13 | -------------------------------------------------------------------------------- /docs/tips/stringEnums.md: -------------------------------------------------------------------------------- 1 | ## String enums 2 | 3 | Sometimes you need a collection of strings collected under a common key. Prior to TypeScript 2.4, TypeScript only supported number-based enums. If using versions prior to 2.4, a work-around is to use [string literal types to create string based enums by combining with union types](../types/literal-types.md). 4 | -------------------------------------------------------------------------------- /docs/tips/typeInstantiation.md: -------------------------------------------------------------------------------- 1 | ## Type Instantiation for Generics 2 | 3 | Say you have something that has a generic parameter e.g. a class `Foo`: 4 | 5 | ```ts 6 | class Foo{ 7 | foo: T; 8 | } 9 | ``` 10 | 11 | You want to create a specialized version for it for a particular type. The pattern is to copy the item into a new variable and give it the type annotation with the generics replaced with concrete types. E.g. if you want a class `Foo`: 12 | 13 | ```ts 14 | class Foo{ 15 | foo: T; 16 | } 17 | let FooNumber = Foo as { new ():Foo }; // ref 1 18 | ``` 19 | In `ref 1` you are saying that `FooNumber` is the same as `Foo` but just treat it as something that when called with the `new` operator gives an instance of `Foo`. 20 | 21 | ### Inheritance 22 | The Type assertion pattern is unsafe in that it trusts you to do the right thing. A common pattern in other languages *for classes* is to just use inheritance : 23 | 24 | ```ts 25 | class FooNumber extends Foo{} 26 | ``` 27 | 28 | One word of caution here: if you use decorators on the base class then the inherited class might not have the same behavior as the base class (it is no longer wrapped by the decorator). 29 | 30 | Of course if you are not specializing classes you still have to come up with a coercion / assertion pattern that works and hence we showed the general assertion pattern first, e.g.: 31 | 32 | ```ts 33 | function id(x: T) { return x; } 34 | const idNum = id as {(x:number):number}; 35 | ``` 36 | 37 | > Inspired by this [stackoverflow question](http://stackoverflow.com/a/34864705/390330) 38 | -------------------------------------------------------------------------------- /docs/tips/typed-event.md: -------------------------------------------------------------------------------- 1 | ## Typesafe Event Emitter 2 | 3 | Conventionally in Node.js and traditional JavaScript you have a single event emitter. This event emitter internally tracks listener for different event types e.g. 4 | 5 | ```ts 6 | const emitter = new EventEmitter(); 7 | // Emit: 8 | emitter.emit('foo', foo); 9 | emitter.emit('bar', bar); 10 | // Listen: 11 | emitter.on('foo', (foo)=>console.log(foo)); 12 | emitter.on('bar', (bar)=>console.log(bar)); 13 | ``` 14 | Essentially `EventEmitter` internally stores data in the form of mapped arrays: 15 | ```ts 16 | {foo: [fooListeners], bar: [barListeners]} 17 | ``` 18 | Instead, for the sake of *event* type safety, you can create an emitter *per* event type: 19 | ```ts 20 | const onFoo = new TypedEvent(); 21 | const onBar = new TypedEvent(); 22 | 23 | // Emit: 24 | onFoo.emit(foo); 25 | onBar.emit(bar); 26 | // Listen: 27 | onFoo.on((foo)=>console.log(foo)); 28 | onBar.on((bar)=>console.log(bar)); 29 | ``` 30 | 31 | This has the following advantages: 32 | * The types of events are easily discoverable as variables. 33 | * The event emitter variables are easily refactored independently. 34 | * Type safety for event data structures. 35 | 36 | ### Reference TypedEvent 37 | ```ts 38 | export interface Listener { 39 | (event: T): any; 40 | } 41 | 42 | export interface Disposable { 43 | dispose(); 44 | } 45 | 46 | /** passes through events as they happen. You will not get events from before you start listening */ 47 | export class TypedEvent { 48 | private listeners: Listener[] = []; 49 | private listenersOncer: Listener[] = []; 50 | 51 | on = (listener: Listener): Disposable => { 52 | this.listeners.push(listener); 53 | return { 54 | dispose: () => this.off(listener) 55 | }; 56 | } 57 | 58 | once = (listener: Listener): void => { 59 | this.listenersOncer.push(listener); 60 | } 61 | 62 | off = (listener: Listener) => { 63 | var callbackIndex = this.listeners.indexOf(listener); 64 | if (callbackIndex > -1) this.listeners.splice(callbackIndex, 1); 65 | } 66 | 67 | emit = (event: T) => { 68 | /** Update any general listeners */ 69 | this.listeners.forEach((listener) => listener(event)); 70 | 71 | /** Clear the `once` queue */ 72 | if (this.listenersOncer.length > 0) { 73 | const toCall = this.listenersOncer; 74 | this.listenersOncer = []; 75 | toCall.forEach((listener) => listener(event)); 76 | } 77 | } 78 | 79 | pipe = (te: TypedEvent): Disposable => { 80 | return this.on((e) => te.emit(e)); 81 | } 82 | } 83 | ``` 84 | -------------------------------------------------------------------------------- /docs/tools/changelog.md: -------------------------------------------------------------------------------- 1 | ## Changelog 2 | > Reading a markdown file with the progress in the project is easier than reading a commit log. 3 | 4 | Automatic changelog generation from commit messages is a fairly common pattern nowadays. There is a project called [conventional-changelog](https://github.com/conventional-changelog/conventional-changelog) that generates a changelog from commit messages that follow a *convention*. 5 | 6 | ### Commit message convention 7 | The most common convention is the *angular* commit messages convention which is [detailed here](https://github.com/angular/angular.js/blob/master/DEVELOPERS.md#-git-commit-guidelines). 8 | 9 | ### Setup 10 | * Install: 11 | 12 | ```bash 13 | npm install standard-version -D 14 | ``` 15 | 16 | * Add a `script` target to your `package.json`: 17 | 18 | ```js 19 | { 20 | "scripts": { 21 | "release": "standard-version" 22 | } 23 | } 24 | ``` 25 | 26 | * Optionally : To automatically push the new *git commit and tag* plus publish to npm add a `postrelease` script: 27 | 28 | ```js 29 | { 30 | "scripts": { 31 | "release": "standard-version", 32 | "postrelease": "git push --follow-tags origin master && npm publish" 33 | } 34 | } 35 | ``` 36 | 37 | ### Releasing 38 | 39 | Simply run: 40 | 41 | ```bash 42 | npm run release 43 | ``` 44 | 45 | Based on the commit messages `major` | `minor` | `patch` is automatically determined. To *explicitly* specify a version you can specify `--release-as` e.g.: 46 | 47 | ```bash 48 | npm run release -- --release-as minor 49 | ``` 50 | -------------------------------------------------------------------------------- /docs/tools/eslint.md: -------------------------------------------------------------------------------- 1 | # ESLint 2 | 3 | ESLint existed to lint JavaScript, but now it is also becoming the defacto linter for [TypeScript](https://github.com/Microsoft/TypeScript/issues/29288), thanks to the [collaboration](https://eslint.org/blog/2019/01/future-typescript-eslint) between the two teams. 4 | 5 | ## Install 6 | 7 | To setup ESLint for TypeScript you need the following packages: 8 | 9 | ```sh 10 | npm i eslint eslint-plugin-react @typescript-eslint/parser @typescript-eslint/eslint-plugin 11 | ``` 12 | 13 | > TIP: eslint calls packages that contain lint rules as "plugin" 14 | 15 | * eslint : Core eslint 16 | * eslint-plugin-react : For react rules provided by eslint. [Supported rules list](https://github.com/yannickcr/eslint-plugin-react#list-of-supported-rules) 17 | * @typescript-eslint/parse : To allow eslint to understand ts / tsx files 18 | * @typescript-eslint/eslint-plugin : For TypeScript rules. [Supported rules list](https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/eslint-plugin#supported-rules) 19 | 20 | > As you can see there are two eslint packages (for use with js or ts) and two @typescript-eslint packages (for use with ts). So the overhead for TypeScript is not *that much*. 21 | 22 | ## Configure 23 | Create `.eslintrc.js`: 24 | 25 | ```js 26 | module.exports = { 27 | parser: '@typescript-eslint/parser', 28 | parserOptions: { 29 | project: './tsconfig.json', 30 | }, 31 | plugins: ['@typescript-eslint'], 32 | extends: [ 33 | 'plugin:react/recommended', 34 | 'plugin:@typescript-eslint/recommended', 35 | ], 36 | rules: { 37 | // Overwrite rules specified from the extended configs e.g. 38 | // "@typescript-eslint/explicit-function-return-type": "off", 39 | } 40 | } 41 | ``` 42 | 43 | ## Run 44 | 45 | In your `package.json` add to `scripts`: 46 | 47 | ```json 48 | { 49 | "scripts": { 50 | "lint": "eslint \"src/**\"" 51 | } 52 | } 53 | ``` 54 | 55 | Now you can `npm run lint` to validate. 56 | 57 | ## Configure VSCode 58 | 59 | * Install extension https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint 60 | * Add to `settings.json`: 61 | ```js 62 | "eslint.validate": [ 63 | "javascript", 64 | "javascriptreact", 65 | {"language": "typescript", "autoFix": true }, 66 | {"language": "typescriptreact", "autoFix": true } 67 | ], 68 | ``` 69 | -------------------------------------------------------------------------------- /docs/tools/husky.md: -------------------------------------------------------------------------------- 1 | # Husky 2 | 3 | > Husky can prevent bad commits, pushes and more 🐶! 4 | 5 | If you want to run some JavaScript / TypeScript code before a commit takes place, husky is the tool for that. 6 | 7 | For example, you can use husky to make sure files are formatted by prettier automatically so you don't have to worry about manually formatting files ever again and focus on the objective of the code instead. Here is the setup: 8 | 9 | * `npm install husky -D` 10 | * Add `scripts` to `package.json`: 11 | 12 | ``` 13 | "precommit": "npm run prettier:write", 14 | ``` 15 | 16 | Now whenever you commit code and there are any formatting changes that need to be made, you'd get them as a *modified* file in your git log. You can now 17 | 18 | * If you have pushed your code already, simply commit them with a comment `pretty`. 19 | * If you haven't pushed your code, amend your last commit and look like a superhero. 20 | -------------------------------------------------------------------------------- /docs/tools/intro.md: -------------------------------------------------------------------------------- 1 | # Tools 2 | Here are some great tools that I recommend you use or at least try in your TypeScript projects. 3 | -------------------------------------------------------------------------------- /docs/tools/prettier.md: -------------------------------------------------------------------------------- 1 | # Prettier 2 | 3 | Prettier is a great tool by facebook that makes code formatting so much easier that it's worth mentioning. Setting up with TypeScript using our recommended project setup (aka everything in `src` folder) is super easy: 4 | 5 | ## Setup 6 | 7 | * `npm install prettier -D` 8 | * Add `scripts` to `package.json`: 9 | 10 | ``` 11 | "prettier:base": "prettier --parser typescript --single-quote", 12 | "prettier:check": "npm run prettier:base -- --list-different \"src/**/*.{ts,tsx}\"", 13 | "prettier:write": "npm run prettier:base -- --write \"src/**/*.{ts,tsx}\"" 14 | ``` 15 | 16 | ## Usage 17 | On your build server: 18 | * `npm run prettier:check` 19 | 20 | During dev (or pre commit hook): 21 | * `npm run prettier:write` 22 | -------------------------------------------------------------------------------- /docs/types/@types.md: -------------------------------------------------------------------------------- 1 | # `@types` 2 | 3 | [Definitely Typed](https://github.com/DefinitelyTyped/DefinitelyTyped) is definitely one of TypeScript's greatest strengths. The community has effectively gone ahead and **documented** the nature of nearly 90% of the top JavaScript projects out there. 4 | 5 | This means that you can use these projects in a very interactive and exploratory manner, no need to have the docs open in a separate window and making sure you don't make a typo. 6 | 7 | ## Using `@types` 8 | 9 | Installation is fairly simple as it just works on top of `npm`. So as an example you can install type definitions for `jquery` simply as: 10 | 11 | ``` 12 | npm install @types/jquery --save-dev 13 | ``` 14 | 15 | `@types` supports both *global* and *module* type definitions. 16 | 17 | 18 | ### Global `@types` 19 | 20 | By default any definitions that support global consumption are included automatically. E.g. for `jquery` you should be able to just start using `$` *globally* in your project. 21 | 22 | However, for *libraries* (like `jquery`) I generally recommend using *modules*: 23 | 24 | ### Module `@types` 25 | 26 | After installation, no special configuration is required really. You just use it like a module e.g.: 27 | 28 | ```ts 29 | import * as $ from "jquery"; 30 | 31 | // Use $ at will in this module :) 32 | ``` 33 | 34 | ## Controlling Globals 35 | 36 | As can be seen, having a definition that allows global leak-in automatically can be a problem for some teams. So you can choose to *explicitly* only bring in the types that make sense using the `tsconfig.json` `compilerOptions.types` e.g.: 37 | 38 | ```json 39 | { 40 | "compilerOptions": { 41 | "types" : [ 42 | "jquery" 43 | ] 44 | } 45 | } 46 | ``` 47 | 48 | The above shows a sample where only `jquery` will be allowed to be used. Even if the person installs another definition like `npm install @types/node` its globals (e.g. [`process`](https://nodejs.org/api/process.html)) will not leak into your code until you add them to the `tsconfig.json` types option. 49 | -------------------------------------------------------------------------------- /docs/types/ambient/d.ts.md: -------------------------------------------------------------------------------- 1 | ### Declaration file 2 | You can tell TypeScript that you are trying to describe code that exists elsewhere (e.g. written in JavaScript/CoffeeScript/The runtime environment like the browser or Node.js) using the `declare` keyword. As a quick example: 3 | 4 | ```ts 5 | foo = 123; // Error: `foo` is not defined 6 | ``` 7 | vs. 8 | ```ts 9 | declare var foo: any; 10 | foo = 123; // allowed 11 | ``` 12 | 13 | You have the option of putting these declarations in a `.ts` file or in a `.d.ts` file. We highly recommend that in your real world projects you use a separate `.d.ts` (start with one called something like `global.d.ts` or `vendor.d.ts`). 14 | 15 | If a file has the extension `.d.ts` then each root level definition must have the `declare` keyword prefixed to it. This helps make it clear to the author that there will be *no code emitted by TypeScript*. The author needs to ensure that the declared item will exist at runtime. 16 | 17 | > * Ambient declarations is a promise that you are making with the compiler. If these do not exist at runtime and you try to use them, things will break without warning. 18 | * Ambient declarations are like docs. If the source changes the docs need to be kept updated. So you might have new behaviours that work at runtime but no one's updated the ambient declaration and hence you get compiler errors. 19 | -------------------------------------------------------------------------------- /docs/types/ambient/intro.md: -------------------------------------------------------------------------------- 1 | ## Ambient Declarations 2 | 3 | As we mentioned in [why TypeScript](../../why-typescript.md): 4 | 5 | > 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*. 6 | 7 | Ambient declarations allow you to *safely use existing popular JavaScript libraries* and *incrementally migrate your JavaScript/CoffeeScript/Other-Compile-To-Js-Language project to TypeScript*. 8 | 9 | Studying patterns in ambient declarations for *third party JavaScript code* is good practice for annotating *your* TypeScript code base as well. This is why we present it so early on. 10 | -------------------------------------------------------------------------------- /docs/types/ambient/variables.md: -------------------------------------------------------------------------------- 1 | ### Variables 2 | For example to tell TypeScript about the [`process` variable](https://nodejs.org/api/process.html) you *can* do: 3 | 4 | ```ts 5 | declare var process: any; 6 | ``` 7 | 8 | > You don't *need* to do this for `process` as there is already a [community maintained `node.d.ts`](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/node/index.d.ts). 9 | 10 | This allows you to use the `process` variable without TypeScript complaining: 11 | 12 | ```ts 13 | process.exit(); 14 | ``` 15 | 16 | We recommend using an interface wherever possible e.g.: 17 | 18 | ```ts 19 | interface Process { 20 | exit(code?: number): void; 21 | } 22 | declare var process: Process; 23 | ``` 24 | 25 | This allows other people to *extend* the nature of these global variables while still telling TypeScript about such modifications. E.g. consider the following case where we add an `exitWithLogging` function to process for our amusement: 26 | 27 | ```ts 28 | interface Process { 29 | exitWithLogging(code?: number): void; 30 | } 31 | process.exitWithLogging = function() { 32 | console.log("exiting"); 33 | process.exit.apply(process, arguments); 34 | }; 35 | ``` 36 | 37 | Let's look at interfaces in a bit more detail next. 38 | -------------------------------------------------------------------------------- /footer.md: -------------------------------------------------------------------------------- 1 | [![fork me](/images/github.png) Fork me on github](https://github.com/basarat/typescript-book/) 2 | -------------------------------------------------------------------------------- /header.html: -------------------------------------------------------------------------------- 1 | 19 | -------------------------------------------------------------------------------- /images/atomts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/basarat/typescript-book/e31fe92c3afeea1bbcac4381d290e75e5b3ab6e3/images/atomts.png -------------------------------------------------------------------------------- /images/designtsx-banner-large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/basarat/typescript-book/e31fe92c3afeea1bbcac4381d290e75e5b3ab6e3/images/designtsx-banner-large.png -------------------------------------------------------------------------------- /images/designtsx-banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/basarat/typescript-book/e31fe92c3afeea1bbcac4381d290e75e5b3ab6e3/images/designtsx-banner.png -------------------------------------------------------------------------------- /images/errors/interpreting-errors/ide.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/basarat/typescript-book/e31fe92c3afeea1bbcac4381d290e75e5b3ab6e3/images/errors/interpreting-errors/ide.png -------------------------------------------------------------------------------- /images/github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/basarat/typescript-book/e31fe92c3afeea1bbcac4381d290e75e5b3ab6e3/images/github.png -------------------------------------------------------------------------------- /images/promise states and fates.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/basarat/typescript-book/e31fe92c3afeea1bbcac4381d290e75e5b3ab6e3/images/promise states and fates.png -------------------------------------------------------------------------------- /images/promise states and fates.vsd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/basarat/typescript-book/e31fe92c3afeea1bbcac4381d290e75e5b3ab6e3/images/promise states and fates.vsd -------------------------------------------------------------------------------- /images/venn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/basarat/typescript-book/e31fe92c3afeea1bbcac4381d290e75e5b3ab6e3/images/venn.png -------------------------------------------------------------------------------- /images/venn.vsd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/basarat/typescript-book/e31fe92c3afeea1bbcac4381d290e75e5b3ab6e3/images/venn.vsd -------------------------------------------------------------------------------- /snippets/md-snippets.cson: -------------------------------------------------------------------------------- 1 | '.source.gfm': 2 | 'include': 3 | 'prefix': 'include' 4 | 'body': """ 5 | {% include "${1:./path}.md" %} 6 | """ --------------------------------------------------------------------------------