= 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 ==
    npm install -g typescript

== Compile ==
    tsc helloworld.ts 

== kate ==
https://github.com/PrettyFlower/KateTypeScriptSyntaxHighlighting
{{{
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
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE language SYSTEM "language.dtd">
<language name="TypeScript" section="Scripts" extensions="*.ts;"
        indenter="cstyle" author="PrettyFlower (abigchode@gmail.com)">
<highlighting>
    <list name="keywords">
        <item> if </item>
        <item> else </item>
        <item> for </item>
        <item> in </item>
        <item> while </item>
        <item> do </item>
        <item> continue </item>
        <item> break </item>
        <item> with </item>
        <item> try </item>
        <item> catch </item>
        <item> finally </item>
        <item> switch </item>
        <item> case </item>
        <item> new </item>
        <item> var </item>
        <item> function </item>
        <item> return </item>
        <item> delete </item>
        <item> true </item>
        <item> false </item>
        <item> void </item>
        <item> throw </item>
        <item> typeof </item>
        <item> const </item>
        <item> default </item>
        <item> this </item>
        <item> null </item>
        <item> undefined </item>
        
        <item> class </item>
        <item> export </item>
        <item> declare </item>
        <item> module </item>
        <item> import </item>
        <item> static </item>
        <item> interface </item>
        <item> implements </item>
        <item> constructor </item>
        <item> public </item>
        <item> private </item>
        <item> string </item>
        <item> number </item>
        <item> bool </item>
        <item> any </item>
        <item> extends </item>
        <item> let </item>
    </list>
    
    <contexts>
        <context attribute="Normal Text" lineEndContext="#stay" name="Normal">
            <DetectSpaces/>
            <keyword attribute="Keyword" context="#stay" String="keywords"/>
            <DetectChar attribute="String" context="String" char="&quot;"/>
            <DetectChar attribute="String Char" context="String 1" char="'"/>
            <StringDetect attribute="Reference" context="Reference" String="///" />
            <Detect2Chars attribute="Comment" context="Comment" char="/" char1="/"/>
            <Detect2Chars attribute="Comment" context="Multi/inline Comment" char="/" char1="*" beginRegion="Comment"/>
            <DetectIdentifier/>
        </context>
        
        <context attribute="String" lineEndContext="#pop" name="String">
            <DetectIdentifier/>
            <HlCStringChar attribute="String Char" context="#stay"/>
            <LineContinue attribute="String" context="#stay"/>
            <DetectChar attribute="String" context="#pop" char="&quot;"/>
        </context>
        
        <context attribute="String Char" lineEndContext="#pop" name="String 1">
            <DetectIdentifier/>
            <HlCStringChar attribute="String Char" context="#stay"/>
            <LineContinue attribute="String" context="#stay"/>
            <DetectChar attribute="String Char" context="#pop" char="'"/>
        </context>

        <context attribute="Comment" lineEndContext="#pop" name="Comment">
            <DetectSpaces />
            <IncludeRules context="##Alerts" />
            <DetectIdentifier />
        </context>
        
        <context attribute="Comment" lineEndContext="#stay" name="Multi/inline Comment">
            <IncludeRules context="##Alerts" />
            <Detect2Chars attribute="Comment" context="#pop" char="*" char1="/" endRegion="Comment"/>
        </context>
        
        <context attribute="Reference" lineEndContext="#pop" name="Reference">
            <DetectChar attribute="ReferenceBracket" context="#stay" char="&lt;"/>
            <DetectChar attribute="ReferenceBracket" context="#stay" char="&gt;"/>
            <DetectChar attribute="ReferenceFile" context="ReferenceFile" char="&quot;"/>
            <DetectChar attribute="ReferenceFile" context="ReferenceFile 1" char="'"/>
        </context>
        
        <context attribute="ReferenceFile" lineEndContext="#pop" name="ReferenceFile">
            <DetectIdentifier/>
            <HlCStringChar attribute="ReferenceFile" context="#stay"/>
            <LineContinue attribute="ReferenceFile" context="#stay"/>
            <DetectChar attribute="ReferenceFile" context="#pop" char="&quot;"/>
        </context>
        
        <context attribute="ReferenceFile" lineEndContext="#pop" name="ReferenceFile 1">
            <DetectIdentifier/>
            <HlCStringChar attribute="ReferenceFile" context="#stay"/>
            <LineContinue attribute="ReferenceFile" context="#stay"/>
            <DetectChar attribute="ReferenceFile" context="#pop" char="'"/>
        </context>
    </contexts>
    <itemDatas>
        <itemData name="Normal Text" defStyleNum="dsNormal"/>
        <itemData name="Keyword" defStyleNum="dsNormal" color="#00f"/>
        <itemData name="Char" defStyleNum="dsChar"/>
        <itemData name="String" defStyleNum="dsString" color="#a31515"/>
        <itemData name="String Char" defStyleNum="dsString" color="#a31515"/>
        <itemData name="Comment" defStyleNum="dsNormal" italic="true" color="#080"/>
        <itemData name="Reference" defStyleNum="dsNormal" color="#aeb9ae"/>
        <itemData name="ReferenceBracket" defStyleNum="dsNormal" color="#708870" bold="true"/>
        <itemData name="ReferenceFile" defStyleNum="dsNormal" color="#2c51cc"/>
    </itemDatas>
</highlighting>
<general>
    <comments>
        <comment name="singleLine" start="//" />
        <comment name="multiLine" start="/*" end="*/" />
    </comments>
    <keywords casesensitive="1"/>
</general>
</language>

}}}

== Sample code typescript for browser ==
{{{#!highlight bash
npm install -g typescript
npm install -g webpack 
}}}

=== greeter.html ===
{{{#!highlight html
<!DOCTYPE html>
<html>
    <head><title>TypeScript Greeter</title><meta charset="UTF-8"></head>
    <body>
        <script src="dist/bundle.js"></script>
    </body>
</html>
}}}


=== 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.

{{{
export function getText(){
    return "text";
}
}}}

=== greeter.ts ===
 * import {xyz} from "module";

{{{
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 ===
{{{
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
<!DOCTYPE html>
<html>
    <head><title>React + typescript test</title><meta charset="UTF-8"></head>
    <body>        
        <div id="app"></div>
        <script src="dist/bundle.js"></script>
    </body>
</html>
}}}

=== 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 ===
{{{
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<MyProps, MyState> {
    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 (
            <div>
                <p>Hello World!!! -- {this.text} -- {this.state.greetings}</p>
                <p>Human {this.state.human != null ? this.state.human.getName() : ""} {this.state.currDate} </p>

                <p> <NameHolder attr="holding..." />  </p>
                <p> <NameHolder attr={this.state.currDate} /> </p>

                <div onClick={() => { this.clickHandler(); }} > {this.props.children} </div>
            </div>
        );
    }

    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 ===
{{{
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 = <App prop="Other text inside the page"> <NameHolder attr="NameHolder child inside App "/> </App>;
ReactDOM.render( markup , appContainer);
}}}

=== NameHolder.tsx ===
{{{
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<NameHolderProperties, NameHolderState> {
    constructor(props: NameHolderProperties) {
        super(props); // populates the this.props         
        this.state = { attr: this.props.attr };

        pubSub.addListener(this.onMessage);
    }

    public render() {
        return <span>!!!{this.state.attr}!!!</span>;
    }

    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 ==
{{{
export class Constants {
    static readonly CONST_A = "constA";
    static readonly CONST_B = "constB";
}
}}}