Typescript – Configuring, Compiling and Debugging

Configuring, Compiling, and Debugging TypeScript Projects

Why TypeScript ?

1. Compile-time type checking prevents errors
2. Classes, types and interfaces assist in collaborative development
3. Numerous time saving features for advanced users

Github

Installing TypeScript globally

E:\proj> tsc // is not recognized

npm install -g typescript@latest

tsc -v
Version 3.6.4

npm init -y

E:\proj>npm install --save-dev typescript@latest

Note : global and local installed version must be same

Test through package.json

"scripts" : {
	"test": "tsc -v"
}
E:\proj> npm test //OUTPUT : version 3.7.2

Executing the TypeScript Compiler
Transforms specified TypeScript files into ES5 Javascript files
Example : server/server.ts


const message: string = "Hello TypeScript"
console.log(message)

E:\proj>tsc server/server.ts
E:\proj>node server/server.js
//OUTPUT :
Hello TypeScript !

What is .tsconfig?

1. Defines which TypeScript files should be compiled and the location of the resulting Javascript files
2. Specifies which TypeScript features to use when compiling this particular project

Define compiler options :

- ES interoperablilty ("esModuleInterop" : false)
- Emitting files ("listEmittedFiles":true)
- Strict mode
- Targeting output language

E:\proj> tsc --init
E:\proj> tsc //OUTPUT : server.js file created

Why Configure the TypeScript Compiler ?

 - Optimize build times with cutting-edge features
 - Orgainze generated and source files as desired
 - Configuration can be done once by senior dev and use by all other devs

Example Settings :

 - Organize files ("outDir": "./build/") // all generated files will be moved here .js, .d.ts, .js.map
 - Create declaration files ("declaration" : true)
 - Specify module format
 - Enable source maps ("sourceMap": true)

Extending TypeScript configuration

 - tsconfig.json can extend the configuration of other projects
 - Multiple projects can use single set of base settings
 - Reduces duplication, speeds up maintenance
 - Create secondary Typescript project in same folder
 - Separate Typescript configuration into base settings and project-specific settings
 - Create new configuration files for our new project and existing main project

E:\proj> tsc --p server/tsconfig.json

Configuring a Default Build

>VS Code and tasks.json

 - tasks.json not only stores your porject settings, but alllows you to standardize them across the whole team.
 - specifies which build command to run by default
 - can be checked in with version control (Git, SVN, etc)
 - proper usage reduces onboarding time for new devs
 - use VS Code to automatically create task.json configuration file
 - Select desired task to execute automatically on build

VSCode -> Terminal -> Configure Build Task -> Create Task
To Run Task :
VSCode -> Terminal -> Run Build Task

In Watch Mode :

What Are Project References ?

Project references allow you to logically separate your TypeScript application, allowing for faster compilation and maintenance.
Organizational – Separate business logic into sub-projects
Performant – TypeScript optimizes builds for referenced projects
Simple – Process of referencing projects very similar to standard imports

References is a series off objects which each define an additional project references.

What Are Type Declaration Files ?

 - Type Declaration files usually complement a Javascript library
 - Used by compiler to prevent errors
 - Used by VSCode / Intellisense to provide code hits
 - Create reference to junior project from main project
 - Note that Typescript minimizes amount of code that is recompiled with each build

To create project reference :
1. create a tsconfig.json file in root directory
2. specify the reference project path

{
	"extends": "./tsconfig-base.json",
	"references" : [{
		"path": "./server"
	}]
}

3. add the properties (“composite”:true)in reference project’s tsconfig.json “compilerOptions”
server/tsconfig.json

{
	"extends" : "./../tsconfig-base.json",
	"compilerOptions" : {
		"outDir" : "./../build/server",
		"composite": true
	}
}

it looks like when we said TSC typescript was super helpful and deciders also compile our child server project as its own Typescript program. so it compiled both, even though the contents of server supposed to be compiled into the main package.
4. in the main tsconfig going to add a properties “files:[]”
this tells typescript that off all the typescript files in the project consider none of them to belong personally to this parent project.They are going to belong to whatever child project. The tsconfig is most relevant for now
5. After this references setup
run command : tsc –build, it going to build our child project.
Type Declaration(d.ts) files are a key tool when combining javascript and TypeScript projects

Type Declaration Files from NPM

 - Many libraries(jQuery, d3) not written in TypeScript but may be needed
 - Contributors create declaration files which help compilation and debugging
 - Declaration files may be found with library or central repo

Creating and Configuring Custom Type Declaration Files

Why Create Custom Declaration Files ?

 - Required legacy tools may be ES5
 - Logically organize interfaces and other non-declarative code
 - Provide better code hints through annotations

Demo :
1. Create a new Interface type that will be implemented by both fornt and back end
– Declaration for a “question” format passed from server to client
2. Import reference from type file

Step 1 : create folder “@types” – src/@types
Step 2 : Create declaration file “Question.d.ts”
Step 3 :

export interface Question {
			title: string;
			content: string;
			answerCount?: number;
	}
	

Step 4 : src/server


	import * as express from "express";
import * as path  from "path";
import { Question } from '../@types/question';

/*import { Question } from '../shared/Question';*/

const port : string | number = process.env.port || 1337;
const app = express();

const questions : Question[] = [{
    title: "Are dividends tax deductible?",
    content: "I have recently decided to invest in....",
    answerCount: 2
}];
app.get("/questions", (_req, res) => {

    res.json(questions);
    
});
app.listen(port);
console.info(`App listening on port ${port}!`);

Step 5 :

"scripts" : {
	"build-server" : "tsc -p server",
	"server" : "node build/server/server.js"
}

Step 6 : npm run build-server
Step 7 : npm run serve
Step 8 : http://localhost:1337/questions

Adding Features to TypeScript Application

Add a client directory with code that is meant to be run client’s PC
– Create separate referenced projects for front/back end
Step 1 : Add client folder “client”
Step 2 : Add tsconfig.json
Step 3 : Add compiler options in tsconfig

{
		"extends" : "./../tsconfig-base.json",
		"compilerOptions" : {
			"target":"es5",
			"module":"es6",
			"outDir" : "../build/client"
		}
	}
	

Step 4 : Create new file “client.ts”
Step 5 : make api request from client.ts

import {Question} from "../@types/Question"
	((): void => {
		let questions : Question[] = [];
		async function init() : Promise<void> {
			const request = await fetch("/questions");
			questions = await request.json();
			console.log(questions)			
		}
		init();
	})
	

Step 6 :

"scripts" : {
	"build-server" : "tsc -p server",
	"build-client" : "tsc -p client",
	"server" : "node build/server/server.js"
}

Step 7 : npm run build-client
Step 8 : above command will execute code and create client.js file into build directory
Step 9 : create API end point in server

	app.get("/main.js", (_req, res)=> {
		res.sendFile(path.resolve(__dirname, "..", "client", "client.js"))
	})

Step 10 : npm run build-server
Step 11 : http://localhost:1337/main.js
Step 12 : it will return client.js file on browser
Step 13 : add the main.js in public folder “public/index.html”
Step 14 : add the script file in html file
Step 15 : http://localhost:1337
Step 16 : browser will print the array in console

Advantage of Typscript Debugging

Typescript offers solid protection from compile-time errors. The Debugger allows developers to fix run-time errors as well

Step 1 : Add debugging script in package.json

"script" : {
	"debug": "node --inspect=9227 build/server/server.js"
}

Step 2 : Configure ‘launch.json’
Step 3 : Select Environment “Node.js”
Step 4 : remove default configuration
Step 5 : click “Add Configuration” buttton
Step 6 : Chose process from dropdown : Launch Via NPM

"configurations": [        
		{
            "type": "node",
            "request": "launch",
            "name": "Launch via NPM",
            "runtimeExecutable": "npm",
            "runtimeArgs": [
                "run-script",
                "debug"
            ],
            "port": 9227,
			"sourceMaps": true
            "skipFiles": [
                "/**"
            ]
        }
	]

Step 7 : add debugger in source code
Step 8 : go to debug screen and choose Launch via NVM then click play button
Step 9 : http://localhost:1337/questions, debugger will be triggered

Configuring ESLint

Why do we need linting in addition to type checking ?

Compile-time error checking can not catch certain mistakes like new line and semicolon…etc

Linting catches stylistic errors that type checking does not. Use ESLint to correct code style

Install ESLint

- Download from NPM
- Create a configuration file 
- Integrate with Typescript
npm install --save-dev eslint

To understand eslint understand other than javascript

npm install --save-dev @typescript-eslint/eslint-plugin @typesciprt-eslint/parser

1. add “.eslintrc” file
2. add the script in it

{
	"parse":"@typescript-eslint/parser",
	"estends":{
		"plugin:@typescript-eslint/recommended"
	}	
}

3. add script in package.json

"scripts":{
	"lint": "eslint server/*.ts"	
}

4. run command : npm run lint

Client-side Typescript Debugging with Chrome Extensions – Integrating debug chrome with VSCode

– Server-side applications are run and debugged with Node
– Client applications are run by the browser of the client’s choice and debugged with Chrome

1. Install Chrome Debugger (“Debugger for chrome”) for VSCode
2. Update launch.json
3. click “Add Configuration” on debug and select “Chrome: Launch” from list

{
            "type": "chrome",
            "request": "launch",
            "name": "Launch Chrome",
            "url": "http://localhost:1337",
            "webRoot": "${workspaceFolder}"
        }

4. run server script npm run server
5. add debugger in VSCode
6. npm “run build-client”
7. now go to debug panel run “Launch Chrome”

we can combine the debug commands

 "compounds": [
        {
            "name": "Run and Debug",
            "configurations": ["Launch via NPM", "Launch Chrome"]
        }
    ]

Final : 1. public/index.html


<head>
    <title>Educational Resources Access</title>
    <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet" crossorigin="anonymous">
</head>
<body>
    <div class="container ">
        <div class="header">
            <div >
                <h5 >
                    Educational Resources Access
                </h5>
                <nav >
                    <a  href="#">Archive</a>
                    <a  href="#">Search</a>
                </nav>
                <a href="#">Sign up</a>
            </div>
        </div>
        <section>            
            <form id="QuestionForm">
                <h3 >Ask a Question</h3>
                    <section >
                        <label for="title">Question Title</label>
                        <input type="text" id="firstName" placeholder="" value="My title">
                        <div>
                            Valid title is required.
                        </div>
                    </section>
                    <section>
                        <label for="contents">Your Question</label>
                        <textarea type="text" id="contents">My Question </textarea>
                    </section>                
                    <button type="submit" >Submit</button>
            </form>
        </section>
        <section >
                <h4 >
                    <span>New Questions</span>
                    <span>2</span>
                </h4>
                <ul id="Questions">                    
                </ul>
    </div>
    <script src="main.js"></script>
</body>
</html>

2. src/client/client.ts


import { Question } from '../@types/question';

(() : void => {

    let questions : Question[] = [];
    function render () : void {        
        document.getElementById("Questions").innerHTML = questions.map(
		({title, content, answerCount = 0}) => `
        <li class="list-group-item d-flex ">
            <div>
                <h6 class="my-0">                    
                    ${title}                
                </h6>
                <small class="text-muted">                    
                    ${content}                
                </small>
            </div>
            <span class="text-muted">                
                ${answerCount} Answer${answerCount === 0 || answerCount > 1 ? `s` : ``}
            </span>
        </li>
    `).join("");
    }

    (async function init() : Promise<void> {

        const request = await fetch("/questions");
        questions = await request.json();
        /* debugger; */
        /* Remove comment to trigger breakpoint */
        render();

    })();
    async function handleSubmitQuestionForm () : Promise<void> {
        event.preventDefault();
		
        const title : string = document.forms["QuestionForm"][0].value;
        const content : string = document.forms["QuestionForm"][1].value;

        const request = await fetch(`/new?title=${title}&content=${content}`);
        const json = await request.json();

        questions = json.questions;
        render();
    }
    document.getElementById('QuestionForm').addEventListener("submit", handleSubmitQuestionForm);
})();

Note : add “strictNullChecks”: false in client/tsconfig.json
Apollo Debug

{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "type": "node",
            "request": "launch",
            "name": "Launch Program",
            "skipFiles": [
                "/**"
            ],
            "program": "${workspaceFolder}\\server\\src\\resolvers.ts",
            "outFiles": [
                "${workspaceFolder}/**/*.js"
            ]
        }
    ]
}

Leave a Reply

Your email address will not be published. Required fields are marked *