= typescript = * https://www.typescriptlang.org * https://www.typescriptlang.org/docs/tutorial.html Typescript is a typed superset of [[Javascript]] that transpiles (is converted) to plain [[Javascript]]. == Install, compile and run == {{{#!highlight sh sudo npm install -g typescript # install echo "console.log(\"Hello world\");" > helloworld.ts tsc helloworld.ts # compile node helloworld.js # run }}} == kate == https://github.com/PrettyFlower/KateTypeScriptSyntaxHighlighting {{{#!highlight bash wget https://github.com/PrettyFlower/KateTypeScriptSyntaxHighlighting/raw/master/typescript.xml cp typescript.xml /usr/share/apps/katepart/syntax/typescript.xml }}} With let keyword added {{{#!highlight xml if else for in while do continue break with try catch finally switch case new var function return delete true false void throw typeof const default this null undefined class export declare module import static interface implements constructor public private string number bool any extends let }}} == Sample code typescript for browser == {{{#!highlight bash npm install -g typescript npm install -g webpack }}} === greeter.html === {{{#!highlight html TypeScript Greeter }}} === lib.ts === * https://www.typescriptlang.org/docs/handbook/modules.html Any declaration (such as a variable, function, class, type alias, or interface) can be exported by adding the export keyword. {{{#!highlight javascript export function getText(){ return "text"; } }}} === greeter.ts === * import {xyz} from "module"; {{{#!highlight javascript import {getText} from "./lib"; interface Person { firstName: string; lastName: string; } function greeterPerson(p:Person) { return "Hello GP, " + p.firstName + ' ' + p.lastName + ' ' + getText() ; } function greeter(person:string) { return "Hello, " + person; } var user = "XPTO User"; //document.body.innerHTML = greeter(user); document.body.innerHTML = greeterPerson( {firstName:"First",lastName:"Last"} ); }}} === tsconfig.json === {{{#!highlight javascript { "compilerOptions": { "module": "es6", "noImplicitAny": true, "removeComments": true, "preserveConstEnums": true, "sourceMap": true }, "files": [ "greeter.ts", "lib.ts"] } }}} === webpack.config.js === {{{#!highlight javascript var path = require('path'); module.exports = { entry: ['./greeter.js','./lib.js'], output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist') } }; }}} === build.sh === {{{#!highlight bash tsc webpack --config webpack.config.js }}} == ReactJS + typescript example == https://reactjs.org/ A [[Javascript]] library for building user interfaces. Build encapsulated components that manage their own state, then compose them to make complex UIs. https://reactjs.org/docs/thinking-in-react.html '''Structure''' {{{#!highlight bash . ├── App.tsx ├── build.sh ├── greeter.html ├── greeter.tsx ├── lib.ts ├── NameHolder.tsx ├── package.json ├── tsconfig.json └── webpack.config.js }}} === webpack.config.js === {{{#!highlight javascript var path = require('path'); module.exports = { entry: {main:'./greeter.js'}, resolve: { extensions: ['.js', '.jsx', '.ts', '.tsx'] }, output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist') } }; }}} === tsconfig.json === {{{#!highlight javascript { "compilerOptions": { "module": "es2015", "target": "es5", "noImplicitAny": true, "removeComments": true, "preserveConstEnums": true, "sourceMap": true, "moduleResolution": "node", "allowSyntheticDefaultImports": true, "jsx": "react" } } }}} === lib.ts === {{{#!highlight javascript function getText() { return "text"; } interface Person { firstName: string; lastName: string; } function greeterPerson(p: Person) { return "Hello GP, " + p.firstName + ' ' + p.lastName + ' ' + getText(); } function greeter(person: string) { return "Hello, " + person; } interface HumanInterface { name: string; getName(): void; } class Human implements HumanInterface { name: string; constructor(name: string) { this.name = name; } getName() { return "My name is " + this.name; } } class PubSub { callbacks: Function[]; constructor() { this.callbacks = []; } addListener(fn: Function): void { this.callbacks.push(fn); } notify(message: string): void { this.callbacks.forEach((fn) => { fn(message); }); } } let pubSub = new PubSub(); export { greeter, greeterPerson, Human, HumanInterface, Person, getText, PubSub, pubSub } }}} === greeter.html === {{{#!highlight html React + typescript test
}}} === package.json === {{{#!highlight javascript { "name": "test", "private": true, "version": "0.0.0", "devDependencies": { "@types/react": "15.0.35", "@types/react-dom": "15.5.1", "@types/webpack-env": "1.13.0", "react": "15.6.1", "react-dom": "15.6.1", "typescript": "2.4.1", "webpack": "2.5.1" } } }}} === App.tsx === {{{#!highlight javascript import React, { ReactChild } from 'react'; import { Person, greeterPerson, Human, HumanInterface } from './lib'; import NameHolder from './NameHolder'; import { pubSub } from './lib'; interface MyState { currDate: string; greetings: string; human: HumanInterface; } function createMyState(currDate: string, greetings: string, human: HumanInterface): MyState { return { currDate: currDate, greetings: greetings, human: human }; } interface MyProps { prop: string; } export default class App extends React.Component { text: string; timerID: number; constructor(props: MyProps) { super(props); this.text = this.props.prop; this.state = createMyState("waiting for date", "waiting for greetings", null); // init with MyState format } public static createHuman(name: string): HumanInterface { return new Human(name); } public tickHandler() { let cd = new Date().toString(); let greetings = greeterPerson({ firstName: "first", lastName: "last" }); let human: HumanInterface = App.createHuman("JohnDoe"); this.setState(createMyState(cd, greetings, human)); } componentDidMount() { // called after the 1st render ! console.log("First render"); this.timerID = setInterval(this.tickHandler.bind(this), 1000); } componentWillUnmount() { // component will be destroyed console.log("Will be destroyed soon"); clearInterval(this.timerID); } public render() { // do not call set state in render ! return (

Hello World!!! -- {this.text} -- {this.state.greetings}

Human {this.state.human != null ? this.state.human.getName() : ""} {this.state.currDate}

{ this.clickHandler(); }} > {this.props.children}
); } public clickHandler() { console.log("clicked. # children " + React.Children.count(this.props.children)); React.Children.forEach(this.props.children, (argx: any) => { if (argx.hasOwnProperty("props")) { console.log("props property found"); pubSub.notify("message from outer space !"); } console.log(JSON.stringify(argx)); }); } } }}} === greeter.tsx === {{{#!highlight javascript import React from 'react'; import ReactDOM from 'react-dom'; import {getText} from "./lib"; import App from './App'; // uses App.tsx import NameHolder from './NameHolder'; console.log("Entry point"); let appContainer = document.getElementById('app') ; let markup = ; ReactDOM.render( markup , appContainer); }}} === NameHolder.tsx === {{{#!highlight javascript import React from 'react'; import { pubSub } from './lib'; // Component properties (XML attributes) interface NameHolderProperties { attr: string; } interface NameHolderState { attr: string; } // properties and state export default class NameHolder extends React.Component { constructor(props: NameHolderProperties) { super(props); // populates the this.props this.state = { attr: this.props.attr }; pubSub.addListener(this.onMessage); } public render() { return !!!{this.state.attr}!!!; } public onMessage(message: string): void { console.log(this.state.attr + " receiVed " + message); } } }}} === build.sh === {{{#!highlight bash PATH=$PATH:./node_modules/typescript/bin echo Delete dist folder rm -rf dist echo Install NPM packages npm install echo Compile project tsc echo Create application bundle nodejs ./node_modules/webpack/bin/webpack.js --config webpack.config.js }}} == Constants == {{{#!highlight javascript export class Constants { static readonly CONST_A = "constA"; static readonly CONST_B = "constB"; } export const STATES = { stateA: 's1', stateB: 's2' }; }}} == Console app hello world == {{{#!highlight bash cd /tmp mkdir bar cd bar npm init echo '{ "compilerOptions": { "target": "es5", "sourceMap": true } }' > tsconfig.json npm install typescript ts-node npm install @types/node echo -e '#!/usr/bin/env node\nconsole.log("Hello world!");' > index.ts ./node_modules/ts-node/dist/bin.js index.ts }}} == Promise == * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise * The Promise object represents the eventual completion (or failure) of an asynchronous operation and its resulting value. * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises * A Promise is an object representing the eventual completion or failure of an asynchronous operation. * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all * The Promise.all() method takes an iterable of promises as an input, and returns a single Promise that resolves to an array of the results of the input promises. * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled * The Promise.allSettled() method returns a promise that resolves after all of the given promises have either fulfilled or rejected, with an array of objects that each describes the outcome of each promise. === index.ts === {{{#!highlight javascript #!/usr/bin/env node let p1:Promise = new Promise( (resolve,reject)=>{ resolve(true); } ); p1.then( (value)=>{ console.log("resolve sent value " + value ); } ) let c1:Promise = new Promise( (resolve,reject)=>{ reject('Error occurred'); } ); c1.catch( (value)=>{ console.log("reject sent value " + value); } ); console.log("Hello world!"); }}} * ./node_modules/ts-node/dist/bin.js index.ts {{{ Hello world! resolve sent value true reject sent value Error occurred }}} * node_modules/typescript/bin/tsc index.ts * node index.js == Question mark after interface member name == * It means that the member is optional {{{#!highlight javascript interface Test{ memberx?:string; } }}} == Exclamation mark after interface member name == * It means that the member is required (not null) {{{#!highlight javascript interface Test{ memberx!:string; } }}} == Method not implemented == {{{#!highlight javascript throw new Error("Method not implemented."); }}} == RxJS == * https://rxjs.dev/guide/subject * An RxJS Subject is a special type of Observable that allows values to be multicasted to many Observers. {{{#!highlight bash sudo apt install nodejs npm -y node -v # v14.19.1 cd /tmp mkdir bar cd bar npm init echo '{ "compilerOptions": { "target": "es5", "sourceMap": true } }' > tsconfig.json npm install typescript ts-node @types/node rxjs }}} === index.ts === {{{#!highlight javascript #!/usr/bin/env node import { Observable, Subject, pipe, take, Subscription } from 'rxjs'; const publisher = new Observable(subscriber => { subscriber.next(1); subscriber.next(2); subscriber.next(3); setTimeout(() => { subscriber.next(4); subscriber.complete(); }, 1000); }); console.log("Hello world!"); publisher.subscribe({ next(x) { console.log('got value ' + x); }, error(err) { console.error('something wrong occurred: ' + err); }, complete() { console.log('done'); } }); let eventStream = new Subject(); // only consumes 2 events let obs1 = eventStream.pipe(take(2)) let subs1: Subscription = obs1.subscribe({ next: (x) => { console.log('Sub1 next: ' + x); }, error: (err) => { console.log('Sub1 error: ' + err); }, complete: () => { console.log('Sub1 completed'); console.log(`In complete closed subs1 ${subs1.closed}`); subs1.unsubscribe(); } }); const subscription2: Subscription = eventStream.subscribe({ next: (x) => { console.log('Sub2 next: ' + x); }, error: (err) => { console.log('Sub2 error: ' + err); }, complete: () => { console.log('Sub2 completed'); } }); // send notifications setTimeout(() => { eventStream.next('n1_foo'); eventStream.next('n2_foo'); eventStream.error('e1_foo'); eventStream.error('e2_foo'); eventStream.complete(); console.log(`Closed subs1 ${subs1.closed}`); }, 3000); }}} {{{#!highlight sh ./node_modules/ts-node/dist/bin.js index.ts ./node_modules/typescript/bin/tsc index.ts node index.js }}} == Enums == Using an enum is simple: just access any member as a property off of the enum itself, and declare types using the name of the enum. * https://www.typescriptlang.org/docs/handbook/enums.html#string-enums * https://www.typescriptlang.org/docs/handbook/enums.html#numeric-enums {{{#!highlight javascript enum Direction { Up=0, Down, Left, Right, } enum Direction { Up = "UP", Down = "DOWN", Left = "LEFT", Right = "RIGHT", } enum BooleanLikeHeterogeneousEnum { No = 0, Yes = "YES", } }}} == Microtask == * https://developer.mozilla.org/en-US/docs/Web/API/HTML_DOM_API/Microtask_guide * https://developer.mozilla.org/en-US/docs/Web/API/queueMicrotask == Date and epoch == {{{#!highlight javascript let d: Date = new Date(); console.log(">>> " + d.getTime() ); }}} == Nullish coalescing operator (??) (double question marks) == * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing_operator The '''nullish coalescing operator (??)''' is a logical operator that returns its right-hand side operand when its left-hand side operand is null or undefined, and otherwise returns its left-hand side operand.