/ittf/models/cheatsheets/ts/index.ittf.ittf (primary)
1 meta2 schema ts3 language typescript4 $include modules5 $include var6 $include functions7 $include classes8 $include interfaces9 $include generics10 $include advanced
/ittf/models/cheatsheets/ts/t/modules.ittf.ittf
1 element modules2 tag3 ast4 category5 item6 title Exporting a declaration7 expected8 + /* Validation.ts */9 + export interface StringValidator {10 + isAcceptable(s: string): boolean;11 + }12 + /* ZipCodeValidator.ts */13 + export const numberRegexp = /^[0-9]+$/;14 + export class ZipCodeValidator implements StringValidator {15 + isAcceptable(s: string) {16 + return s.length === 5 && numberRegexp.test(s);17 + }18 + }19 ittf20 +21 #22 # Validation.ts23 export24 :interface StringValidator25 :m isAcceptable26 :boolean27 param s28 :string29 #30 # ZipCodeValidator.ts31 export32 const numberRegexp = /^[0-9]+$/33 export34 class ZipCodeValidator35 :implements StringValidator36 m isAcceptable37 param s38 :string39 return s.length === 5 && numberRegexp.test(s)40 item41 title Export statements42 expected43 + class ZipCodeValidator implements StringValidator {44 + isAcceptable(s: string) {45 + return s.length === 5 && numberRegexp.test(s);46 + }47 + }48 + export { ZipCodeValidator };49 + export { ZipCodeValidator as mainValidator };50 ittf51 +52 class ZipCodeValidator53 :implements StringValidator54 m isAcceptable55 param s56 :string57 return s.length === 5 && numberRegexp.test(s)58 export59 @ ZipCodeValidator60 export61 @ ZipCodeValidator62 as mainValidator63 item64 title Re - exports65 expected66 + /* ParseIntBasedZipCodeValidator.ts */67 + export class ParseIntBasedZipCodeValidator {68 + isAcceptable(s: string) {69 + return s.length === 5 && parseInt(s).toString() === s;70 + }71 + }72 + // Export original validator but rename it73 + export { ZipCodeValidator as RegExpBasedZipCodeValidator } from "./ZipCodeValidator";74 + // Optionally, a module can wrap one or more modules and combine all their exports using export * from "module" syntax.75 + /* AllValidators.ts */76 + export * from "./StringValidator"; // exports interface 'StringValidator'77 + export * from "./LettersOnlyValidator"; // exports class 'LettersOnlyValidator'78 + export * from "./ZipCodeValidator"; // exports class 'ZipCodeValidator'79 ittf80 +81 #82 # ParseIntBasedZipCodeValidator.ts83 export84 class ParseIntBasedZipCodeValidator85 m isAcceptable86 param s87 :string88 return s.length === 5 && parseInt(s).toString() === s89 export90 @ ZipCodeValidator91 as RegExpBasedZipCodeValidator92 from "./ZipCodeValidator"93 #94 # AllValidators.ts95 export *96 from "./StringValidator"97 export *98 from "./LettersOnlyValidator"99 export *100 from "./ZipCodeValidator"101 item102 title Import a single export from a module103 expected104 + import { ZipCodeValidator } from "./ZipCodeValidator";105 + let myValidator = new ZipCodeValidator();106 + /* imports can also be renamed */107 + import { ZipCodeValidator as ZCV } from "./ZipCodeValidator";108 + let myValidator = new ZCV();109 + /* Import the entire module into a single variable, and use it to access the module exports */110 + import * as validator from "./ZipCodeValidator";111 + let myValidator = new validator.ZipCodeValidator();112 + /* Import a module for side- effects only */113 + import "./my-module.js";114 ittf115 +116 import117 @ ZipCodeValidator118 from "./ZipCodeValidator"119 let myValidator = new ZipCodeValidator()120 #121 # imports can also be renamed122 import123 @ ZipCodeValidator124 as ZCV125 from "./ZipCodeValidator"126 let myValidator = new ZCV()127 #128 # Import the entire module into a single variable, and use it to access the module exports129 import130 as validator131 from "./ZipCodeValidator"132 let myValidator = new validator.ZipCodeValidator()133 #134 # Import a module for side- effects only135 import "./my-module.js"136 item137 title Default exports138 expected139 + /* JQuery.d.ts */140 + declare let $: JQuery;141 + export default $;142 + /* App.ts */143 + import $ from "JQuery";144 + $("button.continue").html("Next Step...");145 ittf146 +147 #148 # JQuery.d.ts149 :declare150 let151 :ref JQuery152 export-default153 #154 # App.ts155 import $ from "JQuery"156 _ $("button.continue").html("Next Step...")157 item158 title Default exports of classes and functions159 expected160 + /* ZipCodeValidator.ts */161 + export default class ZipCodeValidator {162 + static numberRegexp = /^[0-9]+$/;163 + isAcceptable(s: string) {164 + return s.length === 5 && ZipCodeValidator.numberRegexp.test(s);165 + }166 + }167 + /* Test.ts */168 + import validator from "./ZipCodeValidator";169 + let myValidator = new validator();170 + /* or StaticZipCodeValidator.ts */171 + const numberRegexp = /^[0-9]+$/;172 + export default function (s: string) {173 + return s.length === 5 && numberRegexp.test(s);174 + }175 + /* Test.ts */176 + import validate from "./StaticZipCodeValidator";177 + let strings = ["Hello", "98052", "101"];178 + // Use function validate179 + strings.forEach(s => {180 + console.log(`"${s}" ${validate(s) ? " matches" : " does not match"}`);181 + });182 ittf183 +184 #185 # ZipCodeValidator.ts186 export-default187 class ZipCodeValidator188 p numberRegexp189 static190 := /^[0-9]+$/191 m isAcceptable192 param s193 :string194 return s.length === 5 && ZipCodeValidator.numberRegexp.test(s)195 #196 # Test.ts197 import validator from "./ZipCodeValidator"198 let myValidator = new validator()199 #200 # or201 # StaticZipCodeValidator.ts202 const numberRegexp = /^[0-9]+$/203 export-default204 function205 param s206 :string207 return s.length === 5 && numberRegexp.test(s)208 #209 # Test.ts210 import validate from "./StaticZipCodeValidator"211 let strings212 [213 @ "Hello"214 @ "98052"215 @ "101"216 _ strings.forEach217 =>218 param s219 _ console.log220 template221 + "222 @ s223 + "${}224 iif validate(s)225 then " matches"226 else " does not match"227 +228 item229 title Default exports can also be just values:230 expected231 + /* default exports can also be just values: */232 + /* OneTwoThree.ts */233 + export default "123";234 + /* Log.ts */235 + import num from "./OneTwoThree";236 + console.log(num); // "123"237 ittf238 +239 #240 # OneTwoThree.ts241 export-default "123"242 #243 # Log.ts244 import num from "./OneTwoThree"245 _ console.log(num)246 item247 title export = and import = require()248 expected249 + /* ZipCodeValidator.ts */250 + let numberRegexp = /^[0-9]+$/;251 + class ZipCodeValidator {252 + isAcceptable(s: string) {253 + return s.length === 5 && numberRegexp.test(s);254 + }255 + }256 + export = ZipCodeValidator;257 + /* Test.ts */258 + import zip = require("./ZipCodeValidator");259 + // Some samples to try260 + let strings = ["Hello", "98052", "101"];261 + // Validators to use262 + let validator = new zip();263 + // Show whether each string passed each validator264 + strings.forEach(s => {265 + console.log(`"${s}" - ${validator.isAcceptable(s) ? "matches" : "does not match"}`);266 + });267 ittf268 +269 #270 # ZipCodeValidator.ts271 let numberRegexp = /^[0-9]+$/272 class ZipCodeValidator273 m isAcceptable274 param s275 :string276 return s.length === 5 && numberRegexp.test(s)277 :export ZipCodeValidator278 #279 # Test.ts280 :import zip281 :require "./ZipCodeValidator"282 let strings283 [284 @ "Hello"285 @ "98052"286 @ "101"287 let validator = new zip()288 _ strings.forEach289 =>290 param s291 _ console.log292 template293 + "294 @ s295 + " -${}296 iif validator.isAcceptable(s)297 then "matches"298 else "does not match"299 +300 item301 title Code Generation for Modules302 expected303 + import m = require("mod");304 + export let t = m.something + 1;305 + /* AMD / RequireJS SimpleModule.js */306 + define(["require", "exports", "./mod"], function (require, exports, mod_1) {307 + exports.t = mod_1.something + 1;308 + });309 + /* CommonJS / Node SimpleModule.js */310 + var mod_1 = require("./mod");311 + exports.t = mod_1.something + 1;312 + /* UMD SimpleModule.js */313 + (function (factory) {314 + if (typeof module === "object" && typeof module.exports === "object") {315 + var v = factory(require, exports); if (v !== undefined) module.exports = v;316 + } else if (typeof define === "function" && define.amd) {317 + define(["require", "exports", "./mod"], factory);318 + }319 + })(function (require, exports) {320 + var mod_1 = require("./mod");321 + exports.t = mod_1.something + 1;322 + });323 + /* System SimpleModule.js */324 + System.register(["./mod"], function (exports_1) {325 + var mod_1;326 + var t;327 + return {328 + setters: [329 + function (mod_1_1) {330 + mod_1 = mod_1_1;331 + }],332 + execute: function () {333 + exports_1("t", t = mod_1.something + 1);334 + }335 + }336 + });337 + /* Native ECMAScript 2015 modules SimpleModule.js */338 + import { something } from "./mod";339 + export var t = something + 1;340 ittf341 +342 :import m343 :require "mod"344 export345 let t = m.something + 1346 #347 # AMD / RequireJS SimpleModule.js348 _ define349 [350 @ "require"351 @ "exports"352 @ "./mod"353 function354 param require355 param exports356 param mod_1357 set exports.t = mod_1.something + 1358 #359 # CommonJS / Node SimpleModule.js360 var mod_1 = require("./mod")361 set exports.t = mod_1.something + 1362 #363 # UMD SimpleModule.js364 iife365 param factory366 if typeof module === "object" && typeof module.exports === "object"367 var v = factory(require, exports)368 if v !== undefined369 set module.exports = v370 else371 if typeof define === "function" && define.amd372 _ define373 [374 @ "require"375 @ "exports"376 @ "./mod"377 @ factory378 ()379 function380 param require381 param exports382 var mod_1 = require("./mod")383 set exports.t = mod_1.something + 1384 #385 # System SimpleModule.js386 _ System.register387 [388 @ "./mod"389 function390 param exports_1391 var mod_1392 var t393 return394 {395 [ setters396 function397 param mod_1_1398 set mod_1 = mod_1_1399 @ execute400 function401 _ exports_1402 @ "t"403 set t = mod_1.something + 1404 #405 # Native ECMAScript 2015 modules SimpleModule.js406 import407 @ something408 from "./mod"409 export410 var t = something + 1411 item412 title Simple Example413 expected414 + /* Validation.ts */415 + export interface StringValidator {416 + isAcceptable(s: string): boolean;417 + }418 + /* LettersOnlyValidator.ts */419 + import { StringValidator } from "./Validation";420 + const lettersRegexp = /^[A-Za-z]+$/;421 + export class LettersOnlyValidator implements StringValidator {422 + isAcceptable(s: string) {423 + return lettersRegexp.test(s);424 + }425 + }426 + /* ZipCodeValidator.ts */427 + import { StringValidator } from "./Validation";428 + const numberRegexp = /^[0-9]+$/;429 + export class ZipCodeValidator implements StringValidator {430 + isAcceptable(s: string) {431 + return s.length === 5 && numberRegexp.test(s);432 + }433 + }434 + /* Test.ts */435 + import { StringValidator } from "./Validation";436 + import { ZipCodeValidator } from "./ZipCodeValidator";437 + import { LettersOnlyValidator } from "./LettersOnlyValidator";438 + // Some samples to try439 + let strings = ["Hello", "98052", "101"];440 + // Validators to use441 + let validators: { [s: string]: StringValidator; } = {};442 + validators["ZIP code"] = new ZipCodeValidator();443 + validators["Letters only"] = new LettersOnlyValidator();444 + // Show whether each string passed each validator445 + strings.forEach(s => {446 + for (let name in validators) {447 + console.log(`"${s}" - ${validators[name].isAcceptable(s) ? "matches" : "does not match"} ${name}`);448 + }449 + });450 ittf451 +452 #453 # Validation.ts454 export455 :interface StringValidator456 :m isAcceptable457 :boolean458 param s459 :string460 #461 # LettersOnlyValidator.ts462 import463 @ StringValidator464 from "./Validation"465 const lettersRegexp = /^[A-Za-z]+$/466 export467 class LettersOnlyValidator468 :implements StringValidator469 m isAcceptable470 param s471 :string472 return lettersRegexp.test(s)473 #474 # ZipCodeValidator.ts475 import476 @ StringValidator477 from "./Validation"478 const numberRegexp = /^[0-9]+$/479 export480 class ZipCodeValidator481 :implements StringValidator482 m isAcceptable483 param s484 :string485 return s.length === 5 && numberRegexp.test(s)486 #487 # Test.ts488 import489 @ StringValidator490 from "./Validation"491 import492 @ ZipCodeValidator493 from "./ZipCodeValidator"494 import495 @ LettersOnlyValidator496 from "./LettersOnlyValidator"497 let strings498 [499 @ "Hello"500 @ "98052"501 @ "101"502 let validators503 :{504 :index505 :ref StringValidator506 param s507 :string508 {509 set validators["ZIP code"] = new ZipCodeValidator()510 set validators["Letters only"] = new LettersOnlyValidator()511 _ strings.forEach512 =>513 param s514 for let name in validators515 _ console.log516 template517 + "518 @ s519 + " -${}520 iif validators[name].isAcceptable(s)521 then "matches"522 else "does not match"523 + ${}524 @ name525 +526 item527 title Optional Module Loading528 expected529 + /* Dynamic Module Loading in Node.js */530 + declare function require(moduleName: string): any;531 + import { ZipCodeValidator as Zip } from "./ZipCodeValidator";532 + if (needZipValidation) {533 + let ZipCodeValidator: typeof Zip = require("./ZipCodeValidator");534 + let validator = new ZipCodeValidator();535 + if (validator.isAcceptable("...")) { /* ... */ }536 + }537 + /* Sample: Dynamic Module Loading in require.js */538 + declare function require(moduleNames: string[], onLoad: (...args: any[]) => void): void;539 + import * as Zip from "./ZipCodeValidator";540 + if (needZipValidation) {541 + require(["./ZipCodeValidator"], (ZipCodeValidator: typeof Zip) => {542 + let validator = new ZipCodeValidator.ZipCodeValidator();543 + if (validator.isAcceptable("...")) { /* ... */ }544 + });545 + }546 + /* Sample: Dynamic Module Loading in System.js */547 + declare const System: any;548 + import { ZipCodeValidator as Zip } from "./ZipCodeValidator";549 + if (needZipValidation) {550 + System.import("./ZipCodeValidator").then((ZipCodeValidator: typeof Zip) => {551 + var x = new ZipCodeValidator();552 + if (x.isAcceptable("...")) { /* ... */ }553 + });554 + }555 ittf556 +557 #558 # Dynamic Module Loading in Node.js559 :declare560 :function require561 param moduleName562 :string563 :return564 :any565 import566 @ ZipCodeValidator567 as Zip568 from "./ZipCodeValidator"569 if needZipValidation570 let ZipCodeValidator571 :typeof Zip572 _ require("./ZipCodeValidator")573 let validator = new ZipCodeValidator()574 if validator.isAcceptable("...")575 #576 # Sample: Dynamic Module Loading in require.js577 :declare578 :function require579 param moduleNames580 :[581 :string582 param onLoad583 :=>584 :void585 param ...args586 :[587 :any588 :return589 :void590 import591 as Zip592 from "./ZipCodeValidator"593 if needZipValidation594 _ require595 [596 @ "./ZipCodeValidator"597 =>598 param ZipCodeValidator599 :typeof Zip600 let validator = new ZipCodeValidator.ZipCodeValidator()601 if validator.isAcceptable("...")602 #603 # Sample: Dynamic Module Loading in System.js604 :declare605 const System606 :any607 import608 @ ZipCodeValidator609 as Zip610 from "./ZipCodeValidator"611 if needZipValidation612 _ System.import("./ZipCodeValidator").then613 =>614 param ZipCodeValidator615 :typeof Zip616 var x = new ZipCodeValidator()617 if x.isAcceptable("...")618 item619 title Ambient Modules620 expected621 + /* node.d.ts(simplified excerpt) */622 + declare module "url" {623 + export interface Url {624 + protocol?: string;625 + hostname?: string;626 + pathname?: string;627 + }628 + export function parse(urlStr: string, parseQueryString?, slashesDenoteHost?): Url;629 + }630 + declare module "path" {631 + export function normalize(p: string): string;632 + export function join(...paths: any[]): string;633 + export var sep: string;634 + }635 + /* Now we can /// <reference> node.d.ts and then load the modules using import url = require("url"); or import * as URL from "url". */636 + /// <reference path="node.d.ts"/>637 + import * as URL from "url";638 + let myUrl = URL.parse("http://www.typescriptlang.org");639 ittf640 +641 #642 # node.d.ts(simplified excerpt)643 :declare644 :module "url"645 export646 :interface Url647 :p protocol648 :optional649 :string650 :p hostname651 :optional652 :string653 :p pathname654 :optional655 :string656 export657 :function parse658 param urlStr659 :string660 param parseQueryString661 :optional662 param slashesDenoteHost663 :optional664 :return665 :ref Url666 :module "path"667 export668 :function normalize669 param p670 :string671 :return672 :string673 export674 :function join675 param ...paths676 :[677 :any678 :return679 :string680 export681 var sep682 :string683 #684 # Now we can /// <reference> node.d.ts and then load the modules using import url = require("url"); or import * as URL from "url".685 import686 as URL687 from "url"688 let myUrl = URL.parse("http://www.typescriptlang.org")689 item690 title Shorthand ambient modules691 expected692 + /*declarations.d.ts */693 + declare module "hot-new-module";694 + /* All imports from a shorthand module will have the any type. */695 + import x, { y } from "hot-new-module";696 + x(y);697 ittf698 +699 #700 # declarations.d.ts701 :declare702 :module "hot-new-module"703 #704 # All imports from a shorthand module will have the any type.705 import x706 @ y707 from "hot-new-module"708 _ x(y)709 item710 title Wildcard module declarations711 expected712 + declare module "*!text" {713 + const content: string;714 + export default content;715 + }716 + // Some do it the other way around.717 + declare module "json!*" {718 + const value: any;719 + export default value;720 + }721 + /* Now you can import things that match "*!text" or "json!*". */722 + import fileContent from "./xyz.txt!text";723 + import data from "json!http://example.com/data.json";724 + console.log(data, fileContent);725 ittf726 +727 :declare728 :module "*!text"729 const content730 :string731 export-default content732 :module "json!*"733 const value734 :any735 export-default value736 #737 # Now you can import things that match "*!text" or "json!*".738 import fileContent from "./xyz.txt!text"739 import data from "json!http://example.com/data.json"740 _ console.log(data, fileContent)741 item742 title UMD modules743 expected744 + /* math-lib.d.ts */745 + export function isPrime(x: number): boolean;746 + export as namespace mathLib;747 + /* The library can then be used as an import within modules: */748 + import { isPrime } from "math-lib";749 + isPrime(2);750 + mathLib.isPrime(2); // ERROR: can't use the global definition from inside a module751 + /* It can also be used as a global variable, but only inside of a script. (A script is a file with no imports or exports.) */752 + mathLib.isPrime(2);753 ittf754 +755 #756 # math-lib.d.ts757 export758 :function isPrime759 param x760 :number761 :return762 :boolean763 :export-ns mathLib764 #765 # The library can then be used as an import within modules:766 import767 @ isPrime768 from "math-lib"769 _ isPrime(2)770 _ mathLib.isPrime(2)771 #772 # It can also be used as a global variable, but only inside of a script. (A script is a file with no imports or exports.)773 _ mathLib.isPrime(2)774 item775 title Export as close to top-level as possible776 expected777 + MyClass.ts */778 + export default class SomeType {779 + constructor() {}780 + }781 + /* MyFunc.ts */782 + export default function getThing() { return "thing"; }783 + /* Consumer.ts */784 + import t from "./MyClass";785 + import f from "./MyFunc";786 + let x = new t();787 + console.log(f());788 + /* MyThings.ts */789 + export class SomeType { /* ... */ }790 + export function someFunc() { /* ... */ }791 + /* Consumer.ts */792 + import { SomeType, someFunc } from "./MyThings";793 + let x = new SomeType();794 + let y = someFunc();795 + /* MyLargeModule.ts */796 + export class Dog { }797 + export class Cat { }798 + export class Tree { }799 + export class Flower { }800 + /* Consumer.ts */801 + import * as myLargeModule from "./MyLargeModule.ts";802 + let x = new myLargeModule.Dog();803 ittf804 +805 export-default806 class SomeType807 ctor808 #809 # MyFunc.ts810 export-default811 function getThing812 return "thing"813 #814 # Consumer.ts815 import t from "./MyClass"816 import f from "./MyFunc"817 let x = new t()818 _ console.log(f())819 #820 # This is optimal for consumers.821 # They can name your type whatever they want (t in this case) and don’t have to do any excessive dotting to find your objects.822 # If you’re exporting multiple objects, put them all at top- level823 # MyThings.ts824 export825 class SomeType826 export827 function someFunc828 #829 # Conversely when importing:830 # Explicitly list imported names831 # Consumer.ts832 import833 @ SomeType834 @ someFunc835 from "./MyThings"836 let x = new SomeType()837 let y = someFunc()838 #839 # Use the namespace import pattern if you’re importing a large number of things840 # MyLargeModule.ts841 export842 class Dog843 export844 class Cat845 export846 class Tree847 export848 class Flower849 #850 # Consumer.ts851 import852 as myLargeModule853 from "./MyLargeModule.ts"854 let x = new myLargeModule.Dog()855 item856 title Re -export to extend857 expected858 + export class Calculator {859 + private current = 0;860 + private memory = 0;861 + private operator: string;862 + protected processDigit(digit: string, currentValue: number) {863 + if (digit >= "0" && digit <= "9") {864 + return currentValue * 10 + (digit.charCodeAt(0) - "0".charCodeAt(0));865 + }866 + }867 + protected processOperator(operator: string) {868 + if (["+", "-", "*", "/"].indexOf(operator) >= 0) {869 + return operator;870 + }871 + }872 + protected evaluateOperator(operator: string, left: number, right: number): number {873 + switch (this.operator) {874 + case "+": return left + right;875 + case "-": return left - right;876 + case "*": return left * right;877 + case "/": return left / right;878 + }879 + }880 + private evaluate() {881 + if (this.operator) {882 + this.memory = this.evaluateOperator(this.operator, this.memory, this.current);883 + } else {884 + this.memory = this.current;885 + }886 + this.current = 0;887 + }888 + public handleChar(char: string) {889 + if (char === "=") {890 + this.evaluate();891 + return;892 + } else {893 + let value = this.processDigit(char, this.current);894 + if (value !== undefined) {895 + this.current = value;896 + return;897 + } else {898 + let value = this.processOperator(char);899 + if (value !== undefined) {900 + this.evaluate();901 + this.operator = value;902 + return;903 + }904 + }905 + }906 + throw new Error(`Unsupported input: '${char}'`);907 + }908 + public getResult() {909 + return this.memory;910 + }911 + }912 + export function test(c: Calculator, input: string) {913 + for (let i = 0; i < input.length; i++) {914 + c.handleChar(input[i]);915 + }916 + console.log(`result of '${input}' is '${c.getResult()}'`);917 + }918 + /* Here is a simple test for the calculator using the exposed test function. */919 + /* TestCalculator.ts */920 + import { Calculator, test } from "./Calculator";921 + let c = new Calculator();922 + test(c, "1+2*33/11="); // prints 9923 + /* Now to extend this to add support for input with numbers in bases other than 10, let’s create ProgrammerCalculator.ts924 + /* ProgrammerCalculator.ts */925 + import { Calculator } from "./Calculator";926 + class ProgrammerCalculator extends Calculator {927 + static digits = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"];928 + constructor(public base: number) {929 + super();930 + const maxBase = ProgrammerCalculator.digits.length;931 + if (base <= 0 || base > maxBase) {932 + throw new Error(`base has to be within 0 to ${maxBase} inclusive.`);933 + }934 + }935 + protected processDigit(digit: string, currentValue: number) {936 + if (ProgrammerCalculator.digits.indexOf(digit) >= 0) {937 + return currentValue * this.base + ProgrammerCalculator.digits.indexOf(digit);938 + }939 + }940 + }941 + // Export the new extended calculator as Calculator942 + export { ProgrammerCalculator as Calculator };943 + // Also, export the helper function944 + export { test } from "./Calculator";945 + /* TestProgrammerCalculator.ts */946 + import { Calculator, test } from "./ProgrammerCalculator";947 + let c = new Calculator(2);948 + test(c, "001+010="); // prints 3949 ittf950 +951 export952 class Calculator953 p current954 :private955 := 0956 p memory957 :private958 := 0959 p operator960 :private961 :string962 m processDigit963 :protected964 param digit965 :string966 param currentValue967 :number968 if digit >= "0" && digit <= "9"969 return currentValue * 10 + (digit.charCodeAt(0) - "0".charCodeAt(0))970 m processOperator971 :protected972 param operator973 :string974 if975 test976 >=977 [978 @ "+"979 @ "-"980 @ "*"981 @ "/"982 ._ indexOf983 @ operator984 + 0985 return operator986 m evaluateOperator987 :protected988 param operator989 :string990 param left991 :number992 param right993 :number994 :return995 :number996 switch this.operator997 case "+"998 return left + right999 case "-"1000 return left - right1001 case "*"1002 return left * right1003 case "/"1004 return left / right1005 m evaluate1006 :private1007 if this.operator1008 set this.memory = this.evaluateOperator(this.operator, this.memory, this.current)1009 else1010 set this.memory = this.current1011 set this.current = 01012 m handleChar1013 :public1014 param char1015 :string1016 if char === "="1017 _ this.evaluate1018 return1019 else1020 let value = this.processDigit(char, this.current)1021 if value !== undefined1022 set this.current = value1023 return1024 else1025 let value = this.processOperator(char)1026 if value !== undefined1027 _ this.evaluate1028 set this.operator = value1029 return1030 throw1031 new Error1032 template1033 + Unsupported input: '1034 @ char1035 + '1036 m getResult1037 :public1038 return this.memory1039 export1040 function test1041 param c1042 :ref Calculator1043 param input1044 :string1045 for let i = 0; i < input.length; i++1046 _ c.handleChar(input[i])1047 _ console.log1048 template1049 + result of '1050 @ input1051 + ' is '1052 _ c.getResult1053 + '1054 #1055 # Here is a simple test for the calculator using the exposed test function.1056 #1057 # TestCalculator.ts1058 import1059 @ Calculator1060 @ test1061 from "./Calculator"1062 let c = new Calculator()1063 _ test(c, "1+2*33/11=")1064 #1065 # Now to extend this to add support for input with numbers in bases other than 10, let’s create ProgrammerCalculator.ts1066 # ProgrammerCalculator.ts1067 import1068 @ Calculator1069 from "./Calculator"1070 class ProgrammerCalculator1071 super Calculator1072 p digits1073 static1074 [1075 @ "0"1076 @ "1"1077 @ "2"1078 @ "3"1079 @ "4"1080 @ "5"1081 @ "6"1082 @ "7"1083 @ "8"1084 @ "9"1085 @ "A"1086 @ "B"1087 @ "C"1088 @ "D"1089 @ "E"1090 @ "F"1091 ctor1092 param base1093 :public1094 :number1095 _ super1096 const maxBase = ProgrammerCalculator.digits.length1097 if base <= 0 || base > maxBase1098 throw1099 new Error1100 template1101 + base has to be within 0 to${}1102 @ maxBase1103 + ${}inclusive.1104 m processDigit1105 :protected1106 param digit1107 :string1108 param currentValue1109 :number1110 if ProgrammerCalculator.digits.indexOf(digit) >= 01111 return currentValue * this.base + ProgrammerCalculator.digits.indexOf(digit)1112 export1113 @ ProgrammerCalculator1114 as Calculator1115 export1116 @ test1117 from "./Calculator"1118 #1119 # The new module ProgrammerCalculator exports an API shape similar to that of the original Calculator module,1120 # but does not augment any objects in the original module. Here is a test for our ProgrammerCalculator class:1121 # TestProgrammerCalculator.ts1122 import1123 @ Calculator1124 @ test1125 from "./ProgrammerCalculator"1126 let c = new Calculator(2)1127 _ test(c, "001+010=")
/ittf/models/cheatsheets/ts/t/var.ittf.ittf
1 element variables2 tag3 ast4 category5 item6 title Boolean7 expected8 + let isDone: boolean = false;9 ittf10 let isDone11 :boolean12 := false13 item14 title Number15 expected16 + let decimal: number = 6;17 ittf18 let decimal19 :number20 := 621 item22 title String23 expected24 + let color: string = "blue";25 ittf26 let color27 :string28 := "blue"29 item30 title String literal 131 expected32 + let fullName: string = `Bob Bobbington`;33 ittf34 let fullName35 :string36 template37 + Bob Bobbington38 item39 title String literal 240 expected41 + let sentence: string = `Hello, my name is ${fullName}`;42 ittf43 let sentence44 :string45 template46 + Hello, my name is${}47 @ fullName48 +49 item50 title String literal 351 expected52 + let sentence: string = "Hello, my name is " + fullName + ".\n\n" + "I'll be " + (age + 1) + " years old next month.";53 ittf54 let sentence55 :string56 set "Hello, my name is " + fullName + ".\n\n" + "I'll be " + (age + 1) + " years old next month."57 item58 title Array 159 expected60 + let list: number[] = [1, 2, 3];61 ittf62 let list63 :[64 :number65 [66 @ 167 @ 268 @ 369 item70 title Array 271 expected72 + let list: Array<number> = [1, 2, 3];73 ittf74 let list75 :ref Array76 :param number77 [78 @ 179 @ 280 @ 381 item82 title Tuple83 expected84 + let x: [string, number];85 ittf86 let x87 :tuple88 :string89 :number90 item91 title Enum92 expected93 + enum Color { Red, Green, Blue }94 + let c: Color = Color.Green;95 + enum Color { Red = 1, Green, Blue }96 + let c: Color = Color.Green;97 + enum Color { Red = 1, Green = 2, Blue = 4 }98 + let c: Color = Color.Green;99 + enum Color { Red = 1, Green, Blue }100 + let colorName: string = Color[2];101 ittf102 +103 :enum Color104 @ Red105 @ Green106 @ Blue107 let c108 :ref Color109 := Color.Green110 :enum Color111 @ Red 1112 @ Green113 @ Blue114 let c115 :ref Color116 := Color.Green117 :enum Color118 @ Red 1119 @ Green 2120 @ Blue 4121 let c122 :ref Color123 := Color.Green124 :enum Color125 @ Red 1126 @ Green127 @ Blue128 let colorName129 :string130 := Color[2]131 item132 title Any, Void, Null, Undefined133 expected134 + let notSure: any = 4;135 + notSure = "maybe a string instead";136 + notSure = false; // okay, definitely a boolean137 + let notSure: any = 4;138 + notSure.ifItExists(); // okay, ifItExists might exist at runtime139 + notSure.toFixed(); // okay, toFixed exists (but the compiler doesn't check)140 + let prettySure: Object = 4;141 + prettySure.toFixed(); // Error: Property 'toFixed' doesn't exist on type 'Object'.142 + let list: any[] = [1, true, "free"];143 + list[1] = 100;144 + function warnUser(): void {145 + console.log("This is my warning message");146 + }147 + let unusable: void = undefined;148 + let u: undefined = undefined;149 + let n: null = null;150 ittf151 +152 let notSure153 :any154 := 4155 set notSure = "maybe a string instead"156 set notSure = false157 let notSure158 :any159 := 4160 _ notSure.ifItExists161 _ notSure.toFixed162 let prettySure163 :ref Object164 := 4165 _ prettySure.toFixed166 let list167 :[168 :any169 [170 @ 1171 @ true172 @ "free"173 set list[1] = 100174 function warnUser175 :return176 :void177 _ console.log("This is my warning message")178 let unusable179 :void180 := undefined181 let u182 :void183 := undefined184 let n185 :null186 := null187 item188 title Never189 expected190 + function error(message: string): never {191 + throw new Error(message);192 + }193 + function fail() {194 + return error("Something failed");195 + }196 + function infiniteLoop(): never {197 + while (true) {198 + }199 + }200 ittf201 +202 function error203 param message204 :string205 :return206 :never207 throw new Error(message)208 function fail209 return error("Something failed")210 function infiniteLoop211 :return212 :never213 while true214 item215 title Object216 expected217 + declare function create(o: object | null): void;218 + let strLength: number = (someValue as string).length;219 ittf220 +221 :function create222 param o223 :union224 :object225 :null226 :return227 :void228 let strLength229 :number230 :=231 ()232 @id someValue233 :as234 :string235 . length
/ittf/models/cheatsheets/ts/t/functions.ittf.ittf
1 element function2 tag function3 ast4 category5 item6 title Typed functions 17 expected8 + function add(x: number, y: number): number {9 + return x + y;10 + }11 + let myAdd = function (x: number, y: number): number { return x + y; };12 ittf13 +14 function add15 param x16 :number17 param y18 :number19 :return20 :number21 return x + y22 let myAdd23 function24 param x25 :number26 param y27 :number28 :return29 :number30 return x + y31 item32 title Typed functions 233 expected34 + let myAdd: (baseValue: number, increment: number) => number =35 + function (x, y) { return x + y; };36 ittf37 let myAdd38 :=>39 :number40 param x41 :number42 param y43 :number44 function45 param x46 :number47 param y48 :number49 :return50 :number51 return x + y52 item53 title Optional parameters54 expected55 + function buildName(firstName: string, lastName?: string) {56 + if (lastName)57 + return firstName + " " + lastName;58 + else59 + return firstName;60 + }61 + let result1 = buildName("Bob"); // error, too few parameters62 + let result2 = buildName("Bob", "Adams", "Sr."); // error, too many parameters63 + let result3 = buildName("Bob", "Adams"); // ah, just right64 ittf65 +66 function buildName67 param firstName68 :string69 param lastName70 :string71 :optional72 if lastName73 return firstName + " " + lastName74 else75 return firstName76 # error, too few parameters77 let result1 = buildName("Bob")78 # error, too many parameters79 let result2 = buildName("Bob", "Adams", "Sr.")80 # ah, just right81 let result3 = buildName("Bob", "Adams")82 item83 title Rest parameters84 expected85 + function buildName(firstName: string, ...restOfName: string[]) {86 + return firstName + " " + restOfName.join(" ");87 + }88 + let buildNameFun: (fname: string, ...rest: string[]) => string = buildName;89 ittf90 +91 function buildName92 param firstName93 :string94 param ...restOfName95 :[96 :string97 return firstName + " " + restOfName.join(" ")98 let buildNameFun99 :=>100 :string101 param fname102 :string103 param ...rest104 :[105 :string106 := buildName107 item108 title This and arrow functions109 expected110 + let deck = {111 + suits: ["hearts", "spades", "clubs", "diamonds"],112 + cards: Array(52),113 + createCardPicker: function () {114 + return () => {115 + let pickedCard = Math.floor(Math.random() * 52);116 + let pickedSuit = Math.floor(pickedCard / 13);117 + return { suit: this.suits[pickedSuit], card: pickedCard % 13 };118 + }119 + }120 + }121 + let cardPicker = deck.createCardPicker();122 + let pickedCard = cardPicker();123 + alert("card: " + pickedCard.card + " of " + pickedCard.suit);124 ittf125 let deck126 {127 [ suits128 @ "hearts"129 @ "spades"130 @ "clubs"131 @ "diamonds"132 @ cards Array(52)133 @ createCardPicker134 function135 # NOTE: the line below is now an arrow function, allowing us to capture 'this' right here136 return137 =>138 let pickedCard = Math.floor(Math.random() * 52)139 let pickedSuit = Math.floor(pickedCard / 13)140 return141 {142 @ suit this.suits[pickedSuit]143 @ card pickedCard % 13144 item145 title This parameters in callbacks146 expected147 + interface UIElement {148 + addClickListener(onclick: (this: void, e: Event) => void): void;149 + }150 + class Handler {151 + info: string;152 + onClickBad(this: Handler, e: Event) {153 + // oops, used this here. using this callback would crash at runtime154 + this.info = e.message;155 + }156 + }157 ittf158 +159 :interface UIElement160 :m addClickListener161 :void162 param onclick163 :=>164 :void165 param this166 :void167 param e168 :ref Event169 class Handler170 p info171 :string172 m onClickBad173 param this174 :ref Handler175 param e176 :ref Event177 set this.info = e.message178 item179 title Overloads 1180 expected181 + let suits = ["hearts", "spades", "clubs", "diamonds"];182 + function pickCard(x): any {183 + // Check to see if we're working with an object/array184 + // if so, they gave us the deck and we'll pick the card185 + if (typeof x == "object") {186 + let pickedCard = Math.floor(Math.random() * x.length);187 + return pickedCard;188 + }189 + // Otherwise just let them pick the card190 + else if (typeof x == "number") {191 + let pickedSuit = Math.floor(x / 13);192 + return { suit: suits[pickedSuit], card: x % 13 };193 + }194 + }195 ittf196 +197 let suits198 [199 @ "hearts"200 @ "spades"201 @ "clubs"202 @ "diamonds"203 function pickCard204 param x205 :return206 :any207 if typeof x == "object"208 let pickedCard = Math.floor(Math.random() * x.length)209 return pickedCard210 else211 # Otherwise just let them pick the card212 if typeof x == "number"213 let pickedSuit = Math.floor(x / 13)214 return215 {216 @ suit suits[pickedSuit]217 @ card x % 13218 item219 title Overloads 2220 expected221 + let suits = ["hearts", "spades", "clubs", "diamonds"];222 + function pickCard(x: { suit: string; card: number; }[]): number;223 + function pickCard(x: number): { suit: string; card: number; };224 + function pickCard(x): any {225 + // Check to see if we're working with an object/array226 + // if so, they gave us the deck and we'll pick the card227 + if (typeof x == "object") {228 + let pickedCard = Math.floor(Math.random() * x.length);229 + return pickedCard;230 + }231 + // Otherwise just let them pick the card232 + else if (typeof x == "number") {233 + let pickedSuit = Math.floor(x / 13);234 + return { suit: suits[pickedSuit], card: x % 13 };235 + }236 + }237 ittf238 +239 let suits240 [241 @ "hearts"242 @ "spades"243 @ "clubs"244 @ "diamonds"245 :function pickCard246 param x247 :[248 :{249 :p suit250 :string251 :p card252 :number253 :return254 :number255 :function pickCard256 param x257 :number258 :return259 :{260 :p suit261 :string262 :p card263 :number264 function pickCard265 param x266 :return267 :any268 # if so, they gave us the deck and we'll pick the card269 if typeof x == "object"270 let pickedCard = Math.floor(Math.random() * x.length)271 return pickedCard272 else273 # Otherwise just let them pick the card274 if typeof x == "number"275 let pickedSuit = Math.floor(x / 13)276 return277 {278 @ suit suits[pickedSuit]279 @ card x % 13
/ittf/models/cheatsheets/ts/t/classes.ittf.ittf
1 element class2 tag class3 ast4 category5 item6 title Simple class7 expected8 + class Greeter {9 + greeting: string;10 + constructor(message: string) {11 + this.greeting = message;12 + }13 + greet() {14 + return "Hello, " + this.greeting;15 + }16 + }17 + let greeter = new Greeter("world");18 ittf19 class Greeter20 p greeting21 :string22 ctor23 param message24 :string25 set this.greeting = message26 m greet27 return "Hello, " + this.greeting28 let greeter = new Greeter("world")29 item30 title Class extension31 expected32 + class Animal {33 + move(distanceInMeters: number = 0) {34 + console.log(`Animal moved ${distanceInMeters}m.`);35 + }36 + }37 + class Dog extends Animal {38 + bark() {39 + console.log('Woof! Woof!');40 + }41 + }42 ittf43 class Animal44 m move45 param distanceInMeters46 :number47 := 048 _ console.log49 template50 + Animal moved${}51 @ distanceInMeters52 + m.53 class Dog54 super Animal55 m bark56 _ console.log('Woof! Woof!')57 item58 title Complex class example59 expected60 + class Animal {61 + name: string;62 + constructor(theName: string) { this.name = theName; }63 + move(distanceInMeters: number = 0) {64 + console.log(`${this.name} moved ${distanceInMeters}m.`);65 + }66 + }67 + class Snake extends Animal {68 + constructor(name: string) { super(name); }69 + move(distanceInMeters = 5) {70 + console.log("Slithering...");71 + super.move(distanceInMeters);72 + }73 + }74 + class Horse extends Animal {75 + constructor(name: string) { super(name); }76 + move(distanceInMeters = 45) {77 + console.log("Galloping...");78 + super.move(distanceInMeters);79 + }80 + }81 + let sam = new Snake("Sammy the Python");82 + let tom: Animal = new Horse("Tommy the Palomino");83 + sam.move();84 + tom.move(34);85 ittf86 +87 class Animal88 p name89 :string90 ctor91 param theName92 :string93 set this.name = theName94 m move95 param distanceInMeters96 :number97 := 098 _ console.log99 template100 +101 @ this.name102 + ${}moved${}103 @ distanceInMeters104 + m.105 class Snake106 super Animal107 ctor108 param name109 :string110 _ super(name)111 m move112 param distanceInMeters = 5113 _ console.log("Slithering...")114 _ super.move(distanceInMeters)115 class Horse116 super Animal117 ctor118 param name119 :string120 _ super(name)121 m move122 param distanceInMeters = 45123 _ console.log("Galloping...")124 _ super.move(distanceInMeters)125 item126 title Class accessors127 expected128 + class Animal {129 + private name: string;130 + constructor(theName: string) { this.name = theName; }131 + }132 + class Rhino extends Animal {133 + constructor() { super("Rhino"); }134 + }135 + class Employee {136 + private name: string;137 + constructor(theName: string) { this.name = theName; }138 + }139 + let animal = new Animal("Goat");140 + let rhino = new Rhino();141 + let employee = new Employee("Bob");142 + animal = rhino;143 + animal = employee; // Error: 'Animal' and 'Employee' are not compatible144 ittf145 +146 class Animal147 p name148 :private149 :string150 ctor151 param theName152 :string153 set this.name = theName154 class Rhino155 super Animal156 ctor157 _ super("Rhino")158 class Employee159 p name160 :private161 :string162 ctor163 param theName164 :string165 set this.name = theName166 let animal = new Animal("Goat")167 let rhino = new Rhino()168 let employee = new Employee("Bob")169 set animal = rhino170 set animal = employee171 item172 title Class accessors173 expected174 + class Person {175 + protected name: string;176 + constructor(name: string) { this.name = name; }177 + }178 + class Employee extends Person {179 + private department: string;180 + constructor(name: string, department: string) {181 + super(name);182 + this.department = department;183 + }184 + public getElevatorPitch() {185 + return `Hello, my name is ${this.name} and I work in ${this.department}.`;186 + }187 + }188 + let howard = new Employee("Howard", "Sales");189 + console.log(howard.getElevatorPitch());190 + console.log(howard.name); // error191 ittf192 +193 class Person194 p name195 :protected196 :string197 ctor198 param name199 :string200 set this.name = name201 class Employee202 super Person203 p department204 :private205 :string206 ctor207 param name208 :string209 param department210 :string211 _ super(name)212 set this.department = department213 m getElevatorPitch214 :public215 return216 template217 + Hello, my name is${}218 @ this.name219 + ${}and I work in${}220 @ this.department221 + .222 item223 title Readonly modifier224 expected225 + class Octopus {226 + readonly name: string;227 + readonly numberOfLegs: number = 8;228 + constructor(theName: string) {229 + this.name = theName;230 + }231 + }232 + let dad = new Octopus("Man with the 8 strong legs");233 + dad.name = "Man with the 3-piece suit"; // error! name is readonly.234 ittf235 +236 class Octopus237 p name238 :readonly239 :string240 p numberOfLegs241 :readonly242 :number243 := 8244 ctor245 param theName246 :string247 set this.name = theName248 let dad = new Octopus("Man with the 8 strong legs")249 set dad.name = "Man with the 3-piece suit"250 item251 title Parameter properties252 expected253 + class Octopus {254 + readonly numberOfLegs: number = 8;255 + constructor(readonly name: string) {256 + }257 + }258 ittf259 +260 class Octopus261 p numberOfLegs262 :readonly263 :number264 := 8265 ctor266 param267 :readonly268 :string269 item270 title Static members271 expected272 + class Grid {273 + static origin = { x: 0, y: 0 };274 + calculateDistanceFromOrigin(point: { x: number; y: number; }) {275 + let xDist = (point.x - Grid.origin.x);276 + let yDist = (point.y - Grid.origin.y);277 + return Math.sqrt(xDist * xDist + yDist * yDist) / this.scale;278 + }279 + constructor(public scale: number) { }280 + }281 ittf282 class Grid283 p origin284 static285 {286 @ x 0287 @ y 0288 m calculateDistanceFromOrigin289 param point290 :{291 :p x292 :number293 :p y294 :number295 let xDist = (point.x - Grid.origin.x)296 let yDist = (point.y - Grid.origin.y)297 return Math.sqrt(xDist * xDist + yDist * yDist) / this.scale298 ctor299 param scale300 :public301 :number302 item303 title Abstract classes 1304 expected305 + abstract class Animal {306 + abstract makeSound(): void;307 + move(): void {308 + console.log("roaming the earth...");309 + }310 + }311 ittf312 +313 class Animal314 :abstract315 :m makeSound316 :abstract317 :return318 :void319 m move320 :return321 :void322 _ console.log("roaming the earth...")323 item324 title Abstract classes 2325 expected326 + abstract class Department {327 + constructor(public name: string) {328 + }329 + printName(): void {330 + console.log("Department name: " + this.name);331 + }332 + abstract printMeeting(): void; // must be implemented in derived classes333 + }334 + class AccountingDepartment extends Department {335 + constructor() {336 + super("Accounting and Auditing"); // constructors in derived classes must call super()337 + }338 + printMeeting(): void {339 + console.log("The Accounting Department meets each Monday at 10am.");340 + }341 + generateReports(): void {342 + console.log("Generating accounting reports...");343 + }344 + }345 + let department: Department; // ok to create a reference to an abstract type346 + department = new Department(); // error: cannot create an instance of an abstract class347 + department = new AccountingDepartment(); // ok to create and assign a non-abstract subclass348 + department.printName();349 + department.printMeeting();350 + department.generateReports(); // error: method doesn't exist on declared abstract type351 ittf352 +353 class Department354 :abstract355 ctor356 param name357 :public358 :string359 m printName360 :return361 :void362 _ console.log("Department name: " + this.name)363 :m printMeeting364 :abstract365 :return366 :void367 class AccountingDepartment368 super Department369 ctor370 _ super("Accounting and Auditing")371 m printMeeting372 :return373 :void374 _ console.log("The Accounting Department meets each Monday at 10am.")375 m generateReports376 :return377 :void378 _ console.log("Generating accounting reports...")379 let department380 :ref Department381 set department = new Department()382 set department = new AccountingDepartment()383 _ department.printName384 _ department.printMeeting385 _ department.generateReports386 # error: method doesn't exist on declared abstract type387 item388 title Static members389 expected390 + class Greeter {391 + static standardGreeting = "Hello, there";392 + greeting: string;393 + greet() {394 + if (this.greeting) {395 + return "Hello, " + this.greeting;396 + } else {397 + return Greeter.standardGreeting;398 + }399 + }400 + }401 ittf402 +403 class Greeter404 p standardGreeting405 static406 := "Hello, there"407 p greeting408 :string409 m greet410 if this.greeting411 return "Hello, " + this.greeting412 else413 return Greeter.standardGreeting414 item415 title Class extended by interface416 expected417 + class Point {418 + x: number;419 + y: number;420 + }421 + interface Point3d extends Point {422 + z: number;423 + }424 + let point3d: Point3d = { x: 1, y: 2, z: 3 };425 ittf426 +427 class Point428 p x429 :number430 p y431 :number432 :interface Point3d433 :extends Point434 :p z435 :number436 let point3d437 :ref Point3d438 {439 @ x 1440 @ y 2441 @ z 3
/ittf/models/cheatsheets/ts/t/interfaces.ittf.ittf
1 element interfaces2 tag3 ast4 category5 item6 title Simple interface7 expected8 + interface LabelledValue {9 + label: string;10 + }11 ittf12 :interface LabelledValue13 :p label14 :string15 item16 title Reference to interface17 expected18 + function printLabel(labelledObj: LabelledValue) {19 + console.log(labelledObj.label);20 + }21 + let myObj = { size: 10, label: "Size 10 Object" };22 + printLabel(myObj);23 ittf24 +25 function printLabel26 param labelledObj27 :ref LabelledValue28 _ console.log(labelledObj.label)29 let myObj30 {31 @ size 1032 @ label "Size 10 Object"33 _ printLabel(myObj)34 item35 title Optional properties36 expected37 + interface SquareConfig {38 + color?: string;39 + width?: number;40 + }41 ittf42 :interface SquareConfig43 :p color44 :optional45 :string46 :p width47 :optional48 :number49 item50 title Optional properties 251 expected52 + interface SquareConfig {53 + color?: string;54 + width?: number;55 + }56 + function createSquare(config: SquareConfig): { color: string; area: number } {57 + let newSquare = { color: "white", area: 100 };58 + if (config.clor) {59 + // Error: Property 'clor' does not exist on type 'SquareConfig'60 + newSquare.color = config.clor;61 + }62 + if (config.width) {63 + newSquare.area = config.width * config.width;64 + }65 + return newSquare;66 + }67 + let mySquare = createSquare({ color: "black" });68 ittf69 +70 :interface SquareConfig71 :p color72 :optional73 :string74 :p width75 :optional76 :number77 function createSquare78 param config79 :ref SquareConfig80 :return81 :{82 :p color83 :string84 :p area85 :number86 let newSquare87 {88 @ color "white"89 @ area 10090 if config.clor91 # Error: Property 'clor' does not exist on type 'SquareConfig'92 set newSquare.color = config.clor93 if config.width94 set newSquare.area = config.width * config.width95 return newSquare96 let mySquare97 _ createSquare98 {99 @ color "black"100 item101 title Readonly properties102 expected103 + interface Point {104 + readonly x: number;105 + readonly y: number;106 + }107 + // You can construct a Point by assigning an object literal.After the assignment, x and y can’t be changed.108 + let p1: Point = { x: 10, y: 20 };109 + p1.x = 5; // error!110 ittf111 +112 :interface Point113 :p x114 :number115 :p y116 :number117 # You can construct a Point by assigning an object literal.After the assignment, x and y can’t be changed.118 let p1119 :ref Point120 {121 @ x 10122 @ y 20123 # error!124 set p1.x = 5125 item126 title Readonly vs const127 expected128 + interface SquareConfig {129 + color?: string;130 + width?: number;131 + }132 + function createSquare(config: SquareConfig): { color: string; area: number } {133 + // ...134 + }135 + let mySquare = createSquare({ colour: "red", width: 100 });136 ittf137 +138 :interface SquareConfig139 :p color140 :optional141 :string142 :p width143 :optional144 :number145 function createSquare146 param config147 :ref SquareConfig148 :return149 :{150 :p color151 :string152 :p area153 :number154 let mySquare155 _ createSquare156 {157 @ colour "red"158 @ width 100159 item160 title Call signature161 expected162 + interface SearchFunc {163 + (source: string, subString: string): boolean;164 + }165 + let mySearch: SearchFunc;166 + mySearch = function (source: string, subString: string) {167 + let result = source.search(subString);168 + return result > -1;169 + }170 ittf171 +172 :interface SearchFunc173 :call174 :boolean175 param source176 :string177 param subString178 :string179 let mySearch180 :ref SearchFunc181 set mySearch =182 function183 param source184 :string185 param subString186 :string187 let result = source.search(subString)188 return result > -1189 item190 title Index signature191 expected192 + interface StringArray {193 + [index: number]: string;194 + }195 + let myArray: StringArray;196 + myArray = ["Bob", "Fred"];197 + let myStr: string = myArray[0];198 ittf199 +200 :interface StringArray201 :index202 :string203 param index204 :number205 let myArray206 :ref StringArray207 set myArray =208 [209 @ "Bob"210 @ "Fred"211 let myStr212 :string213 := myArray[0]214 item215 title Index signature 2216 expected217 + class Animal {218 + name: string;219 + }220 + class Dog extends Animal {221 + breed: string;222 + }223 + // Error: indexing with a numeric string might get you a completely separate type of Animal!224 + interface NotOkay {225 + [x: number]: Animal;226 + [x: string]: Dog;227 + }228 ittf229 +230 class Animal231 p name232 :string233 class Dog234 super Animal235 p breed236 :string237 :interface NotOkay238 :index239 :ref Animal240 param x241 :number242 :index243 :ref Dog244 param x245 :string246 item247 title Index signature 3248 expected249 + interface NumberDictionary {250 + [index: string]: number;251 + length: number; // ok, length is a number252 + name: string; // error, the type of 'name' is not a subtype of the indexer253 + }254 ittf255 :interface NumberDictionary256 :index257 :number258 param index259 :string260 :p length261 :number262 :p name263 :string264 item265 title Readonly index signature 3266 expected267 + interface ReadonlyStringArray {268 + readonly [index: number]: string;269 + }270 + let myArray: ReadonlyStringArray = ["Alice", "Bob"];271 + myArray[2] = "Mallory"; // error!272 ittf273 +274 :interface ReadonlyStringArray275 :index276 :string277 :readonly278 param index279 :number280 let myArray281 :ref ReadonlyStringArray282 [283 @ "Alice"284 @ "Bob"285 set myArray[2] = "Mallory"286 item287 title Class Types288 expected289 + interface ClockInterface {290 + currentTime: Date;291 + }292 + class Clock implements ClockInterface {293 + currentTime: Date;294 + constructor(h: number, m: number) { }295 + }296 + interface ClockInterface {297 + currentTime: Date;298 + setTime(d: Date);299 + }300 + class Clock implements ClockInterface {301 + currentTime: Date;302 + setTime(d: Date) {303 + this.currentTime = d;304 + }305 + constructor(h: number, m: number) {}306 + }307 ittf308 +309 :interface ClockInterface310 :p currentTime311 :ref Date312 class Clock313 :implements ClockInterface314 p currentTime315 :ref Date316 ctor317 param h318 :number319 param m320 :number321 :interface ClockInterface322 :p currentTime323 :ref Date324 :m setTime325 param d326 :ref Date327 class Clock328 :extends ClockInterface329 p currentTime330 :ref Date331 m setTime332 param d333 :ref Date334 set this.currentTime = d335 ctor336 param h337 :number338 param m339 :number340 item341 title static and instance sides of classes - fails342 expected343 + interface ClockConstructor {344 + new (hour: number, minute: number);345 + }346 + // Error. Since the constructor sits in the static side, it is not included in this check.347 + class Clock implements ClockConstructor {348 + currentTime: Date;349 + constructor(h: number, m: number) { }350 + }351 ittf352 +353 :interface ClockConstructor354 :new355 param hour356 :number357 param minute358 :number359 class Clock360 :implements ClockConstructor361 p currentTime362 :ref Date363 ctor364 param h365 :number366 param m367 :number368 item369 title static and instance sides of classes - succeds370 expected371 + interface ClockConstructor {372 + new (hour: number, minute: number): ClockInterface;373 + }374 + interface ClockInterface {375 + tick();376 + }377 + // Because createClock’s first parameter is of type ClockConstructor, in createClock(AnalogClock, 7, 32),378 + // it checks that AnalogClock has the correct constructor signature.379 + function createClock(ctor: ClockConstructor, hour: number, minute: number): ClockInterface {380 + return new ctor(hour, minute);381 + }382 + class DigitalClock implements ClockInterface {383 + constructor(h: number, m: number) {}384 + tick() {385 + console.log("beep beep");386 + }387 + }388 + class AnalogClock implements ClockInterface {389 + constructor(h: number, m: number) { }390 + tick() {391 + console.log("tick tock");392 + }393 + }394 + let digital = createClock(DigitalClock, 12, 17);395 + let analog = createClock(AnalogClock, 7, 32);396 ittf397 +398 :interface ClockConstructor399 :new400 :ref ClockInterface401 param hour402 :number403 param minute404 :number405 :interface ClockInterface406 :m tick407 function createClock408 param ctor409 :ref ClockConstructor410 param hour411 :number412 param minute413 :number414 :return415 :ref ClockInterface416 return new ctor(hour, minute)417 class DigitalClock418 :implements ClockInterface419 ctor420 param h421 :number422 param m423 :number424 m tick425 _ console.log("beep beep")426 class AnalogClock427 :implements ClockInterface428 ctor429 param h430 :number431 param m432 :number433 m tick434 _ console.log("tick tock")435 let digital = createClock(DigitalClock, 12, 17)436 let analog = createClock(AnalogClock, 7, 32)437 item438 title Extending Interfaces 1439 expected440 + interface Shape {441 + color: string;442 + }443 + interface Square extends Shape {444 + sideLength: number;445 + }446 + let square = {} as Square;447 + square.color = "blue";448 + square.sideLength = 10;449 ittf450 +451 :interface Shape452 :p color453 :string454 :interface Square455 :extends Shape456 :p sideLength457 :number458 let square459 {460 :as461 :ref Square462 set square.color = "blue"463 set square.sideLength = 10464 item465 title Extending Interfaces 2466 expected467 + interface Shape {468 + color: string;469 + }470 + interface PenStroke {471 + penWidth: number;472 + }473 + interface Square extends Shape, PenStroke {474 + sideLength: number;475 + }476 + let square = {} as Square;477 + square.color = "blue";478 + square.sideLength = 10;479 + square.penWidth = 5.0;480 ittf481 +482 :interface Shape483 :p color484 :string485 :interface PenStroke486 :p penWidth487 :number488 :interface Square489 :extends Shape490 :extends PenStroke491 :p sideLength492 :number493 let square494 {495 :as496 :ref Square497 set square.color = "blue"498 set square.sideLength = 10499 set square.penWidth = 5500 item501 title Hybrid Types502 expected503 + interface Counter {504 + (start: number): string;505 + interval: number;506 + reset(): void;507 + }508 + function getCounter(): Counter {509 + let counter = function (start: number) { } as Counter;510 + counter.interval = 123;511 + counter.reset = function () { };512 + return counter;513 + }514 ittf515 +516 :interface Counter517 :call518 :string519 param start520 :number521 :p interval522 :number523 :m reset524 :void525 function getCounter526 :return527 :ref Counter528 let counter529 :as530 :ref Counter531 function532 param start533 :number534 set counter.interval = 123535 set counter.reset =536 function537 return counter538 let c = getCounter()539 _ c(10)540 _ c.reset541 set c.interval = 5542 item543 title Class with private property544 expected545 + class Control {546 + private state: any;547 + }548 ittf549 class Control550 p state551 :private552 :any553 item554 title Interface extending class555 expected556 + interface SelectableControl extends Control {557 + select(): void;558 + }559 ittf560 :interface SelectableControl561 :extends Control562 :m select563 :void564 item565 title Derived class extending interface566 expected567 + class Button extends Control implements SelectableControl {568 + select() {}569 + }570 ittf571 class Button572 super Control573 :implements SelectableControl574 m select575 item576 title Derived class577 expected578 + class TextBox extends Control {579 + select() {}580 + }581 ittf582 class TextBox583 super Control584 m select585 item586 title Class extending interface587 expected588 + // Error: Property 'state' is missing in type 'Image'.589 + class Image implements SelectableControl {590 + select() {}591 + }592 ittf593 class Image594 :implements SelectableControl595 m select
/ittf/models/cheatsheets/ts/t/generics.ittf.ittf
1 element generics2 tag3 ast4 category5 item6 title Identity function with any7 expected8 + function identity(arg: any): any {9 + return arg;10 + }11 ittf12 function identity13 param arg14 :any15 :return16 :any17 return arg18 item19 title Identity function with type variable20 expected21 + function identity<T>(arg: T): T {22 + return arg;23 + }24 ittf25 function identity26 :< T27 param arg28 :ref T29 :return30 :ref T31 return arg32 item33 title Type argument34 expected35 + let output = identity<string>("myString"); // type of output will be 'string'36 ittf37 let output38 _ identity39 :< string40 @ "myString"41 item42 title Length property fails43 expected44 + function loggingIdentity<T>(arg: T): T {45 + console.log(arg.length);46 + return arg;47 + }48 ittf49 function loggingIdentity50 :< T51 param arg52 :ref T53 :return54 :ref T55 _ console.log(arg.length)56 return arg57 item58 title Length property succeds 159 expected60 + function loggingIdentity<T>(arg: T[]): T[] {61 + console.log(arg.length);62 + return arg;63 + }64 ittf65 +66 function loggingIdentity67 :< T68 param arg69 :[70 :ref T71 :return72 :[73 :ref T74 _ console.log(arg.length)75 return arg76 item77 title Length property succeds 278 expected79 + function loggingIdentity<T>(arg: Array<T>): Array<T> {80 + console.log(arg.length);81 + return arg;82 + }83 ittf84 function loggingIdentity85 :< T86 param arg87 :ref Array88 :ref T89 :return90 :ref Array91 :ref T92 _ console.log(arg.length)93 return arg94 item95 title Generic function96 expected97 + function identity<T>(arg: T): T {98 + return arg;99 + }100 + let myIdentity: <T>(arg: T) => T = identity;101 ittf102 +103 function identity104 :< T105 param arg106 :ref T107 :return108 :ref T109 return arg110 let myIdentity111 :=>112 :ref T113 param arg114 :ref T115 := identity116 item117 title Call signature object literal type118 expected119 + function identity<T>(arg: T): T {120 + return arg;121 + }122 + let myIdentity: { <T>(arg: T): T } = identity;123 ittf124 +125 function identity126 :< T127 param arg128 :ref T129 :return130 :ref T131 return arg132 let myIdentity133 :{134 :call135 :< T136 :ref T137 param arg138 :ref T139 := identity140 item141 title Generic interface142 expected143 + interface GenericIdentityFn<T> {144 + (arg: T): T;145 + }146 + function identity<T>(arg: T): T {147 + return arg;148 + }149 + let myIdentity: GenericIdentityFn<number> = identity;150 ittf151 +152 :interface GenericIdentityFn153 :< T154 :call155 :ref T156 param arg157 :ref T158 function identity159 :< T160 param arg161 :ref T162 :return163 :ref T164 return arg165 let myIdentity166 :ref GenericIdentityFn167 :param number168 := identity169 item170 title Generic Classes171 expected172 + class GenericNumber<T> {173 + zeroValue: T;174 + add: (x: T, y: T) => T;175 + }176 ittf177 class GenericNumber178 :< T179 p zeroValue180 :ref T181 p add182 :=>183 :ref T184 param x185 :ref T186 param y187 :ref T188 item189 title Generic Constraints - fails190 expected191 + function loggingIdentity<T>(arg: T): T {192 + console.log(arg.length); // Error: T doesn't have .length193 + return arg;194 + }195 ittf196 function loggingIdentity197 :< T198 param arg199 :ref T200 :return201 :ref T202 _ console.log(arg.length)203 return arg204 item205 title Generic Constraints - succeds206 expected207 + interface Lengthwise {208 + length: number;209 + }210 + function loggingIdentity<T extends Lengthwise>(arg: T): T {211 + console.log(arg.length); // Now we know it has a .length property, so no more error212 + return arg;213 + }214 ittf215 +216 :interface Lengthwise217 :p length218 :number219 function loggingIdentity220 :< T221 :ref Lengthwise222 param arg223 :ref T224 :return225 :ref T226 _ console.log(arg.length)227 return arg228 item229 title Type Parameters in Generic Constraints230 expected231 + function getProperty<T, K extends keyof T>(obj: T, key: K) {232 + return obj[key];233 + }234 + let x = { a: 1, b: 2, c: 3, d: 4 };235 + getProperty(x, "a");236 + getProperty(x, "m");237 ittf238 +239 function getProperty240 :< T241 :< K242 :keyof243 :ref T244 param obj245 :ref T246 param key247 :ref K248 return obj[key]249 let x250 {251 @ a 1252 @ b 2253 @ c 3254 @ d 4255 _ getProperty(x, "a")256 _ getProperty(x, "m")257 item258 title Class Types in Generics259 expected260 + function create<T>(c: { new (): T; }): T {261 + return new c();262 + }263 ittf264 function create265 :< T266 param c267 :{268 :new269 :ref T270 :return271 :ref T272 return new c()273 item274 title Prototype property275 expected276 + class BeeKeeper {277 + hasMask: boolean;278 + }279 + class ZooKeeper {280 + nametag: string;281 + }282 + class Animal {283 + numLegs: number;284 + }285 + class Bee extends Animal {286 + keeper: BeeKeeper;287 + }288 + class Lion extends Animal {289 + keeper: ZooKeeper;290 + }291 + function createInstance<A extends Animal>(c: new () => A): A {292 + return new c();293 + }294 + var x = createInstance(Lion).keeper.nametag;295 + var y = createInstance(Bee).keeper.hasMask;296 ittf297 +298 class BeeKeeper299 p hasMask300 :boolean301 class ZooKeeper302 p nametag303 :string304 class Animal305 p numLegs306 :number307 class Bee308 super Animal309 p keeper310 :ref BeeKeeper311 class Lion312 super Animal313 p keeper314 :ref ZooKeeper315 function createInstance316 :< A317 :ref Animal318 param c319 :ctor320 :ref A321 :return322 :ref A323 return new c()324 var x = createInstance(Lion).keeper.nametag325 var y = createInstance(Bee).keeper.hasMask
/ittf/models/cheatsheets/ts/t/advanced.ittf.ittf
1 element advanced2 tag3 ast4 category5 item6 title Intersection Types7 expected8 + function extend<T, U>(first: T, second: U): T & U {9 + let result = {} as T & U;10 + for (let id in first) {11 + (result as any)[id] = (first as any)[id];12 + }13 + for (let id in second) {14 + if (!result.hasOwnProperty(id)) {15 + (result as any)[id] = (second as any)[id];16 + }17 + }18 + return result;19 + }20 + class Person {21 + constructor(public name: string) {}22 + }23 + interface Loggable {24 + log(): void;25 + }26 + class ConsoleLogger implements Loggable {27 + log() {28 + // ...29 + }30 + }31 + var jim = extend(new Person("Jim"), new ConsoleLogger());32 + var n = jim.name;33 + jim.log();34 ittf35 +36 function extend37 :< T38 :< U39 param first40 :ref T41 param second42 :ref U43 :return44 :intersect45 :ref T46 :ref U47 let result48 :as49 :intersect50 :ref T51 :ref U52 { {}53 for let id in first54 set =55 @expr56 ()57 @id result58 :as59 :any60 .[ id61 @expr62 ()63 @id first64 :as65 :any66 .[ id67 for let id in second68 if !result.hasOwnProperty(id)69 set =70 @expr71 ()72 @id result73 :as74 :any75 .[ id76 @expr77 ()78 @id second79 :as80 :any81 .[ id82 return result83 class Person84 ctor85 param name86 :string87 :interface Loggable88 :m log89 :void90 class ConsoleLogger91 :extends Loggable92 m log93 var jim = extend(new Person("Jim"), new ConsoleLogger())94 var n = jim.name95 _ jim.log96 item97 title Union Types - fail at run time98 expected99 + function padLeft(value: string, padding: any) {100 + if (typeof padding === "number") {101 + return Array(padding + 1).join(" ") + value;102 + }103 + if (typeof padding === "string") {104 + return padding + value;105 + }106 + throw new Error(`Expected string or number, got '${padding}'.`);107 + }108 + padLeft("Hello world", 4); // returns " Hello world"109 + let indentedString = padLeft("Hello world", true); // passes at compile time, fails at runtime.110 ittf111 +112 function padLeft113 param value114 :string115 param padding116 :any117 if typeof padding === "number"118 return Array(padding + 1).join(" ") + value119 if typeof padding === "string"120 return padding + value121 throw122 new Error123 template124 + Expected string or number, got '125 @ padding126 + '.127 _ padLeft("Hello world", 4)128 let indentedString = padLeft("Hello world", true)129 item130 title Union Types - succeds at run time131 expected132 + function padLeft(value: string, padding: string | number) {133 + // ...134 + }135 + let indentedString = padLeft("Hello world", true); // errors during compilation136 ittf137 +138 function padLeft139 param value140 :string141 param padding142 :union143 :string144 :number145 let indentedString = padLeft("Hello world", true)146 item147 title Union Types - common members148 expected149 + // If we have a value that has a union type, we can only access members that are common to all types in the union.150 + interface Bird {151 + fly();152 + layEggs();153 + }154 + interface Fish {155 + swim();156 + layEggs();157 + }158 + function getSmallPet(): Fish | Bird {159 + // ...160 + }161 ittf162 +163 :interface Bird164 :m fly165 :m layEggs166 :interface Fish167 :m swim168 :m layEggs169 function getSmallPet170 :return171 :union172 :ref Fish173 :ref Bird174 let pet = getSmallPet()175 _ pet.layEggs176 _ pet.swim177 item178 title Type Guards and Differentiating Types179 expected180 + let pet = getSmallPet();181 + if ((pet as Fish).swim) {182 + (pet as Fish).swim();183 + } else {184 + (pet as Bird).fly();185 + }186 ittf187 +188 let pet = getSmallPet()189 if190 test191 @expr192 ()193 @id pet194 :as195 :ref Fish196 . swim197 _198 ()199 @id pet200 :as201 :ref Fish202 ._ swim203 else204 _205 ()206 @id pet207 :as208 :ref Bird209 ._ fly210 item211 title User - Defined Type Guards212 expected213 + function isFish(pet: Fish | Bird): pet is Fish {214 + return (pet as Fish).swim !== undefined;215 + }216 + function isNumber(x: any): x is number {217 + return typeof x === "number";218 + }219 + function isString(x: any): x is string {220 + return typeof x === "string";221 + }222 + function padLeft(value: string, padding: string | number) {223 + if (isNumber(padding)) {224 + return Array(padding + 1).join(" ") + value;225 + }226 + if (isString(padding)) {227 + return padding + value;228 + }229 + throw new Error(`Expected string or number, got '${padding}'.`);230 + }231 ittf232 +233 function isFish234 param pet235 :union236 :ref Fish237 :ref Bird238 :return239 :predicate pet240 :ref Fish241 return242 !==243 @expr244 ()245 @id pet246 :as247 :ref Fish248 . swim249 + undefined250 function isNumber251 param x252 :any253 :return254 :predicate x255 :number256 return typeof x === "number"257 function isString258 param x259 :any260 :return261 :predicate x262 :string263 return typeof x === "string"264 function padLeft265 param value266 :string267 param padding268 :union269 :string270 :number271 if isNumber(padding)272 return Array(padding + 1).join(" ") + value273 if isString(padding)274 return padding + value275 throw276 new Error277 template278 + Expected string or number, got '279 @ padding280 + '.281 item282 title Instanceof type guards283 expected284 + interface Padder {285 + getPaddingString(): string286 + }287 + class SpaceRepeatingPadder implements Padder {288 + constructor(private numSpaces: number) {}289 + getPaddingString() {290 + return Array(this.numSpaces + 1).join(" ");291 + }292 + }293 + class StringPadder implements Padder {294 + constructor(private value: string) { }295 + getPaddingString() {296 + return this.value;297 + }298 + }299 + function getRandomPadder() {300 + return Math.random() < 0.5 ?301 + new SpaceRepeatingPadder(4) :302 + new StringPadder(" ");303 + }304 + // Type is 'SpaceRepeatingPadder | StringPadder'305 + let padder: Padder = getRandomPadder();306 + if (padder instanceof SpaceRepeatingPadder) {307 + var x = padder; // type narrowed to 'SpaceRepeatingPadder'308 + }309 + if (padder instanceof StringPadder) {310 + var x = padder; // type narrowed to 'StringPadder'311 + }312 ittf313 +314 :interface Padder315 :m getPaddingString316 :string317 class SpaceRepeatingPadder318 :extends Padder319 ctor320 param numSpaces321 :private322 :number323 m getPaddingString324 return Array(this.numSpaces + 1).join(" ")325 class StringPadder326 :extends Padder327 ctor328 param value329 :private330 :string331 m getPaddingString332 return this.value333 function getRandomPadder334 return335 iif Math.random() < 0.5336 then new SpaceRepeatingPadder(4)337 else new StringPadder(" ")338 # Type is 'SpaceRepeatingPadder | StringPadder'339 let padder340 :ref Padder341 _ getRandomPadder342 if padder instanceof SpaceRepeatingPadder343 var x = padder344 # type narrowed to 'SpaceRepeatingPadder'345 if padder instanceof StringPadder346 var x = padder347 # type narrowed to 'StringPadder'348 item349 title Nullable types350 expected351 + let s = "foo";352 + s = null; // error, 'null' is not assignable to 'string'353 + let sn: string | null = "bar";354 + sn = null; // ok355 + sn = undefined; // error, 'undefined' is not assignable to 'string | null'356 + // Note that TypeScript treats null and undefined differently in order to match JavaScript semantics.357 + // string | null is a different type than string | undefined and string | undefined | null.358 + /*359 + Optional parameters and properties360 + With --strictNullChecks, an optional parameter automatically adds | undefined:361 + */362 + function f(x: number, y?: number) {363 + return x + (y || 0);364 + }365 + f(1, 2);366 + f(1);367 + f(1, undefined);368 + f(1, null); // error, 'null' is not assignable to 'number | undefined'369 + // The same is true for optional properties:370 + class C {371 + a: number;372 + b?: number;373 + }374 + let c = new C();375 + c.a = 12;376 + c.a = undefined; // error, 'undefined' is not assignable to 'number'377 + c.b = 13;378 + c.b = undefined; // ok379 + c.b = null; // error, 'null' is not assignable to 'number | undefined'380 ittf381 +382 let s = "foo"383 set s = null384 let sn385 :union386 :string387 :null388 := "bar"389 set sn = null390 set sn = undefined391 function f392 param x393 :number394 param395 :number396 :optional397 return x + y || 0398 _ f(1, 2)399 _ f(1)400 _ f(1, undefined)401 _ f(1, null)402 class C403 p a404 :number405 p b406 :number407 let c = new C()408 set c.a = 12409 set c.a = undefined410 set c.b = 13411 set c.b = undefined412 set c.b = null413 item414 title Type guards and type assertions415 expected416 + function f(sn: string | null): string {417 + if (sn == null) {418 + return "default";419 + } else {420 + return sn;421 + }422 + }423 + // The null elimination is pretty obvious here, but you can use terser operators too:424 + function f(sn: string | null): string {425 + return sn || "default";426 + }427 + // In cases where the compiler can’t eliminate null or undefined,428 + // you can use the type assertion operator to manually remove them.429 + // The syntax is postfix !: identifier! removes null and undefined from the type of identifier:430 + function broken(name: string | null): string {431 + function postfix(epithet: string) {432 + return name.charAt(0) + '. the ' + epithet; // error, 'name' is possibly null433 + }434 + name = name || "Bob";435 + return postfix("great");436 + }437 + function fixed(name: string | null): string {438 + function postfix(epithet: string) {439 + return name!.charAt(0) + '. the ' + epithet; // ok440 + }441 + name = name || "Bob";442 + return postfix("great");443 + }444 ittf445 +446 function f447 param sn448 :union449 :string450 :null451 :return452 :string453 if sn == null454 return "default"455 else456 return sn457 function f458 param sn459 :union460 :string461 :null462 :return463 :string464 return sn || "default"465 function broken466 param name467 :union468 :string469 :null470 :return471 :string472 function postfix473 param epithet474 :string475 return name.charAt(0) + '. the ' + epithet476 set name = name || "Bob"477 return postfix("great")478 function fixed479 param name480 :union481 :string482 :null483 :return484 :string485 function postfix486 param epithet487 :string488 return489 op+490 op+491 _492 ._ charAt493 @ 0494 + '. the '495 + epithet496 set name = name || "Bob"497 return postfix("great")498 item499 title Type Aliases500 expected501 + type Name = string;502 + type NameResolver = () => string;503 + type NameOrResolver = Name | NameResolver;504 + function getName(n: NameOrResolver): Name {505 + if (typeof n === "string") {506 + return n;507 + } else {508 + return n();509 + }510 + }511 + // Aliasing doesn’t actually create a new type - it creates a new name to refer to that type.512 + // Aliasing a primitive is not terribly useful, though it can be used as a form of documentation.513 + // Just like interfaces, type aliases can also be generic - we can just add type parameters and use them on the right side of the alias declaration:514 + type Container<T> = { value: T };515 + // We can also have a type alias refer to itself in a property:516 + type Tree<T> = {517 + value: T;518 + left: Tree<T>;519 + right: Tree<T>;520 + }521 + // Together with intersection types, we can make some pretty mind-bending types:522 + type LinkedList<T> = T & { next: LinkedList<T> };523 + interface Person {524 + name: string;525 + }526 + var people: LinkedList<Person>;527 + var s = people.name;528 + var s = people.next.name;529 + var s = people.next.next.name;530 + var s = people.next.next.next.name;531 + // However, it’s not possible for a type alias to appear anywhere else on the right side of the declaration:532 + type Yikes = Array<Yikes>; // error533 ittf534 +535 :type Name536 :string537 :type NameResolver538 :=>539 :string540 :type NameOrResolver541 :union542 :ref Name543 :ref NameResolver544 function getName545 param n546 :ref NameOrResolver547 :return548 :ref Name549 if typeof n === "string"550 return n551 else552 return n()553 :type Container554 :< T555 :{556 :p value557 :ref T558 :type Tree559 :< T560 :{561 :p value562 :ref T563 :p left564 :ref Tree565 :ref T566 :p right567 :ref Tree568 :ref T569 :type LinkedList570 :< T571 :intersect572 :ref T573 :{574 :p next575 :ref LinkedList576 :ref T577 :interface Person578 :p name579 :string580 var people581 :ref LinkedList582 :ref Person583 var s = people.name584 var s = people.next.name585 var s = people.next.next.name586 var s = people.next.next.next.name587 :type Yikes588 :ref Array589 :ref Yikes590 item591 title Interfaces vs.Type Aliases592 expected593 +594 ittf595 +596 :type Alias597 :{598 :p num599 :number600 :interface Interface601 :p num602 :number603 :function aliased604 param arg605 :ref Alias606 :return607 :ref Alias608 :function interfaced609 param arg610 :ref Interface611 :return612 :ref Interface613 item614 title String Literal Types615 expected616 + type Easing = "ease-in" | "ease-out" | "ease-in-out";617 + class UIElement {618 + animate(dx: number, dy: number, easing: Easing) {619 + if (easing === "ease-in") {620 + } else if (easing === "ease-out") {621 + } else if (easing === "ease-in-out") {622 + } else {623 + // error! should not pass null or undefined.624 + }625 + }626 + }627 + let button = new UIElement();628 + button.animate(0, 0, "ease-in");629 + button.animate(0, 0, "uneasy"); // error: "uneasy" is not allowed here630 + // You can pass any of the three allowed strings, but any other string will give the error631 + // Argument of type '"uneasy"' is not assignable to parameter of type '"ease-in" | "ease-out" | "ease-in-out"'632 + // String literal types can be used in the same way to distinguish overloads:633 + function createElement(tagName: "img"): HTMLImageElement;634 + function createElement(tagName: "input"): HTMLInputElement;635 + // ... more overloads ...636 + function createElement(tagName: string): Element {637 + // ... code goes here ...638 + }639 ittf640 +641 :type Easing642 :union643 :literal "ease-in"644 :literal "ease-out"645 :literal "ease-in-out"646 class UIElement647 m animate648 param dx649 :number650 param dy651 :number652 param easing653 :ref Easing654 if easing === "ease-in"655 else656 if easing === "ease-out"657 else658 if easing === "ease-in-out"659 else660 let button = new UIElement()661 _ button.animate(0, 0, "ease-in")662 _ button.animate(0, 0, "uneasy")663 :function createElement664 param tagName665 :literal "img"666 :return667 :ref HTMLImageElement668 :function createElement669 param tagName670 :literal "input"671 :return672 :ref HTMLInputElement673 function createElement674 param tagName675 :string676 :return677 :ref Element678 item679 title Numeric Literal Types680 expected681 + function rollDie(): 1 | 2 | 3 | 4 | 5 | 6 {682 + }683 + // These are seldom written explicitly, they can be useful when narrowing can catch bugs:684 + function foo(x: number) {685 + if (x !== 1 || x !== 2) {686 + // Operator '!==' cannot be applied to types '1' and '2'.687 + }688 + }689 + // In other words, x must be 1 when it gets compared to 2, meaning that the above check is making an invalid comparison.690 ittf691 +692 function rollDie693 :return694 :union695 :literal 1696 :literal 2697 :literal 3698 :literal 4699 :literal 5700 :literal 6701 function foo702 param x703 :number704 if x !== 1 || x !== 2705 item706 title Enum Member Types707 expected708 + interface Square {709 + kind: "square";710 + size: number;711 + }712 + interface Rectangle {713 + kind: "rectangle";714 + width: number;715 + height: number;716 + }717 + interface Circle {718 + kind: "circle";719 + radius: number;720 + }721 + // First we declare the interfaces we will union. Each interface has a kind property with722 + // a different string literal type.The kind property is called the discriminant or tag.The other properties are specific to each interface.Notice that the interfaces are currently unrelated.Let’s put them into a union:723 + type Shape = Square | Rectangle | Circle;724 + // Now let’s use the discriminated union:725 + function area(s: Shape) {726 + switch (s.kind) {727 + case "square": return s.size * s.size;728 + case "rectangle": return s.height * s.width;729 + case "circle": return Math.PI * s.radius ** 2;730 + }731 + }732 ittf733 +734 :interface Square735 :p kind736 :literal "square"737 :p size738 :number739 :interface Rectangle740 :p kind741 :literal "rectangle"742 :p width743 :number744 :p height745 :number746 :interface Circle747 :p kind748 :literal "circle"749 :p radius750 :number751 :type Shape752 :union753 :ref Square754 :ref Rectangle755 :ref Circle756 function area757 param s758 :ref Shape759 switch s.kind760 case "square"761 return s.size * s.size762 case "rectangle"763 return s.height * s.width764 case "circle"765 return Math.PI * s.radius ** 2766 item767 title Exhaustiveness checking768 expected769 + type Shape = Square | Rectangle | Circle | Triangle;770 + function area(s: Shape) {771 + switch (s.kind) {772 + case "square": return s.size * s.size;773 + case "rectangle": return s.height * s.width;774 + case "circle": return Math.PI * s.radius ** 2;775 + }776 + // should error here - we didn't handle case "triangle"777 + }778 + // There are two ways to do this. The first is to turn on --strictNullChecks and specify a return type:779 + function area(s: Shape): number { // error: returns number | undefined780 + switch (s.kind) {781 + case "square": return s.size * s.size;782 + case "rectangle": return s.height * s.width;783 + case "circle": return Math.PI * s.radius ** 2;784 + }785 + }786 + // Because the switch is no longer exhaustive, TypeScript is aware that the function could sometimes787 + // return undefined.If you have an explicit return type number, then you will get an error that788 + // the return type is actually number | undefined.However, this method is quite subtle and, besides, --strictNullChecks does not always work with old code.789 + // The second method uses the never type that the compiler uses to check for exhaustiveness:790 + function assertNever(x: never): never {791 + throw new Error("Unexpected object: " + x);792 + }793 + function area(s: Shape) {794 + switch (s.kind) {795 + case "square": return s.size * s.size;796 + case "rectangle": return s.height * s.width;797 + case "circle": return Math.PI * s.radius ** 2;798 + default: return assertNever(s); // error here if there are missing cases799 + }800 + }801 ittf802 +803 :type Shape804 :union805 :ref Square806 :ref Rectangle807 :ref Circle808 :ref Triangle809 function area810 param s811 :ref Shape812 switch s.kind813 case "square"814 return s.size * s.size815 case "rectangle"816 return s.height * s.width817 case "circle"818 return Math.PI * s.radius ** 2819 function area820 param s821 :ref Shape822 :return823 :number824 switch s.kind825 case "square"826 return s.size * s.size827 case "rectangle"828 return s.height * s.width829 case "circle"830 return Math.PI * s.radius ** 2831 function assertNever832 param x833 :never834 :return835 :never836 throw new Error("Unexpected object: " + x)837 function area838 param s839 :ref Shape840 switch s.kind841 case "square"842 return s.size * s.size843 case "rectangle"844 return s.height * s.width845 case "circle"846 return Math.PI * s.radius ** 2847 default848 return assertNever(s)849 item850 title Polymorphic this types851 expected852 + class BasicCalculator {853 + public constructor(protected value: number = 0) { }854 + public currentValue(): number {855 + return this.value;856 + }857 + public add(operand: number): this {858 + this.value += operand;859 + return this;860 + }861 + public multiply(operand: number): this {862 + this.value *= operand;863 + return this;864 + }865 + // ... other operations go here ...866 + }867 + let v = new BasicCalculator(2)868 + .multiply(5)869 + .add(1)870 + .currentValue();871 + // Since the class uses this types, you can extend it and the new class can use the old methods with no changes.872 + class ScientificCalculator extends BasicCalculator {873 + public constructor(value = 0) {874 + super(value);875 + }876 + public sin() {877 + this.value = Math.sin(this.value);878 + return this;879 + }880 + // ... other operations go here ...881 + }882 + let v = new ScientificCalculator(2)883 + .multiply(5)884 + .sin()885 + .add(1)886 + .currentValue();887 + // Without this types, ScientificCalculator would not have been able to extend BasicCalculator and keep the fluent interface. multiply would have returned BasicCalculator, which doesn’t have the sin method. However, with this types, multiply returns this, which is ScientificCalculator here.888 ittf889 +890 class BasicCalculator891 ctor892 :public893 param value894 :number895 := 0896 m currentValue897 :public898 return this.value899 m add900 :public901 param operand902 :number903 set this.value += operand904 return this905 m multiply906 :public907 param operand908 :number909 set this.value *= operand910 return this911 let v = new BasicCalculator(2).multiply(5).add(1).currentValue()912 class ScientificCalculator913 super BasicCalculator914 ctor915 :public916 param value = 0917 _ super(value)918 m sin919 :public920 set this.value = Math.sin(this.value)921 return this922 let v = new ScientificCalculator(2).multiply(5).sin().add(1).currentValue()923 item924 title Index types925 expected926 + function pluck(o, names) {927 + return names.map(n => o[n]);928 + }929 + // Here’s how you would write and use this function in TypeScript, using the index type query and indexed access operators:930 + function pluck<T, K extends keyof T>(o: T, names: K[]): T[K][] {931 + return names.map(n => o[n]);932 + }933 + interface Person {934 + name: string;935 + age: number;936 + }937 + let person: Person = {938 + name: 'Jarid',939 + age: 35940 + };941 + let strings: string[] = pluck(person, ['name']); // ok, string[]942 + // The compiler checks that name is actually a property on Person. The example introduces a couple of new type operators.943 + // First is keyof T, the index type query operator.For any type T, keyof T is the union of known, public property names of T.For example:944 + let personProps: keyof Person; // 'name' | 'age'945 + // keyof Person is completely interchangeable with 'name' | 'age'. The difference is that if you add another property to Person,946 + // say address: string, then keyof Person will automatically update to be 'name' | 'age' | 'address'.And you can use keyof in generic947 + // contexts like pluck, where you can’t possibly know the property names ahead of time.That means the compiler will check that you pass948 + // the right set of property names to pluck:949 + pluck(person, ['age', 'unknown']); // error, 'unknown' is not in 'name' | 'age'950 + // The second operator is T[K], the indexed access operator. Here, the type syntax reflects the expression syntax.951 + // That means that person['name'] has the type Person['name']— which in our example is just string.However, just like index type queries,952 + // you can use T[K] in a generic context, which is where its real power comes to life.You just have to make sure that the type variable K extends keyof T.953 + // Here’s another example with a function named getProperty.954 + function getProperty<T, K extends keyof T>(o: T, name: K): T[K] {955 + return o[name]; // o[name] is of type T[K]956 + }957 + // In getProperty, o: T and name: K, so that means o[name]: T[K]. Once you return the T[K] result, the compiler will instantiate the actual type of the key,958 + // so the return type of getProperty will vary according to which property you request.959 + let name: string = getProperty(person, 'name');960 + let age: number = getProperty(person, 'age');961 + let unknown = getProperty(person, 'unknown'); // error, 'unknown' is not in 'name' | 'age'962 + // Index types and string index signatures963 + // keyof and T[K] interact with string index signatures. If you have a type with a string index signature, keyof T will just be string.964 + // And T[string] is just the type of the index signature:965 + interface Map<T> {966 + [key: string]: T;967 + }968 + let keys: keyof Map<number>; // string969 + let value: Map<number>['foo']; // number970 ittf971 +972 function pluck973 param o974 param names975 return976 _ names.map977 =>978 param n979 + o[n]980 function pluck981 :< T982 :< K983 :keyof984 :ref T985 param o986 :ref T987 param names988 :[989 :ref K990 :return991 :[992 :[]993 :ref T994 :ref K995 return996 _ names.map997 =>998 param n999 + o[n]1000 :interface Person1001 :p name1002 :string1003 :p age1004 :number1005 let person1006 :ref Person1007 {1008 @ name 'Jarid'1009 @ age 351010 let strings1011 :[1012 :string1013 _ pluck1014 @ person1015 [1016 @ 'name'1017 let personProps1018 :keyof1019 :ref Person1020 _ pluck1021 @ person1022 [1023 @ 'age'1024 @ 'unknown'1025 function getProperty1026 :< T1027 :< K1028 :keyof1029 :ref T1030 param o1031 :ref T1032 param name1033 :ref K1034 :return1035 :[]1036 :ref T1037 :ref K1038 return o[name]1039 let name1040 :string1041 _ getProperty(person, 'name')1042 let age1043 :number1044 _ getProperty(person, 'age')1045 let unknown = getProperty(person, 'unknown')1046 :interface Map1047 :< T1048 :index1049 :ref T1050 param key1051 :string1052 let keys1053 :keyof1054 :ref Map1055 :number1056 let value1057 :[]1058 :ref Map1059 :number1060 :literal 'foo'1061 item1062 title Mapped types1063 expected1064 + interface PersonPartial {1065 + name?: string;1066 + age?: number;1067 + }1068 + // Or we might want a readonly version:1069 + interface PersonReadonly {1070 + readonly name: string;1071 + readonly age: number;1072 + }1073 + // This happens often enough in Javascript that TypeScript provides a way to create new types based on old types — mapped types.1074 + // In a mapped type, the new type transforms each property in the old type in the same way.For example, you can make all properties1075 + // of a type readonly or optional.Here are a couple of examples:1076 + type Readonly<T> = {1077 + readonly [P in keyof T]: T[P];1078 + }1079 + type Partial<T> = {1080 + [P in keyof T]?: T[P];1081 + }1082 + // And to use it:1083 + type PersonPartial = Partial<Person>;1084 + type ReadonlyPerson = Readonly<Person>;1085 + // Let’s take a look at the simplest mapped type and its parts:1086 + type Keys = 'option1' | 'option2';1087 + type Flags = {[K in Keys]: boolean };1088 + // The syntax resembles the syntax for index signatures with a for .. in inside. There are three parts:1089 ittf1090 +1091 :interface PersonPartial1092 :p name1093 :optional1094 :string1095 :p age1096 :optional1097 :number1098 :interface PersonReadonly1099 :p name1100 :string1101 :p age1102 :number1103 :type Readonly1104 :< T1105 :mapped1106 :< P1107 :keyof1108 :ref T1109 :[]1110 :ref T1111 :ref P1112 :type Partial1113 :< T1114 :mapped1115 :optional1116 :< P1117 :keyof1118 :ref T1119 :[]1120 :ref T1121 :ref P1122 :type PersonPartial1123 :ref Partial1124 :ref Person1125 :type ReadonlyPerson1126 :ref Readonly1127 :ref Person1128 :type Keys1129 :union1130 :literal 'option1'1131 :literal 'option2'1132 :type Flags1133 :mapped1134 :< K1135 :ref Keys1136 :boolean1137 item1138 title Mapped types 21139 expected1140 + /*1141 + The type variable K, which gets bound to each property in turn.1142 + The string literal union Keys, which contains the names of properties to iterate over.1143 + The resulting type of the property.1144 + In this simple example, Keys is a hard-coded list of property names and the property type is always boolean, so this mapped type is equivalent to writing: */1145 + type Flags = {1146 + option1: boolean;1147 + option2: boolean;1148 + }1149 + // Real applications, however, look like Readonly or Partial above. They’re based on some existing type, and they transform the properties1150 + // in some way. That’s where keyof and indexed access types come in:1151 + type NullablePerson = {[P in keyof Person]: Person[P] | null }1152 + type PartialPerson = {[P in keyof Person]?: Person[P]}1153 + // But it’s more useful to have a general version.1154 + type Nullable<T> = {[P in keyof T]: T[P] | null }1155 + type Partial<T> = {[P in keyof T]?: T[P]}1156 + // In these examples, the properties list is keyof T and the resulting type is some variant of T[P].1157 + // This is a good template for any general use of mapped types. That’s because this kind of transformation is homomorphic,1158 + // which means that the mapping applies only to properties of T and no others. The compiler knows that it can copy all the existing property1159 + // modifiers before adding any new ones. For example, if Person.name was readonly, Partial<Person>.name would be readonly and optional.1160 + // Here’s one more example, in which T[P] is wrapped in a Proxy<T> class:1161 + type Proxy<T> = {1162 + get(): T;1163 + set(value: T): void;1164 + }1165 + type Proxify<T> = {1166 + [P in keyof T]: Proxy<T[P]>;1167 + }1168 + function proxify<T>(o: T): Proxify<T> {1169 + // ... wrap proxies ...1170 + }1171 + let proxyProps = proxify(props);1172 + // Note that Readonly<T> and Partial<T> are so useful, they are included in TypeScript’s standard library along with Pick and Record:1173 + type Pick<T, K extends keyof T> = {1174 + [P in K]: T[P];1175 + }1176 + type Record<K extends string, T> = {1177 + [P in K]: T;1178 + }1179 + // Readonly, Partial and Pick are homomorphic whereas Record is not. One clue that Record is not homomorphic is that it doesn’t take1180 + // an input type to copy properties from:1181 + type ThreeStringProps = Record<'prop1' | 'prop2' | 'prop3', string>1182 + // Non-homomorphic types are essentially creating new properties, so they can’t copy property modifiers from anywhere.1183 ittf1184 +1185 :type Flags1186 :{1187 :p option11188 :boolean1189 :p option21190 :boolean1191 :type NullablePerson1192 :mapped1193 :< P1194 :keyof1195 :ref Person1196 :union1197 :[]1198 :ref Person1199 :ref P1200 :null1201 :type PartialPerson1202 :mapped1203 :optional1204 :< P1205 :keyof1206 :ref Person1207 :[]1208 :ref Person1209 :ref P1210 :type Nullable1211 :< T1212 :mapped1213 :< P1214 :keyof1215 :ref T1216 :union1217 :[]1218 :ref T1219 :ref P1220 :null1221 :type Partial1222 :< T1223 :mapped1224 :optional1225 :< P1226 :keyof1227 :ref T1228 :[]1229 :ref T1230 :ref P1231 :type Proxy1232 :< T1233 :{1234 :m get1235 :ref T1236 :m set1237 :void1238 param value1239 :ref T1240 :type Proxify1241 :< T1242 :mapped1243 :< P1244 :keyof1245 :ref T1246 :ref Proxy1247 :[]1248 :ref T1249 :ref P1250 function proxify1251 :< T1252 param o1253 :ref T1254 :return1255 :ref Proxify1256 :ref T1257 let proxyProps = proxify(props)1258 :type Pick1259 :< T1260 :< K1261 :keyof1262 :ref T1263 :mapped1264 :< P1265 :ref K1266 :[]1267 :ref T1268 :ref P1269 :type Record1270 :< K1271 :string1272 :< T1273 :mapped1274 :< P1275 :ref K1276 :ref T1277 :type ThreeStringProps1278 :ref Record1279 :union1280 :literal 'prop1'1281 :literal 'prop2'1282 :literal 'prop3'1283 :string1284 item1285 title Inference from mapped types1286 expected1287 + function unproxify<T>(t: Proxify<T>): T {1288 + let result = {} as T;1289 + for (const k in t) {1290 + result[k] = t[k].get();1291 + }1292 + return result;1293 + }1294 + let originalProps = unproxify(proxyProps);1295 ittf1296 +1297 function unproxify1298 :< T1299 param t1300 :ref Proxify1301 :param1302 :ref T1303 :return1304 :ref T1305 let result = {}1306 for const k in t1307 set result[k] = t[k].get()1308 return result1309 let originalProps = unproxify(proxyProps)1310 item1311 title Conditional Types1312 expected1313 + declare function f<T extends boolean>(x: T): T extends true ? string : number;1314 + // Type is 'string | number1315 + let x = f(Math.random() < 0.5)1316 + // Another example would be the TypeName type alias, which uses nested conditional types:1317 + type TypeName<T> =1318 + T extends string ? "string" :1319 + T extends number ? "number" :1320 + T extends boolean ? "boolean" :1321 + T extends undefined ? "undefined" :1322 + T extends Function ? "function" :1323 + "object";1324 + type T0 = TypeName<string>; // "string"1325 + type T1 = TypeName<"a">; // "string"1326 + type T2 = TypeName<true>; // "boolean"1327 + type T3 = TypeName<() => void>; // "function"1328 + type T4 = TypeName<string[]>; // "object"1329 + // But as an example of a place where conditonal types are deferred - where they stick around instead of picking a branch - would be in the following:1330 + interface Foo {1331 + propA: boolean;1332 + propB: boolean;1333 + }1334 + declare function f<T>(x: T): T extends Foo ? string : number;1335 + function foo<U>(x: U) {1336 + // Has type 'U extends Foo ? string : number'1337 + let a = f(x);1338 + // This assignment is allowed though!1339 + let b: string | number = a;1340 + }1341 ittf1342 +1343 :function f1344 :< T1345 :boolean1346 param x1347 :ref T1348 :return1349 :iif1350 :check1351 :ref T1352 :extends1353 :literal true1354 :then1355 :string1356 :else1357 :number1358 # Type is 'string | number1359 let x = f(Math.random() < 0.5)1360 # Another example would be the TypeName type alias, which uses nested conditional types:1361 :type TypeName1362 :< T1363 :iif1364 :check1365 :ref T1366 :extends1367 :string1368 :then1369 :literal "string"1370 :else1371 :iif1372 :check1373 :ref T1374 :extends1375 :number1376 :then1377 :literal "number"1378 :else1379 :iif1380 :check1381 :ref T1382 :extends1383 :boolean1384 :then1385 :literal "boolean"1386 :else1387 :iif1388 :check1389 :ref T1390 :extends1391 :void1392 :then1393 :literal "undefined"1394 :else1395 :iif1396 :check1397 :ref T1398 :extends1399 :ref Function1400 :then1401 :literal "function"1402 :else1403 :literal "object"1404 :type T01405 :ref TypeName1406 :param string1407 # "string"1408 :type T11409 :ref TypeName1410 :param1411 :literal "a"1412 # "string"1413 :type T21414 :ref TypeName1415 :param1416 :literal true1417 # "boolean"1418 :type T31419 :ref TypeName1420 :param1421 :=>1422 :void1423 # "function"1424 :type T41425 :ref TypeName1426 :param1427 :[1428 :string1429 # "object"1430 # But as an example of a place where conditonal types are deferred - where they stick around instead of picking a branch - would be in the following:1431 :interface Foo1432 :p propA1433 :boolean1434 :p propB1435 :boolean1436 :function f1437 :< T1438 param x1439 :ref T1440 :return1441 :iif1442 :check1443 :ref T1444 :extends1445 :ref Foo1446 :then1447 :string1448 :else1449 :number1450 function foo1451 :< U1452 param x1453 :ref U1454 # Has type 'U extends Foo ? string : number'1455 let a = f(x)1456 # This assignment is allowed though!1457 let b1458 :union1459 :string1460 :number1461 := a1462 item1463 title Distributive conditional types1464 expected1465 + type T10 = TypeName<string | (() => void)>; // "string" | "function"1466 + type T12 = TypeName<string | string[] | undefined>; // "string" | "object" | "undefined"1467 + type T11 = TypeName<string[] | number[]>; // "object"1468 + /* In instantiations of a distributive conditional type T extends U ? X : Y, references to T within the conditional type are resolved1469 + to individual constituents of the union type (i.e. T refers to the individual constituents after the conditional type is distributed1470 + over the union type). Furthermore, references to T within X have an additional type parameter constraint U (i.e. T is considered1471 + assignable to U within X).*/1472 + // Example1473 + type BoxedValue<T> = { value: T };1474 + type BoxedArray<T> = { array: T[] };1475 + type Boxed<T> = T extends any[] ? BoxedArray<T[number]> : BoxedValue<T>;1476 + type T20 = Boxed<string>; // BoxedValue<string>;1477 + type T21 = Boxed<number[]>; // BoxedArray<number>;1478 + type T22 = Boxed<string | number[]>; // BoxedValue<string> | BoxedArray<number>;1479 + // Notice that T has the additional constraint any[] within the true branch of Boxed<T> and it is therefore possible to refer to the element type of the array as T[number]. Also, notice how the conditional type is distributed over the union type in the last example.1480 + // The distributive property of conditional types can conveniently be used to filter union types:1481 + type Diff<T, U> = T extends U ? never : T; // Remove types from T that are assignable to U1482 + type Filter<T, U> = T extends U ? T : never; // Remove types from T that are not assignable to U1483 + type T30 = Diff<"a" | "b" | "c" | "d", "a" | "c" | "f">; // "b" | "d"1484 + type T31 = Filter<"a" | "b" | "c" | "d", "a" | "c" | "f">; // "a" | "c"1485 + type T32 = Diff<string | number | (() => void), Function>; // string | number1486 + type T33 = Filter<string | number | (() => void), Function>; // () => void1487 + type NonNullable<T> = Diff<T, null | undefined>; // Remove null and undefined from T1488 + type T34 = NonNullable<string | number | undefined>; // string | number1489 + type T35 = NonNullable<string | string[] | null | undefined>; // string | string[]1490 + function f1<T>(x: T, y: NonNullable<T>) {1491 + x = y; // Ok1492 + y = x; // Error1493 + }1494 + function f2<T extends string | undefined>(x: T, y: NonNullable<T>) {1495 + x = y; // Ok1496 + y = x; // Error1497 + let s1: string = x; // Error1498 + let s2: string = y; // Ok1499 + }1500 ittf1501 +1502 :type T101503 :ref TypeName1504 :param1505 :union1506 :string1507 :paren1508 :=>1509 :void1510 :type T121511 :ref TypeName1512 :param1513 :union1514 :string1515 :[1516 :string1517 :void1518 :type T111519 :ref TypeName1520 :param1521 :union1522 :[1523 :string1524 :[1525 :number1526 #1527 # In instantiations of a distributive conditional type T extends U ? X : Y, references to T within the conditional type are resolved1528 # to individual constituents of the union type (i.e. T refers to the individual constituents after the conditional type is distributed1529 # over the union type). Furthermore, references to T within X have an additional type parameter constraint U (i.e. T is considered1530 # assignable to U within X).1531 :type BoxedValue1532 :< T1533 :{1534 :p value1535 :ref T1536 :type BoxedArray1537 :< T1538 :{1539 :p array1540 :[1541 :ref T1542 :type Boxed1543 :< T1544 :iif1545 :check1546 :ref T1547 :extends1548 :[1549 :any1550 :then1551 :ref BoxedArray1552 :param1553 :[]1554 :ref T1555 :number1556 :else1557 :ref BoxedValue1558 :param1559 :ref T1560 :type T201561 :ref Boxed1562 :param string1563 :type T211564 :ref Boxed1565 :param1566 :[1567 :number1568 :type T221569 :ref Boxed1570 :param1571 :union1572 :string1573 :[1574 :number1575 :type Diff1576 :< T1577 :< U1578 :iif1579 :check1580 :ref T1581 :extends1582 :ref U1583 :then1584 :never1585 :else1586 :ref T1587 :type Filter1588 :< T1589 :< U1590 :iif1591 :check1592 :ref T1593 :extends1594 :ref U1595 :then1596 :ref T1597 :else1598 :never1599 :type T301600 :ref Diff1601 :param1602 :union1603 :literal "a"1604 :literal "b"1605 :literal "c"1606 :literal "d"1607 :param1608 :union1609 :literal "a"1610 :literal "c"1611 :literal "f"1612 :type T311613 :ref Filter1614 :param1615 :union1616 :literal "a"1617 :literal "b"1618 :literal "c"1619 :literal "d"1620 :param1621 :union1622 :literal "a"1623 :literal "c"1624 :literal "f"1625 :type T321626 :ref Diff1627 :param1628 :union1629 :string1630 :number1631 :paren1632 :=>1633 :void1634 :param1635 :ref Function1636 :type T331637 :ref Filter1638 :param1639 :union1640 :string1641 :number1642 :paren1643 :=>1644 :void1645 :param1646 :ref Function1647 :type NonNullable1648 :< T1649 :ref Diff1650 :param1651 :ref T1652 :param1653 :union1654 :null1655 :void1656 :type T341657 :ref NonNullable1658 :param1659 :union1660 :string1661 :number1662 :void1663 :type T351664 :ref NonNullable1665 :param1666 :union1667 :string1668 :[1669 :string1670 :null1671 :void1672 function f11673 :< T1674 param x1675 :ref T1676 param y1677 :ref NonNullable1678 :param1679 :ref T1680 set x = y1681 set y = x1682 function f21683 :< T1684 :union1685 :string1686 :void1687 param x1688 :ref T1689 param y1690 :ref NonNullable1691 :param1692 :ref T1693 set x = y1694 set y = x1695 let s11696 :string1697 := x1698 let s21699 :string1700 := y1701 item1702 title Conditional types combined with mapped types:1703 expected1704 + // conditional types are particularly useful when combined with mapped types:1705 + type FunctionPropertyNames<T> = {[K in keyof T]: T[K] extends Function ? K : never }[keyof T];1706 + type FunctionProperties<T> = Pick<T, FunctionPropertyNames<T>>;1707 + type NonFunctionPropertyNames<T> = {[K in keyof T]: T[K] extends Function ? never : K }[keyof T];1708 + type NonFunctionProperties<T> = Pick<T, NonFunctionPropertyNames<T>>;1709 + interface Part {1710 + id: number;1711 + name: string;1712 + subparts: Part[];1713 + updatePart(newName: string): void;1714 + }1715 + type T40 = FunctionPropertyNames<Part>; // "updatePart"1716 + type T41 = NonFunctionPropertyNames<Part>; // "id" | "name" | "subparts"1717 + type T42 = FunctionProperties<Part>; // { updatePart(newName: string): void }1718 + type T43 = NonFunctionProperties<Part>; // { id: number, name: string, subparts: Part[] }1719 + // Similar to union and intersection types, conditional types are not permitted to reference themselves recursively.For example the following is an error.1720 + // Example1721 + type ElementType<T> = T extends any[] ? ElementType<T[number]> : T; // Error1722 ittf1723 +1724 :type FunctionPropertyNames1725 :< T1726 :[]1727 :mapped1728 :< K1729 :keyof1730 :ref T1731 :iif1732 :check1733 :[]1734 :ref T1735 :ref K1736 :extends1737 :ref Function1738 :then1739 :ref K1740 :else1741 :never1742 :keyof1743 :ref T1744 :type FunctionProperties1745 :< T1746 :ref Pick1747 :param1748 :ref T1749 :param1750 :ref FunctionPropertyNames1751 :param1752 :ref T1753 :type NonFunctionPropertyNames1754 :< T1755 :[]1756 :mapped1757 :< K1758 :keyof1759 :ref T1760 :iif1761 :check1762 :[]1763 :ref T1764 :ref K1765 :extends1766 :ref Function1767 :then1768 :never1769 :else1770 :ref K1771 :keyof1772 :ref T1773 :type NonFunctionProperties1774 :< T1775 :ref Pick1776 :param1777 :ref T1778 :param1779 :ref NonFunctionPropertyNames1780 :param1781 :ref T1782 :interface Part1783 :p id1784 :number1785 :p name1786 :string1787 :p subparts1788 :[1789 :ref Part1790 :m updatePart1791 :void1792 param newName1793 :string1794 :type T401795 :ref FunctionPropertyNames1796 :param1797 :ref Part1798 :type T411799 :ref NonFunctionPropertyNames1800 :param1801 :ref Part1802 :type T421803 :ref FunctionProperties1804 :param1805 :ref Part1806 :type T431807 :ref NonFunctionProperties1808 :param1809 :ref Part1810 :type ElementType1811 :< T1812 :iif1813 :check1814 :ref T1815 :extends1816 :[1817 :any1818 :then1819 :ref ElementType1820 :param1821 :[]1822 :ref T1823 :number1824 :else1825 :ref T1826 item1827 title Type inference in conditional types1828 expected1829 + //For example, the following extracts the return type of a function type:1830 + type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;1831 + // Conditional types can be nested to form a sequence of pattern matches that are evaluated in order:1832 + type Unpacked<T> =1833 + T extends (infer U)[] ? U :1834 + T extends (...args: any[]) => infer U ? U :1835 + T extends Promise < infer U> ? U :1836 + T;1837 + type T0 = Unpacked<string>; // string1838 + type T1 = Unpacked<string[]>; // string1839 + type T2 = Unpacked<() => string>; // string1840 + type T3 = Unpacked<Promise<string>>; // string1841 + type T4 = Unpacked<Promise<string>[]>; // Promise<string>1842 + type T5 = Unpacked<Unpacked<Promise<string>[]>>; // string1843 + // The following example demonstrates how multiple candidates for the same type variable in co - variant positions causes a union type to be inferred:1844 + type Foo<T> = T extends { a: infer U, b: infer U } ? U: never;1845 + type T10 = Foo<{ a: string, b: string }>; // string1846 + type T11 = Foo<{ a: string, b: number }>; // string | number1847 + // Likewise, multiple candidates for the same type variable in contra - variant positions causes an intersection type to be inferred:1848 + type Bar<T> = T extends { a: (x: infer U) => void, b: (x: infer U) => void } ? U: never;1849 + type T20 = Bar<{ a: (x: string) => void, b: (x: string) => void }>; // string1850 + type T21 = Bar<{ a: (x: string) => void, b: (x: number) => void }>; // string & number1851 + // When inferring from a type with multiple call signatures (such as the type of an overloaded function), inferences are made1852 + // from the last signature (which, presumably, is the most permissive catch-all case). It is not possible to perform overload1853 + // resolution based on a list of argument types.1854 + declare function foo(x: string): number;1855 + declare function foo(x: number): string;1856 + declare function foo(x: string | number): string | number;1857 + type T30 = ReturnType<typeof foo>; // string | number1858 + // It is not possible to use infer declarations in constraint clauses for regular type parameters:1859 + type ReturnType<T extends (...args: any[]) => infer R> = R; // Error, not supported1860 + // However, much the same effect can be obtained by erasing the type variables in the constraint and instead specifying a conditional type:1861 + type AnyFunction = (...args: any[]) => any;1862 + type ReturnType<T extends AnyFunction> = T extends (...args: any[]) => infer R ? R : any;1863 ittf1864 +1865 :type ReturnType1866 :< T1867 :iif1868 :check1869 :ref T1870 :extends1871 :=>1872 :infer1873 :< R1874 param ...args1875 :[1876 :any1877 :then1878 :ref R1879 :else1880 :any1881 :type Unpacked1882 :< T1883 :iif1884 :check1885 :ref T1886 :extends1887 :[1888 :paren1889 :infer1890 :< U1891 :then1892 :ref U1893 :else1894 :iif1895 :check1896 :ref T1897 :extends1898 :=>1899 :infer1900 :< U1901 param ...args1902 :[1903 :any1904 :then1905 :ref U1906 :else1907 :iif1908 :check1909 :ref T1910 :extends1911 :ref Promise1912 :param1913 :infer1914 :< U1915 :then1916 :ref U1917 :else1918 :ref T1919 :type T01920 :ref Unpacked1921 :param string1922 :type T11923 :ref Unpacked1924 :param1925 :[1926 :string1927 :type T21928 :ref Unpacked1929 :param1930 :=>1931 :string1932 :type T31933 :ref Unpacked1934 :param1935 :ref Promise1936 :param string1937 :type T41938 :ref Unpacked1939 :param1940 :[1941 :ref Promise1942 :param string1943 :type T51944 :ref Unpacked1945 :param1946 :ref Unpacked1947 :param1948 :[1949 :ref Promise1950 :param string1951 :type Foo1952 :< T1953 :iif1954 :check1955 :ref T1956 :extends1957 :{1958 :p a1959 :infer1960 :< U1961 :p b1962 :infer1963 :< U1964 :then1965 :ref U1966 :else1967 :never1968 :type T101969 :ref Foo1970 :param1971 :{1972 :p a1973 :string1974 :p b1975 :string1976 :type T111977 :ref Foo1978 :param1979 :{1980 :p a1981 :string1982 :p b1983 :number1984 :type Bar1985 :< T1986 :iif1987 :check1988 :ref T1989 :extends1990 :{1991 :p a1992 :=>1993 :void1994 param x1995 :infer1996 :< U1997 :p b1998 :=>1999 :void2000 param x2001 :infer2002 :< U2003 :then2004 :ref U2005 :else2006 :never2007 :type T202008 :ref Bar2009 :param2010 :{2011 :p a2012 :=>2013 :void2014 param x2015 :string2016 :p b2017 :=>2018 :void2019 param x2020 :string2021 :type T212022 :ref Bar2023 :param2024 :{2025 :p a2026 :=>2027 :void2028 param x2029 :string2030 :p b2031 :=>2032 :void2033 param x2034 :number2035 :function foo2036 param x2037 :string2038 :return2039 :number2040 :function foo2041 param x2042 :number2043 :return2044 :string2045 :function foo2046 param x2047 :union2048 :string2049 :number2050 :return2051 :union2052 :string2053 :number2054 :type T302055 :ref ReturnType2056 :param2057 :typeof foo2058 :type ReturnType2059 :< T2060 :=>2061 :infer2062 :< R2063 param ...args2064 :[2065 :any2066 :ref R2067 :type AnyFunction2068 :=>2069 :any2070 param ...args2071 :[2072 :any2073 :type ReturnType2074 :< T2075 :ref AnyFunction2076 :iif2077 :check2078 :ref T2079 :extends2080 :=>2081 :infer2082 :< R2083 param ...args2084 :[2085 :any2086 :then2087 :ref R2088 :else2089 :any2090 item2091 title Predefined conditional types2092 expected2093 + type T00 = Exclude<"a" | "b" | "c" | "d", "a" | "c" | "f">; // "b" | "d"2094 + type T01 = Extract<"a" | "b" | "c" | "d", "a" | "c" | "f">; // "a" | "c"2095 + type T02 = Exclude<string | number | (() => void), Function>; // string | number2096 + type T03 = Extract<string | number | (() => void), Function>; // () => void2097 + type T04 = NonNullable<string | number | undefined>; // string | number2098 + type T05 = NonNullable<(() => string) | string[] | null | undefined>; // (() => string) | string[]2099 + function f1(s: string) {2100 + return { a: 1, b: s }2101 + }2102 + class C {2103 + x = 0;2104 + y = 0;2105 + }2106 + type T10 = ReturnType<() => string>; // string2107 + type T11 = ReturnType<(s: string) => void>; // void2108 + type T12 = ReturnType<(<T>() => T)>; // {}2109 + type T13 = ReturnType<(<T extends U, U extends number[]>() => T)>; // number[]2110 + type T14 = ReturnType<typeof f1>; // { a: number, b: string }2111 + type T15 = ReturnType<any>; // any2112 + type T16 = ReturnType<never>; // any2113 + type T17 = ReturnType<string>; // Error2114 + type T18 = ReturnType<Function>; // Error2115 + type T20 = InstanceType<typeof C>; // C2116 + type T21 = InstanceType<any>; // any2117 + type T22 = InstanceType<never>; // any2118 + type T23 = InstanceType<string>; // Error2119 + type T24 = InstanceType<Function>; // Error2120 ittf2121 +2122 :type T002123 :ref Exclude2124 :param2125 :union2126 :literal "a"2127 :literal "b"2128 :literal "c"2129 :literal "d"2130 :param2131 :union2132 :literal "a"2133 :literal "c"2134 :literal "f"2135 :type T012136 :ref Extract2137 :param2138 :union2139 :literal "a"2140 :literal "b"2141 :literal "c"2142 :literal "d"2143 :param2144 :union2145 :literal "a"2146 :literal "c"2147 :literal "f"2148 :type T022149 :ref Exclude2150 :param2151 :union2152 :string2153 :number2154 :paren2155 :=>2156 :void2157 :param2158 :ref Function2159 :type T032160 :ref Extract2161 :param2162 :union2163 :string2164 :number2165 :paren2166 :=>2167 :void2168 :param2169 :ref Function2170 :type T042171 :ref NonNullable2172 :param2173 :union2174 :string2175 :number2176 :void2177 :type T052178 :ref NonNullable2179 :param2180 :union2181 :paren2182 :=>2183 :string2184 :[2185 :string2186 :null2187 :void2188 function f12189 param s2190 :string2191 return2192 {2193 @ a 12194 @ b s2195 class C2196 p x2197 := 02198 p y2199 := 02200 :type T102201 :ref ReturnType2202 :param2203 :=>2204 :string2205 :type T112206 :ref ReturnType2207 :param2208 :=>2209 :void2210 param s2211 :string2212 :type T122213 :ref ReturnType2214 :param2215 :paren2216 :=>2217 :< T2218 :ref T2219 :type T132220 :ref ReturnType2221 :param2222 :paren2223 :=>2224 :< T2225 :ref U2226 :< U2227 :[2228 :number2229 :ref T2230 :type T142231 :ref ReturnType2232 :param2233 :typeof f12234 :type T152235 :ref ReturnType2236 :param any2237 :type T162238 :ref ReturnType2239 :param never2240 :type T172241 :ref ReturnType2242 :param string2243 :type T182244 :ref ReturnType2245 :param2246 :ref Function2247 :type T202248 :ref InstanceType2249 :param2250 :typeof C2251 :type T212252 :ref InstanceType2253 :param any2254 :type T222255 :ref InstanceType2256 :param never2257 :type T232258 :ref InstanceType2259 :param string2260 :type T242261 :ref InstanceType2262 :param2263 :ref Function2264 # Error