/ittf/models/cheatsheets/ts/index.ittf.ittf (primary)
1 meta 2 schema ts 3 language typescript 4 $include modules 5 $include var 6 $include functions 7 $include classes 8 $include interfaces 9 $include generics 10 $include advanced
/ittf/models/cheatsheets/ts/t/modules.ittf.ittf
1 element modules 2 tag 3 ast 4 category 5 item 6 title Exporting a declaration 7 expected 8 + /* 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 ittf 20 + 21 # 22 # Validation.ts 23 export 24 :interface StringValidator 25 :m isAcceptable 26 :boolean 27 param s 28 :string 29 # 30 # ZipCodeValidator.ts 31 export 32 const numberRegexp = /^[0-9]+$/ 33 export 34 class ZipCodeValidator 35 :implements StringValidator 36 m isAcceptable 37 param s 38 :string 39 return s.length === 5 && numberRegexp.test(s) 40 item 41 title Export statements 42 expected 43 + 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 ittf 51 + 52 class ZipCodeValidator 53 :implements StringValidator 54 m isAcceptable 55 param s 56 :string 57 return s.length === 5 && numberRegexp.test(s) 58 export 59 @ ZipCodeValidator 60 export 61 @ ZipCodeValidator 62 as mainValidator 63 item 64 title Re - exports 65 expected 66 + /* 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 it 73 + 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 ittf 80 + 81 # 82 # ParseIntBasedZipCodeValidator.ts 83 export 84 class ParseIntBasedZipCodeValidator 85 m isAcceptable 86 param s 87 :string 88 return s.length === 5 && parseInt(s).toString() === s 89 export 90 @ ZipCodeValidator 91 as RegExpBasedZipCodeValidator 92 from "./ZipCodeValidator" 93 # 94 # AllValidators.ts 95 export * 96 from "./StringValidator" 97 export * 98 from "./LettersOnlyValidator" 99 export * 100 from "./ZipCodeValidator" 101 item 102 title Import a single export from a module 103 expected 104 + 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 ittf 115 + 116 import 117 @ ZipCodeValidator 118 from "./ZipCodeValidator" 119 let myValidator = new ZipCodeValidator() 120 # 121 # imports can also be renamed 122 import 123 @ ZipCodeValidator 124 as ZCV 125 from "./ZipCodeValidator" 126 let myValidator = new ZCV() 127 # 128 # Import the entire module into a single variable, and use it to access the module exports 129 import 130 as validator 131 from "./ZipCodeValidator" 132 let myValidator = new validator.ZipCodeValidator() 133 # 134 # Import a module for side- effects only 135 import "./my-module.js" 136 item 137 title Default exports 138 expected 139 + /* JQuery.d.ts */ 140 + declare let $: JQuery; 141 + export default $; 142 + /* App.ts */ 143 + import $ from "JQuery"; 144 + $("button.continue").html("Next Step..."); 145 ittf 146 + 147 # 148 # JQuery.d.ts 149 :declare 150 let 151 :ref JQuery 152 export-default 153 # 154 # App.ts 155 import $ from "JQuery" 156 _ $("button.continue").html("Next Step...") 157 item 158 title Default exports of classes and functions 159 expected 160 + /* 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 validate 179 + strings.forEach(s => { 180 + console.log(`"${s}" ${validate(s) ? " matches" : " does not match"}`); 181 + }); 182 ittf 183 + 184 # 185 # ZipCodeValidator.ts 186 export-default 187 class ZipCodeValidator 188 p numberRegexp 189 static 190 := /^[0-9]+$/ 191 m isAcceptable 192 param s 193 :string 194 return s.length === 5 && ZipCodeValidator.numberRegexp.test(s) 195 # 196 # Test.ts 197 import validator from "./ZipCodeValidator" 198 let myValidator = new validator() 199 # 200 # or 201 # StaticZipCodeValidator.ts 202 const numberRegexp = /^[0-9]+$/ 203 export-default 204 function 205 param s 206 :string 207 return s.length === 5 && numberRegexp.test(s) 208 # 209 # Test.ts 210 import validate from "./StaticZipCodeValidator" 211 let strings 212 [ 213 @ "Hello" 214 @ "98052" 215 @ "101" 216 _ strings.forEach 217 => 218 param s 219 _ console.log 220 template 221 + " 222 @ s 223 + "${} 224 iif validate(s) 225 then " matches" 226 else " does not match" 227 + 228 item 229 title Default exports can also be just values: 230 expected 231 + /* 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 ittf 238 + 239 # 240 # OneTwoThree.ts 241 export-default "123" 242 # 243 # Log.ts 244 import num from "./OneTwoThree" 245 _ console.log(num) 246 item 247 title export = and import = require() 248 expected 249 + /* 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 try 260 + let strings = ["Hello", "98052", "101"]; 261 + // Validators to use 262 + let validator = new zip(); 263 + // Show whether each string passed each validator 264 + strings.forEach(s => { 265 + console.log(`"${s}" - ${validator.isAcceptable(s) ? "matches" : "does not match"}`); 266 + }); 267 ittf 268 + 269 # 270 # ZipCodeValidator.ts 271 let numberRegexp = /^[0-9]+$/ 272 class ZipCodeValidator 273 m isAcceptable 274 param s 275 :string 276 return s.length === 5 && numberRegexp.test(s) 277 :export ZipCodeValidator 278 # 279 # Test.ts 280 :import zip 281 :require "./ZipCodeValidator" 282 let strings 283 [ 284 @ "Hello" 285 @ "98052" 286 @ "101" 287 let validator = new zip() 288 _ strings.forEach 289 => 290 param s 291 _ console.log 292 template 293 + " 294 @ s 295 + " -${} 296 iif validator.isAcceptable(s) 297 then "matches" 298 else "does not match" 299 + 300 item 301 title Code Generation for Modules 302 expected 303 + 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 ittf 341 + 342 :import m 343 :require "mod" 344 export 345 let t = m.something + 1 346 # 347 # AMD / RequireJS SimpleModule.js 348 _ define 349 [ 350 @ "require" 351 @ "exports" 352 @ "./mod" 353 function 354 param require 355 param exports 356 param mod_1 357 set exports.t = mod_1.something + 1 358 # 359 # CommonJS / Node SimpleModule.js 360 var mod_1 = require("./mod") 361 set exports.t = mod_1.something + 1 362 # 363 # UMD SimpleModule.js 364 iife 365 param factory 366 if typeof module === "object" && typeof module.exports === "object" 367 var v = factory(require, exports) 368 if v !== undefined 369 set module.exports = v 370 else 371 if typeof define === "function" && define.amd 372 _ define 373 [ 374 @ "require" 375 @ "exports" 376 @ "./mod" 377 @ factory 378 () 379 function 380 param require 381 param exports 382 var mod_1 = require("./mod") 383 set exports.t = mod_1.something + 1 384 # 385 # System SimpleModule.js 386 _ System.register 387 [ 388 @ "./mod" 389 function 390 param exports_1 391 var mod_1 392 var t 393 return 394 { 395 [ setters 396 function 397 param mod_1_1 398 set mod_1 = mod_1_1 399 @ execute 400 function 401 _ exports_1 402 @ "t" 403 set t = mod_1.something + 1 404 # 405 # Native ECMAScript 2015 modules SimpleModule.js 406 import 407 @ something 408 from "./mod" 409 export 410 var t = something + 1 411 item 412 title Simple Example 413 expected 414 + /* 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 try 439 + let strings = ["Hello", "98052", "101"]; 440 + // Validators to use 441 + let validators: { [s: string]: StringValidator; } = {}; 442 + validators["ZIP code"] = new ZipCodeValidator(); 443 + validators["Letters only"] = new LettersOnlyValidator(); 444 + // Show whether each string passed each validator 445 + 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 ittf 451 + 452 # 453 # Validation.ts 454 export 455 :interface StringValidator 456 :m isAcceptable 457 :boolean 458 param s 459 :string 460 # 461 # LettersOnlyValidator.ts 462 import 463 @ StringValidator 464 from "./Validation" 465 const lettersRegexp = /^[A-Za-z]+$/ 466 export 467 class LettersOnlyValidator 468 :implements StringValidator 469 m isAcceptable 470 param s 471 :string 472 return lettersRegexp.test(s) 473 # 474 # ZipCodeValidator.ts 475 import 476 @ StringValidator 477 from "./Validation" 478 const numberRegexp = /^[0-9]+$/ 479 export 480 class ZipCodeValidator 481 :implements StringValidator 482 m isAcceptable 483 param s 484 :string 485 return s.length === 5 && numberRegexp.test(s) 486 # 487 # Test.ts 488 import 489 @ StringValidator 490 from "./Validation" 491 import 492 @ ZipCodeValidator 493 from "./ZipCodeValidator" 494 import 495 @ LettersOnlyValidator 496 from "./LettersOnlyValidator" 497 let strings 498 [ 499 @ "Hello" 500 @ "98052" 501 @ "101" 502 let validators 503 :{ 504 :index 505 :ref StringValidator 506 param s 507 :string 508 { 509 set validators["ZIP code"] = new ZipCodeValidator() 510 set validators["Letters only"] = new LettersOnlyValidator() 511 _ strings.forEach 512 => 513 param s 514 for let name in validators 515 _ console.log 516 template 517 + " 518 @ s 519 + " -${} 520 iif validators[name].isAcceptable(s) 521 then "matches" 522 else "does not match" 523 + ${} 524 @ name 525 + 526 item 527 title Optional Module Loading 528 expected 529 + /* 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 ittf 556 + 557 # 558 # Dynamic Module Loading in Node.js 559 :declare 560 :function require 561 param moduleName 562 :string 563 :return 564 :any 565 import 566 @ ZipCodeValidator 567 as Zip 568 from "./ZipCodeValidator" 569 if needZipValidation 570 let ZipCodeValidator 571 :typeof Zip 572 _ require("./ZipCodeValidator") 573 let validator = new ZipCodeValidator() 574 if validator.isAcceptable("...") 575 # 576 # Sample: Dynamic Module Loading in require.js 577 :declare 578 :function require 579 param moduleNames 580 :[ 581 :string 582 param onLoad 583 :=> 584 :void 585 param ...args 586 :[ 587 :any 588 :return 589 :void 590 import 591 as Zip 592 from "./ZipCodeValidator" 593 if needZipValidation 594 _ require 595 [ 596 @ "./ZipCodeValidator" 597 => 598 param ZipCodeValidator 599 :typeof Zip 600 let validator = new ZipCodeValidator.ZipCodeValidator() 601 if validator.isAcceptable("...") 602 # 603 # Sample: Dynamic Module Loading in System.js 604 :declare 605 const System 606 :any 607 import 608 @ ZipCodeValidator 609 as Zip 610 from "./ZipCodeValidator" 611 if needZipValidation 612 _ System.import("./ZipCodeValidator").then 613 => 614 param ZipCodeValidator 615 :typeof Zip 616 var x = new ZipCodeValidator() 617 if x.isAcceptable("...") 618 item 619 title Ambient Modules 620 expected 621 + /* 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 ittf 640 + 641 # 642 # node.d.ts(simplified excerpt) 643 :declare 644 :module "url" 645 export 646 :interface Url 647 :p protocol 648 :optional 649 :string 650 :p hostname 651 :optional 652 :string 653 :p pathname 654 :optional 655 :string 656 export 657 :function parse 658 param urlStr 659 :string 660 param parseQueryString 661 :optional 662 param slashesDenoteHost 663 :optional 664 :return 665 :ref Url 666 :module "path" 667 export 668 :function normalize 669 param p 670 :string 671 :return 672 :string 673 export 674 :function join 675 param ...paths 676 :[ 677 :any 678 :return 679 :string 680 export 681 var sep 682 :string 683 # 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 import 686 as URL 687 from "url" 688 let myUrl = URL.parse("http://www.typescriptlang.org") 689 item 690 title Shorthand ambient modules 691 expected 692 + /*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 ittf 698 + 699 # 700 # declarations.d.ts 701 :declare 702 :module "hot-new-module" 703 # 704 # All imports from a shorthand module will have the any type. 705 import x 706 @ y 707 from "hot-new-module" 708 _ x(y) 709 item 710 title Wildcard module declarations 711 expected 712 + 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 ittf 726 + 727 :declare 728 :module "*!text" 729 const content 730 :string 731 export-default content 732 :module "json!*" 733 const value 734 :any 735 export-default value 736 # 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 item 742 title UMD modules 743 expected 744 + /* 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 module 751 + /* 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 ittf 754 + 755 # 756 # math-lib.d.ts 757 export 758 :function isPrime 759 param x 760 :number 761 :return 762 :boolean 763 :export-ns mathLib 764 # 765 # The library can then be used as an import within modules: 766 import 767 @ isPrime 768 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 item 775 title Export as close to top-level as possible 776 expected 777 + 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 ittf 804 + 805 export-default 806 class SomeType 807 ctor 808 # 809 # MyFunc.ts 810 export-default 811 function getThing 812 return "thing" 813 # 814 # Consumer.ts 815 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- level 823 # MyThings.ts 824 export 825 class SomeType 826 export 827 function someFunc 828 # 829 # Conversely when importing: 830 # Explicitly list imported names 831 # Consumer.ts 832 import 833 @ SomeType 834 @ someFunc 835 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 things 840 # MyLargeModule.ts 841 export 842 class Dog 843 export 844 class Cat 845 export 846 class Tree 847 export 848 class Flower 849 # 850 # Consumer.ts 851 import 852 as myLargeModule 853 from "./MyLargeModule.ts" 854 let x = new myLargeModule.Dog() 855 item 856 title Re -export to extend 857 expected 858 + 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 9 923 + /* Now to extend this to add support for input with numbers in bases other than 10, let’s create ProgrammerCalculator.ts 924 + /* 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 Calculator 942 + export { ProgrammerCalculator as Calculator }; 943 + // Also, export the helper function 944 + 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 3 949 ittf 950 + 951 export 952 class Calculator 953 p current 954 :private 955 := 0 956 p memory 957 :private 958 := 0 959 p operator 960 :private 961 :string 962 m processDigit 963 :protected 964 param digit 965 :string 966 param currentValue 967 :number 968 if digit >= "0" && digit <= "9" 969 return currentValue * 10 + (digit.charCodeAt(0) - "0".charCodeAt(0)) 970 m processOperator 971 :protected 972 param operator 973 :string 974 if 975 test 976 >= 977 [ 978 @ "+" 979 @ "-" 980 @ "*" 981 @ "/" 982 ._ indexOf 983 @ operator 984 + 0 985 return operator 986 m evaluateOperator 987 :protected 988 param operator 989 :string 990 param left 991 :number 992 param right 993 :number 994 :return 995 :number 996 switch this.operator 997 case "+" 998 return left + right 999 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 variables 2 tag 3 ast 4 category 5 item 6 title Boolean 7 expected 8 + let isDone: boolean = false; 9 ittf 10 let isDone 11 :boolean 12 := false 13 item 14 title Number 15 expected 16 + let decimal: number = 6; 17 ittf 18 let decimal 19 :number 20 := 6 21 item 22 title String 23 expected 24 + let color: string = "blue"; 25 ittf 26 let color 27 :string 28 := "blue" 29 item 30 title String literal 1 31 expected 32 + let fullName: string = `Bob Bobbington`; 33 ittf 34 let fullName 35 :string 36 template 37 + Bob Bobbington 38 item 39 title String literal 2 40 expected 41 + let sentence: string = `Hello, my name is ${fullName}`; 42 ittf 43 let sentence 44 :string 45 template 46 + Hello, my name is${} 47 @ fullName 48 + 49 item 50 title String literal 3 51 expected 52 + let sentence: string = "Hello, my name is " + fullName + ".\n\n" + "I'll be " + (age + 1) + " years old next month."; 53 ittf 54 let sentence 55 :string 56 set "Hello, my name is " + fullName + ".\n\n" + "I'll be " + (age + 1) + " years old next month." 57 item 58 title Array 1 59 expected 60 + let list: number[] = [1, 2, 3]; 61 ittf 62 let list 63 :[ 64 :number 65 [ 66 @ 1 67 @ 2 68 @ 3 69 item 70 title Array 2 71 expected 72 + let list: Array<number> = [1, 2, 3]; 73 ittf 74 let list 75 :ref Array 76 :param number 77 [ 78 @ 1 79 @ 2 80 @ 3 81 item 82 title Tuple 83 expected 84 + let x: [string, number]; 85 ittf 86 let x 87 :tuple 88 :string 89 :number 90 item 91 title Enum 92 expected 93 + 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 ittf 102 + 103 :enum Color 104 @ Red 105 @ Green 106 @ Blue 107 let c 108 :ref Color 109 := Color.Green 110 :enum Color 111 @ Red 1 112 @ Green 113 @ Blue 114 let c 115 :ref Color 116 := Color.Green 117 :enum Color 118 @ Red 1 119 @ Green 2 120 @ Blue 4 121 let c 122 :ref Color 123 := Color.Green 124 :enum Color 125 @ Red 1 126 @ Green 127 @ Blue 128 let colorName 129 :string 130 := Color[2] 131 item 132 title Any, Void, Null, Undefined 133 expected 134 + let notSure: any = 4; 135 + notSure = "maybe a string instead"; 136 + notSure = false; // okay, definitely a boolean 137 + let notSure: any = 4; 138 + notSure.ifItExists(); // okay, ifItExists might exist at runtime 139 + 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 ittf 151 + 152 let notSure 153 :any 154 := 4 155 set notSure = "maybe a string instead" 156 set notSure = false 157 let notSure 158 :any 159 := 4 160 _ notSure.ifItExists 161 _ notSure.toFixed 162 let prettySure 163 :ref Object 164 := 4 165 _ prettySure.toFixed 166 let list 167 :[ 168 :any 169 [ 170 @ 1 171 @ true 172 @ "free" 173 set list[1] = 100 174 function warnUser 175 :return 176 :void 177 _ console.log("This is my warning message") 178 let unusable 179 :void 180 := undefined 181 let u 182 :void 183 := undefined 184 let n 185 :null 186 := null 187 item 188 title Never 189 expected 190 + 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 ittf 201 + 202 function error 203 param message 204 :string 205 :return 206 :never 207 throw new Error(message) 208 function fail 209 return error("Something failed") 210 function infiniteLoop 211 :return 212 :never 213 while true 214 item 215 title Object 216 expected 217 + declare function create(o: object | null): void; 218 + let strLength: number = (someValue as string).length; 219 ittf 220 + 221 :function create 222 param o 223 :union 224 :object 225 :null 226 :return 227 :void 228 let strLength 229 :number 230 := 231 () 232 @id someValue 233 :as 234 :string 235 . length
/ittf/models/cheatsheets/ts/t/functions.ittf.ittf
1 element function 2 tag function 3 ast 4 category 5 item 6 title Typed functions 1 7 expected 8 + 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 ittf 13 + 14 function add 15 param x 16 :number 17 param y 18 :number 19 :return 20 :number 21 return x + y 22 let myAdd 23 function 24 param x 25 :number 26 param y 27 :number 28 :return 29 :number 30 return x + y 31 item 32 title Typed functions 2 33 expected 34 + let myAdd: (baseValue: number, increment: number) => number = 35 + function (x, y) { return x + y; }; 36 ittf 37 let myAdd 38 :=> 39 :number 40 param x 41 :number 42 param y 43 :number 44 function 45 param x 46 :number 47 param y 48 :number 49 :return 50 :number 51 return x + y 52 item 53 title Optional parameters 54 expected 55 + function buildName(firstName: string, lastName?: string) { 56 + if (lastName) 57 + return firstName + " " + lastName; 58 + else 59 + return firstName; 60 + } 61 + let result1 = buildName("Bob"); // error, too few parameters 62 + let result2 = buildName("Bob", "Adams", "Sr."); // error, too many parameters 63 + let result3 = buildName("Bob", "Adams"); // ah, just right 64 ittf 65 + 66 function buildName 67 param firstName 68 :string 69 param lastName 70 :string 71 :optional 72 if lastName 73 return firstName + " " + lastName 74 else 75 return firstName 76 # error, too few parameters 77 let result1 = buildName("Bob") 78 # error, too many parameters 79 let result2 = buildName("Bob", "Adams", "Sr.") 80 # ah, just right 81 let result3 = buildName("Bob", "Adams") 82 item 83 title Rest parameters 84 expected 85 + function buildName(firstName: string, ...restOfName: string[]) { 86 + return firstName + " " + restOfName.join(" "); 87 + } 88 + let buildNameFun: (fname: string, ...rest: string[]) => string = buildName; 89 ittf 90 + 91 function buildName 92 param firstName 93 :string 94 param ...restOfName 95 :[ 96 :string 97 return firstName + " " + restOfName.join(" ") 98 let buildNameFun 99 :=> 100 :string 101 param fname 102 :string 103 param ...rest 104 :[ 105 :string 106 := buildName 107 item 108 title This and arrow functions 109 expected 110 + 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 ittf 125 let deck 126 { 127 [ suits 128 @ "hearts" 129 @ "spades" 130 @ "clubs" 131 @ "diamonds" 132 @ cards Array(52) 133 @ createCardPicker 134 function 135 # NOTE: the line below is now an arrow function, allowing us to capture 'this' right here 136 return 137 => 138 let pickedCard = Math.floor(Math.random() * 52) 139 let pickedSuit = Math.floor(pickedCard / 13) 140 return 141 { 142 @ suit this.suits[pickedSuit] 143 @ card pickedCard % 13 144 item 145 title This parameters in callbacks 146 expected 147 + 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 runtime 154 + this.info = e.message; 155 + } 156 + } 157 ittf 158 + 159 :interface UIElement 160 :m addClickListener 161 :void 162 param onclick 163 :=> 164 :void 165 param this 166 :void 167 param e 168 :ref Event 169 class Handler 170 p info 171 :string 172 m onClickBad 173 param this 174 :ref Handler 175 param e 176 :ref Event 177 set this.info = e.message 178 item 179 title Overloads 1 180 expected 181 + let suits = ["hearts", "spades", "clubs", "diamonds"]; 182 + function pickCard(x): any { 183 + // Check to see if we're working with an object/array 184 + // if so, they gave us the deck and we'll pick the card 185 + if (typeof x == "object") { 186 + let pickedCard = Math.floor(Math.random() * x.length); 187 + return pickedCard; 188 + } 189 + // Otherwise just let them pick the card 190 + else if (typeof x == "number") { 191 + let pickedSuit = Math.floor(x / 13); 192 + return { suit: suits[pickedSuit], card: x % 13 }; 193 + } 194 + } 195 ittf 196 + 197 let suits 198 [ 199 @ "hearts" 200 @ "spades" 201 @ "clubs" 202 @ "diamonds" 203 function pickCard 204 param x 205 :return 206 :any 207 if typeof x == "object" 208 let pickedCard = Math.floor(Math.random() * x.length) 209 return pickedCard 210 else 211 # Otherwise just let them pick the card 212 if typeof x == "number" 213 let pickedSuit = Math.floor(x / 13) 214 return 215 { 216 @ suit suits[pickedSuit] 217 @ card x % 13 218 item 219 title Overloads 2 220 expected 221 + 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/array 226 + // if so, they gave us the deck and we'll pick the card 227 + if (typeof x == "object") { 228 + let pickedCard = Math.floor(Math.random() * x.length); 229 + return pickedCard; 230 + } 231 + // Otherwise just let them pick the card 232 + else if (typeof x == "number") { 233 + let pickedSuit = Math.floor(x / 13); 234 + return { suit: suits[pickedSuit], card: x % 13 }; 235 + } 236 + } 237 ittf 238 + 239 let suits 240 [ 241 @ "hearts" 242 @ "spades" 243 @ "clubs" 244 @ "diamonds" 245 :function pickCard 246 param x 247 :[ 248 :{ 249 :p suit 250 :string 251 :p card 252 :number 253 :return 254 :number 255 :function pickCard 256 param x 257 :number 258 :return 259 :{ 260 :p suit 261 :string 262 :p card 263 :number 264 function pickCard 265 param x 266 :return 267 :any 268 # if so, they gave us the deck and we'll pick the card 269 if typeof x == "object" 270 let pickedCard = Math.floor(Math.random() * x.length) 271 return pickedCard 272 else 273 # Otherwise just let them pick the card 274 if typeof x == "number" 275 let pickedSuit = Math.floor(x / 13) 276 return 277 { 278 @ suit suits[pickedSuit] 279 @ card x % 13
/ittf/models/cheatsheets/ts/t/classes.ittf.ittf
1 element class 2 tag class 3 ast 4 category 5 item 6 title Simple class 7 expected 8 + 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 ittf 19 class Greeter 20 p greeting 21 :string 22 ctor 23 param message 24 :string 25 set this.greeting = message 26 m greet 27 return "Hello, " + this.greeting 28 let greeter = new Greeter("world") 29 item 30 title Class extension 31 expected 32 + 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 ittf 43 class Animal 44 m move 45 param distanceInMeters 46 :number 47 := 0 48 _ console.log 49 template 50 + Animal moved${} 51 @ distanceInMeters 52 + m. 53 class Dog 54 super Animal 55 m bark 56 _ console.log('Woof! Woof!') 57 item 58 title Complex class example 59 expected 60 + 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 ittf 86 + 87 class Animal 88 p name 89 :string 90 ctor 91 param theName 92 :string 93 set this.name = theName 94 m move 95 param distanceInMeters 96 :number 97 := 0 98 _ console.log 99 template 100 + 101 @ this.name 102 + ${}moved${} 103 @ distanceInMeters 104 + m. 105 class Snake 106 super Animal 107 ctor 108 param name 109 :string 110 _ super(name) 111 m move 112 param distanceInMeters = 5 113 _ console.log("Slithering...") 114 _ super.move(distanceInMeters) 115 class Horse 116 super Animal 117 ctor 118 param name 119 :string 120 _ super(name) 121 m move 122 param distanceInMeters = 45 123 _ console.log("Galloping...") 124 _ super.move(distanceInMeters) 125 item 126 title Class accessors 127 expected 128 + 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 compatible 144 ittf 145 + 146 class Animal 147 p name 148 :private 149 :string 150 ctor 151 param theName 152 :string 153 set this.name = theName 154 class Rhino 155 super Animal 156 ctor 157 _ super("Rhino") 158 class Employee 159 p name 160 :private 161 :string 162 ctor 163 param theName 164 :string 165 set this.name = theName 166 let animal = new Animal("Goat") 167 let rhino = new Rhino() 168 let employee = new Employee("Bob") 169 set animal = rhino 170 set animal = employee 171 item 172 title Class accessors 173 expected 174 + 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); // error 191 ittf 192 + 193 class Person 194 p name 195 :protected 196 :string 197 ctor 198 param name 199 :string 200 set this.name = name 201 class Employee 202 super Person 203 p department 204 :private 205 :string 206 ctor 207 param name 208 :string 209 param department 210 :string 211 _ super(name) 212 set this.department = department 213 m getElevatorPitch 214 :public 215 return 216 template 217 + Hello, my name is${} 218 @ this.name 219 + ${}and I work in${} 220 @ this.department 221 + . 222 item 223 title Readonly modifier 224 expected 225 + 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 ittf 235 + 236 class Octopus 237 p name 238 :readonly 239 :string 240 p numberOfLegs 241 :readonly 242 :number 243 := 8 244 ctor 245 param theName 246 :string 247 set this.name = theName 248 let dad = new Octopus("Man with the 8 strong legs") 249 set dad.name = "Man with the 3-piece suit" 250 item 251 title Parameter properties 252 expected 253 + class Octopus { 254 + readonly numberOfLegs: number = 8; 255 + constructor(readonly name: string) { 256 + } 257 + } 258 ittf 259 + 260 class Octopus 261 p numberOfLegs 262 :readonly 263 :number 264 := 8 265 ctor 266 param 267 :readonly 268 :string 269 item 270 title Static members 271 expected 272 + 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 ittf 282 class Grid 283 p origin 284 static 285 { 286 @ x 0 287 @ y 0 288 m calculateDistanceFromOrigin 289 param point 290 :{ 291 :p x 292 :number 293 :p y 294 :number 295 let xDist = (point.x - Grid.origin.x) 296 let yDist = (point.y - Grid.origin.y) 297 return Math.sqrt(xDist * xDist + yDist * yDist) / this.scale 298 ctor 299 param scale 300 :public 301 :number 302 item 303 title Abstract classes 1 304 expected 305 + abstract class Animal { 306 + abstract makeSound(): void; 307 + move(): void { 308 + console.log("roaming the earth..."); 309 + } 310 + } 311 ittf 312 + 313 class Animal 314 :abstract 315 :m makeSound 316 :abstract 317 :return 318 :void 319 m move 320 :return 321 :void 322 _ console.log("roaming the earth...") 323 item 324 title Abstract classes 2 325 expected 326 + 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 classes 333 + } 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 type 346 + department = new Department(); // error: cannot create an instance of an abstract class 347 + department = new AccountingDepartment(); // ok to create and assign a non-abstract subclass 348 + department.printName(); 349 + department.printMeeting(); 350 + department.generateReports(); // error: method doesn't exist on declared abstract type 351 ittf 352 + 353 class Department 354 :abstract 355 ctor 356 param name 357 :public 358 :string 359 m printName 360 :return 361 :void 362 _ console.log("Department name: " + this.name) 363 :m printMeeting 364 :abstract 365 :return 366 :void 367 class AccountingDepartment 368 super Department 369 ctor 370 _ super("Accounting and Auditing") 371 m printMeeting 372 :return 373 :void 374 _ console.log("The Accounting Department meets each Monday at 10am.") 375 m generateReports 376 :return 377 :void 378 _ console.log("Generating accounting reports...") 379 let department 380 :ref Department 381 set department = new Department() 382 set department = new AccountingDepartment() 383 _ department.printName 384 _ department.printMeeting 385 _ department.generateReports 386 # error: method doesn't exist on declared abstract type 387 item 388 title Static members 389 expected 390 + 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 ittf 402 + 403 class Greeter 404 p standardGreeting 405 static 406 := "Hello, there" 407 p greeting 408 :string 409 m greet 410 if this.greeting 411 return "Hello, " + this.greeting 412 else 413 return Greeter.standardGreeting 414 item 415 title Class extended by interface 416 expected 417 + 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 ittf 426 + 427 class Point 428 p x 429 :number 430 p y 431 :number 432 :interface Point3d 433 :extends Point 434 :p z 435 :number 436 let point3d 437 :ref Point3d 438 { 439 @ x 1 440 @ y 2 441 @ z 3
/ittf/models/cheatsheets/ts/t/interfaces.ittf.ittf
1 element interfaces 2 tag 3 ast 4 category 5 item 6 title Simple interface 7 expected 8 + interface LabelledValue { 9 + label: string; 10 + } 11 ittf 12 :interface LabelledValue 13 :p label 14 :string 15 item 16 title Reference to interface 17 expected 18 + function printLabel(labelledObj: LabelledValue) { 19 + console.log(labelledObj.label); 20 + } 21 + let myObj = { size: 10, label: "Size 10 Object" }; 22 + printLabel(myObj); 23 ittf 24 + 25 function printLabel 26 param labelledObj 27 :ref LabelledValue 28 _ console.log(labelledObj.label) 29 let myObj 30 { 31 @ size 10 32 @ label "Size 10 Object" 33 _ printLabel(myObj) 34 item 35 title Optional properties 36 expected 37 + interface SquareConfig { 38 + color?: string; 39 + width?: number; 40 + } 41 ittf 42 :interface SquareConfig 43 :p color 44 :optional 45 :string 46 :p width 47 :optional 48 :number 49 item 50 title Optional properties 2 51 expected 52 + 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 ittf 69 + 70 :interface SquareConfig 71 :p color 72 :optional 73 :string 74 :p width 75 :optional 76 :number 77 function createSquare 78 param config 79 :ref SquareConfig 80 :return 81 :{ 82 :p color 83 :string 84 :p area 85 :number 86 let newSquare 87 { 88 @ color "white" 89 @ area 100 90 if config.clor 91 # Error: Property 'clor' does not exist on type 'SquareConfig' 92 set newSquare.color = config.clor 93 if config.width 94 set newSquare.area = config.width * config.width 95 return newSquare 96 let mySquare 97 _ createSquare 98 { 99 @ color "black" 100 item 101 title Readonly properties 102 expected 103 + 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 ittf 111 + 112 :interface Point 113 :p x 114 :number 115 :p y 116 :number 117 # You can construct a Point by assigning an object literal.After the assignment, x and y can’t be changed. 118 let p1 119 :ref Point 120 { 121 @ x 10 122 @ y 20 123 # error! 124 set p1.x = 5 125 item 126 title Readonly vs const 127 expected 128 + 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 ittf 137 + 138 :interface SquareConfig 139 :p color 140 :optional 141 :string 142 :p width 143 :optional 144 :number 145 function createSquare 146 param config 147 :ref SquareConfig 148 :return 149 :{ 150 :p color 151 :string 152 :p area 153 :number 154 let mySquare 155 _ createSquare 156 { 157 @ colour "red" 158 @ width 100 159 item 160 title Call signature 161 expected 162 + 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 ittf 171 + 172 :interface SearchFunc 173 :call 174 :boolean 175 param source 176 :string 177 param subString 178 :string 179 let mySearch 180 :ref SearchFunc 181 set mySearch = 182 function 183 param source 184 :string 185 param subString 186 :string 187 let result = source.search(subString) 188 return result > -1 189 item 190 title Index signature 191 expected 192 + interface StringArray { 193 + [index: number]: string; 194 + } 195 + let myArray: StringArray; 196 + myArray = ["Bob", "Fred"]; 197 + let myStr: string = myArray[0]; 198 ittf 199 + 200 :interface StringArray 201 :index 202 :string 203 param index 204 :number 205 let myArray 206 :ref StringArray 207 set myArray = 208 [ 209 @ "Bob" 210 @ "Fred" 211 let myStr 212 :string 213 := myArray[0] 214 item 215 title Index signature 2 216 expected 217 + 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 ittf 229 + 230 class Animal 231 p name 232 :string 233 class Dog 234 super Animal 235 p breed 236 :string 237 :interface NotOkay 238 :index 239 :ref Animal 240 param x 241 :number 242 :index 243 :ref Dog 244 param x 245 :string 246 item 247 title Index signature 3 248 expected 249 + interface NumberDictionary { 250 + [index: string]: number; 251 + length: number; // ok, length is a number 252 + name: string; // error, the type of 'name' is not a subtype of the indexer 253 + } 254 ittf 255 :interface NumberDictionary 256 :index 257 :number 258 param index 259 :string 260 :p length 261 :number 262 :p name 263 :string 264 item 265 title Readonly index signature 3 266 expected 267 + interface ReadonlyStringArray { 268 + readonly [index: number]: string; 269 + } 270 + let myArray: ReadonlyStringArray = ["Alice", "Bob"]; 271 + myArray[2] = "Mallory"; // error! 272 ittf 273 + 274 :interface ReadonlyStringArray 275 :index 276 :string 277 :readonly 278 param index 279 :number 280 let myArray 281 :ref ReadonlyStringArray 282 [ 283 @ "Alice" 284 @ "Bob" 285 set myArray[2] = "Mallory" 286 item 287 title Class Types 288 expected 289 + 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 ittf 308 + 309 :interface ClockInterface 310 :p currentTime 311 :ref Date 312 class Clock 313 :implements ClockInterface 314 p currentTime 315 :ref Date 316 ctor 317 param h 318 :number 319 param m 320 :number 321 :interface ClockInterface 322 :p currentTime 323 :ref Date 324 :m setTime 325 param d 326 :ref Date 327 class Clock 328 :extends ClockInterface 329 p currentTime 330 :ref Date 331 m setTime 332 param d 333 :ref Date 334 set this.currentTime = d 335 ctor 336 param h 337 :number 338 param m 339 :number 340 item 341 title static and instance sides of classes - fails 342 expected 343 + 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 ittf 352 + 353 :interface ClockConstructor 354 :new 355 param hour 356 :number 357 param minute 358 :number 359 class Clock 360 :implements ClockConstructor 361 p currentTime 362 :ref Date 363 ctor 364 param h 365 :number 366 param m 367 :number 368 item 369 title static and instance sides of classes - succeds 370 expected 371 + 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 ittf 397 + 398 :interface ClockConstructor 399 :new 400 :ref ClockInterface 401 param hour 402 :number 403 param minute 404 :number 405 :interface ClockInterface 406 :m tick 407 function createClock 408 param ctor 409 :ref ClockConstructor 410 param hour 411 :number 412 param minute 413 :number 414 :return 415 :ref ClockInterface 416 return new ctor(hour, minute) 417 class DigitalClock 418 :implements ClockInterface 419 ctor 420 param h 421 :number 422 param m 423 :number 424 m tick 425 _ console.log("beep beep") 426 class AnalogClock 427 :implements ClockInterface 428 ctor 429 param h 430 :number 431 param m 432 :number 433 m tick 434 _ console.log("tick tock") 435 let digital = createClock(DigitalClock, 12, 17) 436 let analog = createClock(AnalogClock, 7, 32) 437 item 438 title Extending Interfaces 1 439 expected 440 + 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 ittf 450 + 451 :interface Shape 452 :p color 453 :string 454 :interface Square 455 :extends Shape 456 :p sideLength 457 :number 458 let square 459 { 460 :as 461 :ref Square 462 set square.color = "blue" 463 set square.sideLength = 10 464 item 465 title Extending Interfaces 2 466 expected 467 + 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 ittf 481 + 482 :interface Shape 483 :p color 484 :string 485 :interface PenStroke 486 :p penWidth 487 :number 488 :interface Square 489 :extends Shape 490 :extends PenStroke 491 :p sideLength 492 :number 493 let square 494 { 495 :as 496 :ref Square 497 set square.color = "blue" 498 set square.sideLength = 10 499 set square.penWidth = 5 500 item 501 title Hybrid Types 502 expected 503 + 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 ittf 515 + 516 :interface Counter 517 :call 518 :string 519 param start 520 :number 521 :p interval 522 :number 523 :m reset 524 :void 525 function getCounter 526 :return 527 :ref Counter 528 let counter 529 :as 530 :ref Counter 531 function 532 param start 533 :number 534 set counter.interval = 123 535 set counter.reset = 536 function 537 return counter 538 let c = getCounter() 539 _ c(10) 540 _ c.reset 541 set c.interval = 5 542 item 543 title Class with private property 544 expected 545 + class Control { 546 + private state: any; 547 + } 548 ittf 549 class Control 550 p state 551 :private 552 :any 553 item 554 title Interface extending class 555 expected 556 + interface SelectableControl extends Control { 557 + select(): void; 558 + } 559 ittf 560 :interface SelectableControl 561 :extends Control 562 :m select 563 :void 564 item 565 title Derived class extending interface 566 expected 567 + class Button extends Control implements SelectableControl { 568 + select() {} 569 + } 570 ittf 571 class Button 572 super Control 573 :implements SelectableControl 574 m select 575 item 576 title Derived class 577 expected 578 + class TextBox extends Control { 579 + select() {} 580 + } 581 ittf 582 class TextBox 583 super Control 584 m select 585 item 586 title Class extending interface 587 expected 588 + // Error: Property 'state' is missing in type 'Image'. 589 + class Image implements SelectableControl { 590 + select() {} 591 + } 592 ittf 593 class Image 594 :implements SelectableControl 595 m select
/ittf/models/cheatsheets/ts/t/generics.ittf.ittf
1 element generics 2 tag 3 ast 4 category 5 item 6 title Identity function with any 7 expected 8 + function identity(arg: any): any { 9 + return arg; 10 + } 11 ittf 12 function identity 13 param arg 14 :any 15 :return 16 :any 17 return arg 18 item 19 title Identity function with type variable 20 expected 21 + function identity<T>(arg: T): T { 22 + return arg; 23 + } 24 ittf 25 function identity 26 :< T 27 param arg 28 :ref T 29 :return 30 :ref T 31 return arg 32 item 33 title Type argument 34 expected 35 + let output = identity<string>("myString"); // type of output will be 'string' 36 ittf 37 let output 38 _ identity 39 :< string 40 @ "myString" 41 item 42 title Length property fails 43 expected 44 + function loggingIdentity<T>(arg: T): T { 45 + console.log(arg.length); 46 + return arg; 47 + } 48 ittf 49 function loggingIdentity 50 :< T 51 param arg 52 :ref T 53 :return 54 :ref T 55 _ console.log(arg.length) 56 return arg 57 item 58 title Length property succeds 1 59 expected 60 + function loggingIdentity<T>(arg: T[]): T[] { 61 + console.log(arg.length); 62 + return arg; 63 + } 64 ittf 65 + 66 function loggingIdentity 67 :< T 68 param arg 69 :[ 70 :ref T 71 :return 72 :[ 73 :ref T 74 _ console.log(arg.length) 75 return arg 76 item 77 title Length property succeds 2 78 expected 79 + function loggingIdentity<T>(arg: Array<T>): Array<T> { 80 + console.log(arg.length); 81 + return arg; 82 + } 83 ittf 84 function loggingIdentity 85 :< T 86 param arg 87 :ref Array 88 :ref T 89 :return 90 :ref Array 91 :ref T 92 _ console.log(arg.length) 93 return arg 94 item 95 title Generic function 96 expected 97 + function identity<T>(arg: T): T { 98 + return arg; 99 + } 100 + let myIdentity: <T>(arg: T) => T = identity; 101 ittf 102 + 103 function identity 104 :< T 105 param arg 106 :ref T 107 :return 108 :ref T 109 return arg 110 let myIdentity 111 :=> 112 :ref T 113 param arg 114 :ref T 115 := identity 116 item 117 title Call signature object literal type 118 expected 119 + function identity<T>(arg: T): T { 120 + return arg; 121 + } 122 + let myIdentity: { <T>(arg: T): T } = identity; 123 ittf 124 + 125 function identity 126 :< T 127 param arg 128 :ref T 129 :return 130 :ref T 131 return arg 132 let myIdentity 133 :{ 134 :call 135 :< T 136 :ref T 137 param arg 138 :ref T 139 := identity 140 item 141 title Generic interface 142 expected 143 + 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 ittf 151 + 152 :interface GenericIdentityFn 153 :< T 154 :call 155 :ref T 156 param arg 157 :ref T 158 function identity 159 :< T 160 param arg 161 :ref T 162 :return 163 :ref T 164 return arg 165 let myIdentity 166 :ref GenericIdentityFn 167 :param number 168 := identity 169 item 170 title Generic Classes 171 expected 172 + class GenericNumber<T> { 173 + zeroValue: T; 174 + add: (x: T, y: T) => T; 175 + } 176 ittf 177 class GenericNumber 178 :< T 179 p zeroValue 180 :ref T 181 p add 182 :=> 183 :ref T 184 param x 185 :ref T 186 param y 187 :ref T 188 item 189 title Generic Constraints - fails 190 expected 191 + function loggingIdentity<T>(arg: T): T { 192 + console.log(arg.length); // Error: T doesn't have .length 193 + return arg; 194 + } 195 ittf 196 function loggingIdentity 197 :< T 198 param arg 199 :ref T 200 :return 201 :ref T 202 _ console.log(arg.length) 203 return arg 204 item 205 title Generic Constraints - succeds 206 expected 207 + 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 error 212 + return arg; 213 + } 214 ittf 215 + 216 :interface Lengthwise 217 :p length 218 :number 219 function loggingIdentity 220 :< T 221 :ref Lengthwise 222 param arg 223 :ref T 224 :return 225 :ref T 226 _ console.log(arg.length) 227 return arg 228 item 229 title Type Parameters in Generic Constraints 230 expected 231 + 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 ittf 238 + 239 function getProperty 240 :< T 241 :< K 242 :keyof 243 :ref T 244 param obj 245 :ref T 246 param key 247 :ref K 248 return obj[key] 249 let x 250 { 251 @ a 1 252 @ b 2 253 @ c 3 254 @ d 4 255 _ getProperty(x, "a") 256 _ getProperty(x, "m") 257 item 258 title Class Types in Generics 259 expected 260 + function create<T>(c: { new (): T; }): T { 261 + return new c(); 262 + } 263 ittf 264 function create 265 :< T 266 param c 267 :{ 268 :new 269 :ref T 270 :return 271 :ref T 272 return new c() 273 item 274 title Prototype property 275 expected 276 + 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 ittf 297 + 298 class BeeKeeper 299 p hasMask 300 :boolean 301 class ZooKeeper 302 p nametag 303 :string 304 class Animal 305 p numLegs 306 :number 307 class Bee 308 super Animal 309 p keeper 310 :ref BeeKeeper 311 class Lion 312 super Animal 313 p keeper 314 :ref ZooKeeper 315 function createInstance 316 :< A 317 :ref Animal 318 param c 319 :ctor 320 :ref A 321 :return 322 :ref A 323 return new c() 324 var x = createInstance(Lion).keeper.nametag 325 var y = createInstance(Bee).keeper.hasMask
/ittf/models/cheatsheets/ts/t/advanced.ittf.ittf
1 element advanced 2 tag 3 ast 4 category 5 item 6 title Intersection Types 7 expected 8 + 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 ittf 35 + 36 function extend 37 :< T 38 :< U 39 param first 40 :ref T 41 param second 42 :ref U 43 :return 44 :intersect 45 :ref T 46 :ref U 47 let result 48 :as 49 :intersect 50 :ref T 51 :ref U 52 { {} 53 for let id in first 54 set = 55 @expr 56 () 57 @id result 58 :as 59 :any 60 .[ id 61 @expr 62 () 63 @id first 64 :as 65 :any 66 .[ id 67 for let id in second 68 if !result.hasOwnProperty(id) 69 set = 70 @expr 71 () 72 @id result 73 :as 74 :any 75 .[ id 76 @expr 77 () 78 @id second 79 :as 80 :any 81 .[ id 82 return result 83 class Person 84 ctor 85 param name 86 :string 87 :interface Loggable 88 :m log 89 :void 90 class ConsoleLogger 91 :extends Loggable 92 m log 93 var jim = extend(new Person("Jim"), new ConsoleLogger()) 94 var n = jim.name 95 _ jim.log 96 item 97 title Union Types - fail at run time 98 expected 99 + 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 ittf 111 + 112 function padLeft 113 param value 114 :string 115 param padding 116 :any 117 if typeof padding === "number" 118 return Array(padding + 1).join(" ") + value 119 if typeof padding === "string" 120 return padding + value 121 throw 122 new Error 123 template 124 + Expected string or number, got ' 125 @ padding 126 + '. 127 _ padLeft("Hello world", 4) 128 let indentedString = padLeft("Hello world", true) 129 item 130 title Union Types - succeds at run time 131 expected 132 + function padLeft(value: string, padding: string | number) { 133 + // ... 134 + } 135 + let indentedString = padLeft("Hello world", true); // errors during compilation 136 ittf 137 + 138 function padLeft 139 param value 140 :string 141 param padding 142 :union 143 :string 144 :number 145 let indentedString = padLeft("Hello world", true) 146 item 147 title Union Types - common members 148 expected 149 + // 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 ittf 162 + 163 :interface Bird 164 :m fly 165 :m layEggs 166 :interface Fish 167 :m swim 168 :m layEggs 169 function getSmallPet 170 :return 171 :union 172 :ref Fish 173 :ref Bird 174 let pet = getSmallPet() 175 _ pet.layEggs 176 _ pet.swim 177 item 178 title Type Guards and Differentiating Types 179 expected 180 + let pet = getSmallPet(); 181 + if ((pet as Fish).swim) { 182 + (pet as Fish).swim(); 183 + } else { 184 + (pet as Bird).fly(); 185 + } 186 ittf 187 + 188 let pet = getSmallPet() 189 if 190 test 191 @expr 192 () 193 @id pet 194 :as 195 :ref Fish 196 . swim 197 _ 198 () 199 @id pet 200 :as 201 :ref Fish 202 ._ swim 203 else 204 _ 205 () 206 @id pet 207 :as 208 :ref Bird 209 ._ fly 210 item 211 title User - Defined Type Guards 212 expected 213 + 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 ittf 232 + 233 function isFish 234 param pet 235 :union 236 :ref Fish 237 :ref Bird 238 :return 239 :predicate pet 240 :ref Fish 241 return 242 !== 243 @expr 244 () 245 @id pet 246 :as 247 :ref Fish 248 . swim 249 + undefined 250 function isNumber 251 param x 252 :any 253 :return 254 :predicate x 255 :number 256 return typeof x === "number" 257 function isString 258 param x 259 :any 260 :return 261 :predicate x 262 :string 263 return typeof x === "string" 264 function padLeft 265 param value 266 :string 267 param padding 268 :union 269 :string 270 :number 271 if isNumber(padding) 272 return Array(padding + 1).join(" ") + value 273 if isString(padding) 274 return padding + value 275 throw 276 new Error 277 template 278 + Expected string or number, got ' 279 @ padding 280 + '. 281 item 282 title Instanceof type guards 283 expected 284 + interface Padder { 285 + getPaddingString(): string 286 + } 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 ittf 313 + 314 :interface Padder 315 :m getPaddingString 316 :string 317 class SpaceRepeatingPadder 318 :extends Padder 319 ctor 320 param numSpaces 321 :private 322 :number 323 m getPaddingString 324 return Array(this.numSpaces + 1).join(" ") 325 class StringPadder 326 :extends Padder 327 ctor 328 param value 329 :private 330 :string 331 m getPaddingString 332 return this.value 333 function getRandomPadder 334 return 335 iif Math.random() < 0.5 336 then new SpaceRepeatingPadder(4) 337 else new StringPadder(" ") 338 # Type is 'SpaceRepeatingPadder | StringPadder' 339 let padder 340 :ref Padder 341 _ getRandomPadder 342 if padder instanceof SpaceRepeatingPadder 343 var x = padder 344 # type narrowed to 'SpaceRepeatingPadder' 345 if padder instanceof StringPadder 346 var x = padder 347 # type narrowed to 'StringPadder' 348 item 349 title Nullable types 350 expected 351 + let s = "foo"; 352 + s = null; // error, 'null' is not assignable to 'string' 353 + let sn: string | null = "bar"; 354 + sn = null; // ok 355 + 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 properties 360 + 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; // ok 379 + c.b = null; // error, 'null' is not assignable to 'number | undefined' 380 ittf 381 + 382 let s = "foo" 383 set s = null 384 let sn 385 :union 386 :string 387 :null 388 := "bar" 389 set sn = null 390 set sn = undefined 391 function f 392 param x 393 :number 394 param 395 :number 396 :optional 397 return x + y || 0 398 _ f(1, 2) 399 _ f(1) 400 _ f(1, undefined) 401 _ f(1, null) 402 class C 403 p a 404 :number 405 p b 406 :number 407 let c = new C() 408 set c.a = 12 409 set c.a = undefined 410 set c.b = 13 411 set c.b = undefined 412 set c.b = null 413 item 414 title Type guards and type assertions 415 expected 416 + 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 null 433 + } 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; // ok 440 + } 441 + name = name || "Bob"; 442 + return postfix("great"); 443 + } 444 ittf 445 + 446 function f 447 param sn 448 :union 449 :string 450 :null 451 :return 452 :string 453 if sn == null 454 return "default" 455 else 456 return sn 457 function f 458 param sn 459 :union 460 :string 461 :null 462 :return 463 :string 464 return sn || "default" 465 function broken 466 param name 467 :union 468 :string 469 :null 470 :return 471 :string 472 function postfix 473 param epithet 474 :string 475 return name.charAt(0) + '. the ' + epithet 476 set name = name || "Bob" 477 return postfix("great") 478 function fixed 479 param name 480 :union 481 :string 482 :null 483 :return 484 :string 485 function postfix 486 param epithet 487 :string 488 return 489 op+ 490 op+ 491 _ 492 ._ charAt 493 @ 0 494 + '. the ' 495 + epithet 496 set name = name || "Bob" 497 return postfix("great") 498 item 499 title Type Aliases 500 expected 501 + 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>; // error 533 ittf 534 + 535 :type Name 536 :string 537 :type NameResolver 538 :=> 539 :string 540 :type NameOrResolver 541 :union 542 :ref Name 543 :ref NameResolver 544 function getName 545 param n 546 :ref NameOrResolver 547 :return 548 :ref Name 549 if typeof n === "string" 550 return n 551 else 552 return n() 553 :type Container 554 :< T 555 :{ 556 :p value 557 :ref T 558 :type Tree 559 :< T 560 :{ 561 :p value 562 :ref T 563 :p left 564 :ref Tree 565 :ref T 566 :p right 567 :ref Tree 568 :ref T 569 :type LinkedList 570 :< T 571 :intersect 572 :ref T 573 :{ 574 :p next 575 :ref LinkedList 576 :ref T 577 :interface Person 578 :p name 579 :string 580 var people 581 :ref LinkedList 582 :ref Person 583 var s = people.name 584 var s = people.next.name 585 var s = people.next.next.name 586 var s = people.next.next.next.name 587 :type Yikes 588 :ref Array 589 :ref Yikes 590 item 591 title Interfaces vs.Type Aliases 592 expected 593 + 594 ittf 595 + 596 :type Alias 597 :{ 598 :p num 599 :number 600 :interface Interface 601 :p num 602 :number 603 :function aliased 604 param arg 605 :ref Alias 606 :return 607 :ref Alias 608 :function interfaced 609 param arg 610 :ref Interface 611 :return 612 :ref Interface 613 item 614 title String Literal Types 615 expected 616 + 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 here 630 + // You can pass any of the three allowed strings, but any other string will give the error 631 + // 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 ittf 640 + 641 :type Easing 642 :union 643 :literal "ease-in" 644 :literal "ease-out" 645 :literal "ease-in-out" 646 class UIElement 647 m animate 648 param dx 649 :number 650 param dy 651 :number 652 param easing 653 :ref Easing 654 if easing === "ease-in" 655 else 656 if easing === "ease-out" 657 else 658 if easing === "ease-in-out" 659 else 660 let button = new UIElement() 661 _ button.animate(0, 0, "ease-in") 662 _ button.animate(0, 0, "uneasy") 663 :function createElement 664 param tagName 665 :literal "img" 666 :return 667 :ref HTMLImageElement 668 :function createElement 669 param tagName 670 :literal "input" 671 :return 672 :ref HTMLInputElement 673 function createElement 674 param tagName 675 :string 676 :return 677 :ref Element 678 item 679 title Numeric Literal Types 680 expected 681 + 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 ittf 691 + 692 function rollDie 693 :return 694 :union 695 :literal 1 696 :literal 2 697 :literal 3 698 :literal 4 699 :literal 5 700 :literal 6 701 function foo 702 param x 703 :number 704 if x !== 1 || x !== 2 705 item 706 title Enum Member Types 707 expected 708 + 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 with 722 + // 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 ittf 733 + 734 :interface Square 735 :p kind 736 :literal "square" 737 :p size 738 :number 739 :interface Rectangle 740 :p kind 741 :literal "rectangle" 742 :p width 743 :number 744 :p height 745 :number 746 :interface Circle 747 :p kind 748 :literal "circle" 749 :p radius 750 :number 751 :type Shape 752 :union 753 :ref Square 754 :ref Rectangle 755 :ref Circle 756 function area 757 param s 758 :ref Shape 759 switch s.kind 760 case "square" 761 return s.size * s.size 762 case "rectangle" 763 return s.height * s.width 764 case "circle" 765 return Math.PI * s.radius ** 2 766 item 767 title Exhaustiveness checking 768 expected 769 + 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 | undefined 780 + 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 sometimes 787 + // return undefined.If you have an explicit return type number, then you will get an error that 788 + // 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 cases 799 + } 800 + } 801 ittf 802 + 803 :type Shape 804 :union 805 :ref Square 806 :ref Rectangle 807 :ref Circle 808 :ref Triangle 809 function area 810 param s 811 :ref Shape 812 switch s.kind 813 case "square" 814 return s.size * s.size 815 case "rectangle" 816 return s.height * s.width 817 case "circle" 818 return Math.PI * s.radius ** 2 819 function area 820 param s 821 :ref Shape 822 :return 823 :number 824 switch s.kind 825 case "square" 826 return s.size * s.size 827 case "rectangle" 828 return s.height * s.width 829 case "circle" 830 return Math.PI * s.radius ** 2 831 function assertNever 832 param x 833 :never 834 :return 835 :never 836 throw new Error("Unexpected object: " + x) 837 function area 838 param s 839 :ref Shape 840 switch s.kind 841 case "square" 842 return s.size * s.size 843 case "rectangle" 844 return s.height * s.width 845 case "circle" 846 return Math.PI * s.radius ** 2 847 default 848 return assertNever(s) 849 item 850 title Polymorphic this types 851 expected 852 + 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 ittf 889 + 890 class BasicCalculator 891 ctor 892 :public 893 param value 894 :number 895 := 0 896 m currentValue 897 :public 898 return this.value 899 m add 900 :public 901 param operand 902 :number 903 set this.value += operand 904 return this 905 m multiply 906 :public 907 param operand 908 :number 909 set this.value *= operand 910 return this 911 let v = new BasicCalculator(2).multiply(5).add(1).currentValue() 912 class ScientificCalculator 913 super BasicCalculator 914 ctor 915 :public 916 param value = 0 917 _ super(value) 918 m sin 919 :public 920 set this.value = Math.sin(this.value) 921 return this 922 let v = new ScientificCalculator(2).multiply(5).sin().add(1).currentValue() 923 item 924 title Index types 925 expected 926 + 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: 35 940 + }; 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 generic 947 + // contexts like pluck, where you can’t possibly know the property names ahead of time.That means the compiler will check that you pass 948 + // 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 signatures 963 + // 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>; // string 969 + let value: Map<number>['foo']; // number 970 ittf 971 + 972 function pluck 973 param o 974 param names 975 return 976 _ names.map 977 => 978 param n 979 + o[n] 980 function pluck 981 :< T 982 :< K 983 :keyof 984 :ref T 985 param o 986 :ref T 987 param names 988 :[ 989 :ref K 990 :return 991 :[ 992 :[] 993 :ref T 994 :ref K 995 return 996 _ names.map 997 => 998 param n 999 + 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