Starter Lab Productions Play
Project Docs Github
Log in
ittf models cheatsheets ts index.ittf.ittf Edit
  • /ittf/models/cheatsheets/ts/index.ittf.ittf
  • /ittf/models/cheatsheets/ts/t/modules.ittf.ittf
  • /ittf/models/cheatsheets/ts/t/var.ittf.ittf
  • /ittf/models/cheatsheets/ts/t/functions.ittf.ittf
  • /ittf/models/cheatsheets/ts/t/classes.ittf.ittf
  • /ittf/models/cheatsheets/ts/t/interfaces.ittf.ittf
  • /ittf/models/cheatsheets/ts/t/generics.ittf.ittf
  • /ittf/models/cheatsheets/ts/t/advanced.ittf.ittf

/ittf/models/cheatsheets/ts/index.ittf.ittf (primary)

edit
                                            
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

edit
                                            
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 - right
1001 case "*"
1002 return left * right
1003 case "/"
1004 return left / right
1005 m evaluate
1006 :private
1007 if this.operator
1008 set this.memory = this.evaluateOperator(this.operator, this.memory, this.current)
1009 else
1010 set this.memory = this.current
1011 set this.current = 0
1012 m handleChar
1013 :public
1014 param char
1015 :string
1016 if char === "="
1017 _ this.evaluate
1018 return
1019 else
1020 let value = this.processDigit(char, this.current)
1021 if value !== undefined
1022 set this.current = value
1023 return
1024 else
1025 let value = this.processOperator(char)
1026 if value !== undefined
1027 _ this.evaluate
1028 set this.operator = value
1029 return
1030 throw
1031 new Error
1032 template
1033 + Unsupported input: '
1034 @ char
1035 + '
1036 m getResult
1037 :public
1038 return this.memory
1039 export
1040 function test
1041 param c
1042 :ref Calculator
1043 param input
1044 :string
1045 for let i = 0; i < input.length; i++
1046 _ c.handleChar(input[i])
1047 _ console.log
1048 template
1049 + result of '
1050 @ input
1051 + ' is '
1052 _ c.getResult
1053 + '
1054 #
1055 # Here is a simple test for the calculator using the exposed test function.
1056 #
1057 # TestCalculator.ts
1058 import
1059 @ Calculator
1060 @ test
1061 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.ts
1066 # ProgrammerCalculator.ts
1067 import
1068 @ Calculator
1069 from "./Calculator"
1070 class ProgrammerCalculator
1071 super Calculator
1072 p digits
1073 static
1074 [
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 ctor
1092 param base
1093 :public
1094 :number
1095 _ super
1096 const maxBase = ProgrammerCalculator.digits.length
1097 if base <= 0 || base > maxBase
1098 throw
1099 new Error
1100 template
1101 + base has to be within 0 to${}
1102 @ maxBase
1103 + ${}inclusive.
1104 m processDigit
1105 :protected
1106 param digit
1107 :string
1108 param currentValue
1109 :number
1110 if ProgrammerCalculator.digits.indexOf(digit) >= 0
1111 return currentValue * this.base + ProgrammerCalculator.digits.indexOf(digit)
1112 export
1113 @ ProgrammerCalculator
1114 as Calculator
1115 export
1116 @ test
1117 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.ts
1122 import
1123 @ Calculator
1124 @ test
1125 from "./ProgrammerCalculator"
1126 let c = new Calculator(2)
1127 _ test(c, "001+010=")

/ittf/models/cheatsheets/ts/t/var.ittf.ittf

edit
                                            
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

edit
                                            
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

edit
                                            
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

edit
                                            
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

edit
                                            
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

edit
                                            
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 Person
1001 :p name
1002 :string
1003 :p age
1004 :number
1005 let person
1006 :ref Person
1007 {
1008 @ name 'Jarid'
1009 @ age 35
1010 let strings
1011 :[
1012 :string
1013 _ pluck
1014 @ person
1015 [
1016 @ 'name'
1017 let personProps
1018 :keyof
1019 :ref Person
1020 _ pluck
1021 @ person
1022 [
1023 @ 'age'
1024 @ 'unknown'
1025 function getProperty
1026 :< T
1027 :< K
1028 :keyof
1029 :ref T
1030 param o
1031 :ref T
1032 param name
1033 :ref K
1034 :return
1035 :[]
1036 :ref T
1037 :ref K
1038 return o[name]
1039 let name
1040 :string
1041 _ getProperty(person, 'name')
1042 let age
1043 :number
1044 _ getProperty(person, 'age')
1045 let unknown = getProperty(person, 'unknown')
1046 :interface Map
1047 :< T
1048 :index
1049 :ref T
1050 param key
1051 :string
1052 let keys
1053 :keyof
1054 :ref Map
1055 :number
1056 let value
1057 :[]
1058 :ref Map
1059 :number
1060 :literal 'foo'
1061 item
1062 title Mapped types
1063 expected
1064 + 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 properties
1075 + // 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 ittf
1090 +
1091 :interface PersonPartial
1092 :p name
1093 :optional
1094 :string
1095 :p age
1096 :optional
1097 :number
1098 :interface PersonReadonly
1099 :p name
1100 :string
1101 :p age
1102 :number
1103 :type Readonly
1104 :< T
1105 :mapped
1106 :< P
1107 :keyof
1108 :ref T
1109 :[]
1110 :ref T
1111 :ref P
1112 :type Partial
1113 :< T
1114 :mapped
1115 :optional
1116 :< P
1117 :keyof
1118 :ref T
1119 :[]
1120 :ref T
1121 :ref P
1122 :type PersonPartial
1123 :ref Partial
1124 :ref Person
1125 :type ReadonlyPerson
1126 :ref Readonly
1127 :ref Person
1128 :type Keys
1129 :union
1130 :literal 'option1'
1131 :literal 'option2'
1132 :type Flags
1133 :mapped
1134 :< K
1135 :ref Keys
1136 :boolean
1137 item
1138 title Mapped types 2
1139 expected
1140 + /*
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 properties
1150 + // 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 property
1159 + // 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 take
1180 + // 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 ittf
1184 +
1185 :type Flags
1186 :{
1187 :p option1
1188 :boolean
1189 :p option2
1190 :boolean
1191 :type NullablePerson
1192 :mapped
1193 :< P
1194 :keyof
1195 :ref Person
1196 :union
1197 :[]
1198 :ref Person
1199 :ref P
1200 :null
1201 :type PartialPerson
1202 :mapped
1203 :optional
1204 :< P
1205 :keyof
1206 :ref Person
1207 :[]
1208 :ref Person
1209 :ref P
1210 :type Nullable
1211 :< T
1212 :mapped
1213 :< P
1214 :keyof
1215 :ref T
1216 :union
1217 :[]
1218 :ref T
1219 :ref P
1220 :null
1221 :type Partial
1222 :< T
1223 :mapped
1224 :optional
1225 :< P
1226 :keyof
1227 :ref T
1228 :[]
1229 :ref T
1230 :ref P
1231 :type Proxy
1232 :< T
1233 :{
1234 :m get
1235 :ref T
1236 :m set
1237 :void
1238 param value
1239 :ref T
1240 :type Proxify
1241 :< T
1242 :mapped
1243 :< P
1244 :keyof
1245 :ref T
1246 :ref Proxy
1247 :[]
1248 :ref T
1249 :ref P
1250 function proxify
1251 :< T
1252 param o
1253 :ref T
1254 :return
1255 :ref Proxify
1256 :ref T
1257 let proxyProps = proxify(props)
1258 :type Pick
1259 :< T
1260 :< K
1261 :keyof
1262 :ref T
1263 :mapped
1264 :< P
1265 :ref K
1266 :[]
1267 :ref T
1268 :ref P
1269 :type Record
1270 :< K
1271 :string
1272 :< T
1273 :mapped
1274 :< P
1275 :ref K
1276 :ref T
1277 :type ThreeStringProps
1278 :ref Record
1279 :union
1280 :literal 'prop1'
1281 :literal 'prop2'
1282 :literal 'prop3'
1283 :string
1284 item
1285 title Inference from mapped types
1286 expected
1287 + 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 ittf
1296 +
1297 function unproxify
1298 :< T
1299 param t
1300 :ref Proxify
1301 :param
1302 :ref T
1303 :return
1304 :ref T
1305 let result = {}
1306 for const k in t
1307 set result[k] = t[k].get()
1308 return result
1309 let originalProps = unproxify(proxyProps)
1310 item
1311 title Conditional Types
1312 expected
1313 + declare function f<T extends boolean>(x: T): T extends true ? string : number;
1314 + // Type is 'string | number
1315 + 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 ittf
1342 +
1343 :function f
1344 :< T
1345 :boolean
1346 param x
1347 :ref T
1348 :return
1349 :iif
1350 :check
1351 :ref T
1352 :extends
1353 :literal true
1354 :then
1355 :string
1356 :else
1357 :number
1358 # Type is 'string | number
1359 let x = f(Math.random() < 0.5)
1360 # Another example would be the TypeName type alias, which uses nested conditional types:
1361 :type TypeName
1362 :< T
1363 :iif
1364 :check
1365 :ref T
1366 :extends
1367 :string
1368 :then
1369 :literal "string"
1370 :else
1371 :iif
1372 :check
1373 :ref T
1374 :extends
1375 :number
1376 :then
1377 :literal "number"
1378 :else
1379 :iif
1380 :check
1381 :ref T
1382 :extends
1383 :boolean
1384 :then
1385 :literal "boolean"
1386 :else
1387 :iif
1388 :check
1389 :ref T
1390 :extends
1391 :void
1392 :then
1393 :literal "undefined"
1394 :else
1395 :iif
1396 :check
1397 :ref T
1398 :extends
1399 :ref Function
1400 :then
1401 :literal "function"
1402 :else
1403 :literal "object"
1404 :type T0
1405 :ref TypeName
1406 :param string
1407 # "string"
1408 :type T1
1409 :ref TypeName
1410 :param
1411 :literal "a"
1412 # "string"
1413 :type T2
1414 :ref TypeName
1415 :param
1416 :literal true
1417 # "boolean"
1418 :type T3
1419 :ref TypeName
1420 :param
1421 :=>
1422 :void
1423 # "function"
1424 :type T4
1425 :ref TypeName
1426 :param
1427 :[
1428 :string
1429 # "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 Foo
1432 :p propA
1433 :boolean
1434 :p propB
1435 :boolean
1436 :function f
1437 :< T
1438 param x
1439 :ref T
1440 :return
1441 :iif
1442 :check
1443 :ref T
1444 :extends
1445 :ref Foo
1446 :then
1447 :string
1448 :else
1449 :number
1450 function foo
1451 :< U
1452 param x
1453 :ref U
1454 # Has type 'U extends Foo ? string : number'
1455 let a = f(x)
1456 # This assignment is allowed though!
1457 let b
1458 :union
1459 :string
1460 :number
1461 := a
1462 item
1463 title Distributive conditional types
1464 expected
1465 + 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 resolved
1469 + to individual constituents of the union type (i.e. T refers to the individual constituents after the conditional type is distributed
1470 + over the union type). Furthermore, references to T within X have an additional type parameter constraint U (i.e. T is considered
1471 + assignable to U within X).*/
1472 + // Example
1473 + 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 U
1482 + type Filter<T, U> = T extends U ? T : never; // Remove types from T that are not assignable to U
1483 + 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 | number
1486 + type T33 = Filter<string | number | (() => void), Function>; // () => void
1487 + type NonNullable<T> = Diff<T, null | undefined>; // Remove null and undefined from T
1488 + type T34 = NonNullable<string | number | undefined>; // string | number
1489 + type T35 = NonNullable<string | string[] | null | undefined>; // string | string[]
1490 + function f1<T>(x: T, y: NonNullable<T>) {
1491 + x = y; // Ok
1492 + y = x; // Error
1493 + }
1494 + function f2<T extends string | undefined>(x: T, y: NonNullable<T>) {
1495 + x = y; // Ok
1496 + y = x; // Error
1497 + let s1: string = x; // Error
1498 + let s2: string = y; // Ok
1499 + }
1500 ittf
1501 +
1502 :type T10
1503 :ref TypeName
1504 :param
1505 :union
1506 :string
1507 :paren
1508 :=>
1509 :void
1510 :type T12
1511 :ref TypeName
1512 :param
1513 :union
1514 :string
1515 :[
1516 :string
1517 :void
1518 :type T11
1519 :ref TypeName
1520 :param
1521 :union
1522 :[
1523 :string
1524 :[
1525 :number
1526 #
1527 # In instantiations of a distributive conditional type T extends U ? X : Y, references to T within the conditional type are resolved
1528 # to individual constituents of the union type (i.e. T refers to the individual constituents after the conditional type is distributed
1529 # over the union type). Furthermore, references to T within X have an additional type parameter constraint U (i.e. T is considered
1530 # assignable to U within X).
1531 :type BoxedValue
1532 :< T
1533 :{
1534 :p value
1535 :ref T
1536 :type BoxedArray
1537 :< T
1538 :{
1539 :p array
1540 :[
1541 :ref T
1542 :type Boxed
1543 :< T
1544 :iif
1545 :check
1546 :ref T
1547 :extends
1548 :[
1549 :any
1550 :then
1551 :ref BoxedArray
1552 :param
1553 :[]
1554 :ref T
1555 :number
1556 :else
1557 :ref BoxedValue
1558 :param
1559 :ref T
1560 :type T20
1561 :ref Boxed
1562 :param string
1563 :type T21
1564 :ref Boxed
1565 :param
1566 :[
1567 :number
1568 :type T22
1569 :ref Boxed
1570 :param
1571 :union
1572 :string
1573 :[
1574 :number
1575 :type Diff
1576 :< T
1577 :< U
1578 :iif
1579 :check
1580 :ref T
1581 :extends
1582 :ref U
1583 :then
1584 :never
1585 :else
1586 :ref T
1587 :type Filter
1588 :< T
1589 :< U
1590 :iif
1591 :check
1592 :ref T
1593 :extends
1594 :ref U
1595 :then
1596 :ref T
1597 :else
1598 :never
1599 :type T30
1600 :ref Diff
1601 :param
1602 :union
1603 :literal "a"
1604 :literal "b"
1605 :literal "c"
1606 :literal "d"
1607 :param
1608 :union
1609 :literal "a"
1610 :literal "c"
1611 :literal "f"
1612 :type T31
1613 :ref Filter
1614 :param
1615 :union
1616 :literal "a"
1617 :literal "b"
1618 :literal "c"
1619 :literal "d"
1620 :param
1621 :union
1622 :literal "a"
1623 :literal "c"
1624 :literal "f"
1625 :type T32
1626 :ref Diff
1627 :param
1628 :union
1629 :string
1630 :number
1631 :paren
1632 :=>
1633 :void
1634 :param
1635 :ref Function
1636 :type T33
1637 :ref Filter
1638 :param
1639 :union
1640 :string
1641 :number
1642 :paren
1643 :=>
1644 :void
1645 :param
1646 :ref Function
1647 :type NonNullable
1648 :< T
1649 :ref Diff
1650 :param
1651 :ref T
1652 :param
1653 :union
1654 :null
1655 :void
1656 :type T34
1657 :ref NonNullable
1658 :param
1659 :union
1660 :string
1661 :number
1662 :void
1663 :type T35
1664 :ref NonNullable
1665 :param
1666 :union
1667 :string
1668 :[
1669 :string
1670 :null
1671 :void
1672 function f1
1673 :< T
1674 param x
1675 :ref T
1676 param y
1677 :ref NonNullable
1678 :param
1679 :ref T
1680 set x = y
1681 set y = x
1682 function f2
1683 :< T
1684 :union
1685 :string
1686 :void
1687 param x
1688 :ref T
1689 param y
1690 :ref NonNullable
1691 :param
1692 :ref T
1693 set x = y
1694 set y = x
1695 let s1
1696 :string
1697 := x
1698 let s2
1699 :string
1700 := y
1701 item
1702 title Conditional types combined with mapped types:
1703 expected
1704 + // 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 + // Example
1721 + type ElementType<T> = T extends any[] ? ElementType<T[number]> : T; // Error
1722 ittf
1723 +
1724 :type FunctionPropertyNames
1725 :< T
1726 :[]
1727 :mapped
1728 :< K
1729 :keyof
1730 :ref T
1731 :iif
1732 :check
1733 :[]
1734 :ref T
1735 :ref K
1736 :extends
1737 :ref Function
1738 :then
1739 :ref K
1740 :else
1741 :never
1742 :keyof
1743 :ref T
1744 :type FunctionProperties
1745 :< T
1746 :ref Pick
1747 :param
1748 :ref T
1749 :param
1750 :ref FunctionPropertyNames
1751 :param
1752 :ref T
1753 :type NonFunctionPropertyNames
1754 :< T
1755 :[]
1756 :mapped
1757 :< K
1758 :keyof
1759 :ref T
1760 :iif
1761 :check
1762 :[]
1763 :ref T
1764 :ref K
1765 :extends
1766 :ref Function
1767 :then
1768 :never
1769 :else
1770 :ref K
1771 :keyof
1772 :ref T
1773 :type NonFunctionProperties
1774 :< T
1775 :ref Pick
1776 :param
1777 :ref T
1778 :param
1779 :ref NonFunctionPropertyNames
1780 :param
1781 :ref T
1782 :interface Part
1783 :p id
1784 :number
1785 :p name
1786 :string
1787 :p subparts
1788 :[
1789 :ref Part
1790 :m updatePart
1791 :void
1792 param newName
1793 :string
1794 :type T40
1795 :ref FunctionPropertyNames
1796 :param
1797 :ref Part
1798 :type T41
1799 :ref NonFunctionPropertyNames
1800 :param
1801 :ref Part
1802 :type T42
1803 :ref FunctionProperties
1804 :param
1805 :ref Part
1806 :type T43
1807 :ref NonFunctionProperties
1808 :param
1809 :ref Part
1810 :type ElementType
1811 :< T
1812 :iif
1813 :check
1814 :ref T
1815 :extends
1816 :[
1817 :any
1818 :then
1819 :ref ElementType
1820 :param
1821 :[]
1822 :ref T
1823 :number
1824 :else
1825 :ref T
1826 item
1827 title Type inference in conditional types
1828 expected
1829 + //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>; // string
1838 + type T1 = Unpacked<string[]>; // string
1839 + type T2 = Unpacked<() => string>; // string
1840 + type T3 = Unpacked<Promise<string>>; // string
1841 + type T4 = Unpacked<Promise<string>[]>; // Promise<string>
1842 + type T5 = Unpacked<Unpacked<Promise<string>[]>>; // string
1843 + // 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 }>; // string
1846 + type T11 = Foo<{ a: string, b: number }>; // string | number
1847 + // 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 }>; // string
1850 + type T21 = Bar<{ a: (x: string) => void, b: (x: number) => void }>; // string & number
1851 + // When inferring from a type with multiple call signatures (such as the type of an overloaded function), inferences are made
1852 + // from the last signature (which, presumably, is the most permissive catch-all case). It is not possible to perform overload
1853 + // 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 | number
1858 + // 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 supported
1860 + // 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 ittf
1864 +
1865 :type ReturnType
1866 :< T
1867 :iif
1868 :check
1869 :ref T
1870 :extends
1871 :=>
1872 :infer
1873 :< R
1874 param ...args
1875 :[
1876 :any
1877 :then
1878 :ref R
1879 :else
1880 :any
1881 :type Unpacked
1882 :< T
1883 :iif
1884 :check
1885 :ref T
1886 :extends
1887 :[
1888 :paren
1889 :infer
1890 :< U
1891 :then
1892 :ref U
1893 :else
1894 :iif
1895 :check
1896 :ref T
1897 :extends
1898 :=>
1899 :infer
1900 :< U
1901 param ...args
1902 :[
1903 :any
1904 :then
1905 :ref U
1906 :else
1907 :iif
1908 :check
1909 :ref T
1910 :extends
1911 :ref Promise
1912 :param
1913 :infer
1914 :< U
1915 :then
1916 :ref U
1917 :else
1918 :ref T
1919 :type T0
1920 :ref Unpacked
1921 :param string
1922 :type T1
1923 :ref Unpacked
1924 :param
1925 :[
1926 :string
1927 :type T2
1928 :ref Unpacked
1929 :param
1930 :=>
1931 :string
1932 :type T3
1933 :ref Unpacked
1934 :param
1935 :ref Promise
1936 :param string
1937 :type T4
1938 :ref Unpacked
1939 :param
1940 :[
1941 :ref Promise
1942 :param string
1943 :type T5
1944 :ref Unpacked
1945 :param
1946 :ref Unpacked
1947 :param
1948 :[
1949 :ref Promise
1950 :param string
1951 :type Foo
1952 :< T
1953 :iif
1954 :check
1955 :ref T
1956 :extends
1957 :{
1958 :p a
1959 :infer
1960 :< U
1961 :p b
1962 :infer
1963 :< U
1964 :then
1965 :ref U
1966 :else
1967 :never
1968 :type T10
1969 :ref Foo
1970 :param
1971 :{
1972 :p a
1973 :string
1974 :p b
1975 :string
1976 :type T11
1977 :ref Foo
1978 :param
1979 :{
1980 :p a
1981 :string
1982 :p b
1983 :number
1984 :type Bar
1985 :< T
1986 :iif
1987 :check
1988 :ref T
1989 :extends
1990 :{
1991 :p a
1992 :=>
1993 :void
1994 param x
1995 :infer
1996 :< U
1997 :p b
1998 :=>
1999 :void
2000 param x
2001 :infer
2002 :< U
2003 :then
2004 :ref U
2005 :else
2006 :never
2007 :type T20
2008 :ref Bar
2009 :param
2010 :{
2011 :p a
2012 :=>
2013 :void
2014 param x
2015 :string
2016 :p b
2017 :=>
2018 :void
2019 param x
2020 :string
2021 :type T21
2022 :ref Bar
2023 :param
2024 :{
2025 :p a
2026 :=>
2027 :void
2028 param x
2029 :string
2030 :p b
2031 :=>
2032 :void
2033 param x
2034 :number
2035 :function foo
2036 param x
2037 :string
2038 :return
2039 :number
2040 :function foo
2041 param x
2042 :number
2043 :return
2044 :string
2045 :function foo
2046 param x
2047 :union
2048 :string
2049 :number
2050 :return
2051 :union
2052 :string
2053 :number
2054 :type T30
2055 :ref ReturnType
2056 :param
2057 :typeof foo
2058 :type ReturnType
2059 :< T
2060 :=>
2061 :infer
2062 :< R
2063 param ...args
2064 :[
2065 :any
2066 :ref R
2067 :type AnyFunction
2068 :=>
2069 :any
2070 param ...args
2071 :[
2072 :any
2073 :type ReturnType
2074 :< T
2075 :ref AnyFunction
2076 :iif
2077 :check
2078 :ref T
2079 :extends
2080 :=>
2081 :infer
2082 :< R
2083 param ...args
2084 :[
2085 :any
2086 :then
2087 :ref R
2088 :else
2089 :any
2090 item
2091 title Predefined conditional types
2092 expected
2093 + 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 | number
2096 + type T03 = Extract<string | number | (() => void), Function>; // () => void
2097 + type T04 = NonNullable<string | number | undefined>; // string | number
2098 + 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>; // string
2107 + type T11 = ReturnType<(s: string) => void>; // void
2108 + 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>; // any
2112 + type T16 = ReturnType<never>; // any
2113 + type T17 = ReturnType<string>; // Error
2114 + type T18 = ReturnType<Function>; // Error
2115 + type T20 = InstanceType<typeof C>; // C
2116 + type T21 = InstanceType<any>; // any
2117 + type T22 = InstanceType<never>; // any
2118 + type T23 = InstanceType<string>; // Error
2119 + type T24 = InstanceType<Function>; // Error
2120 ittf
2121 +
2122 :type T00
2123 :ref Exclude
2124 :param
2125 :union
2126 :literal "a"
2127 :literal "b"
2128 :literal "c"
2129 :literal "d"
2130 :param
2131 :union
2132 :literal "a"
2133 :literal "c"
2134 :literal "f"
2135 :type T01
2136 :ref Extract
2137 :param
2138 :union
2139 :literal "a"
2140 :literal "b"
2141 :literal "c"
2142 :literal "d"
2143 :param
2144 :union
2145 :literal "a"
2146 :literal "c"
2147 :literal "f"
2148 :type T02
2149 :ref Exclude
2150 :param
2151 :union
2152 :string
2153 :number
2154 :paren
2155 :=>
2156 :void
2157 :param
2158 :ref Function
2159 :type T03
2160 :ref Extract
2161 :param
2162 :union
2163 :string
2164 :number
2165 :paren
2166 :=>
2167 :void
2168 :param
2169 :ref Function
2170 :type T04
2171 :ref NonNullable
2172 :param
2173 :union
2174 :string
2175 :number
2176 :void
2177 :type T05
2178 :ref NonNullable
2179 :param
2180 :union
2181 :paren
2182 :=>
2183 :string
2184 :[
2185 :string
2186 :null
2187 :void
2188 function f1
2189 param s
2190 :string
2191 return
2192 {
2193 @ a 1
2194 @ b s
2195 class C
2196 p x
2197 := 0
2198 p y
2199 := 0
2200 :type T10
2201 :ref ReturnType
2202 :param
2203 :=>
2204 :string
2205 :type T11
2206 :ref ReturnType
2207 :param
2208 :=>
2209 :void
2210 param s
2211 :string
2212 :type T12
2213 :ref ReturnType
2214 :param
2215 :paren
2216 :=>
2217 :< T
2218 :ref T
2219 :type T13
2220 :ref ReturnType
2221 :param
2222 :paren
2223 :=>
2224 :< T
2225 :ref U
2226 :< U
2227 :[
2228 :number
2229 :ref T
2230 :type T14
2231 :ref ReturnType
2232 :param
2233 :typeof f1
2234 :type T15
2235 :ref ReturnType
2236 :param any
2237 :type T16
2238 :ref ReturnType
2239 :param never
2240 :type T17
2241 :ref ReturnType
2242 :param string
2243 :type T18
2244 :ref ReturnType
2245 :param
2246 :ref Function
2247 :type T20
2248 :ref InstanceType
2249 :param
2250 :typeof C
2251 :type T21
2252 :ref InstanceType
2253 :param any
2254 :type T22
2255 :ref InstanceType
2256 :param never
2257 :type T23
2258 :ref InstanceType
2259 :param string
2260 :type T24
2261 :ref InstanceType
2262 :param
2263 :ref Function
2264 # Error
Save
Save & Refresh
Cancel