Advanced Typescript
Jump to navigation
Jump to search
Advanced Typescript
Advanced Typescript Training Materials
Copyright Notice
Copyright © 2004-2023 by NobleProg Limited All rights reserved.
This publication is protected by copyright, and permission must be obtained from the publisher prior to any prohibited reproduction, storage in a retrieval system, or transmission in any form or by any means, electronic, mechanical, photocopying, recording, or likewise.
Introduction
- Overview of TypeScript features and advantages
- Programming best practices and tips
- We'll cover some of them during the day
Getting Started
- Installing TypeScript, Nodejs, and Visual Studio Code
- Initializing the server
- Configuring access modifiers and compiler options
- Setting up a Node.js project
- Building and debugging Node.js TypeScript
Configuring access modifiers and compiler options
- Example with Angular - jwt
- Related docs - aka.ms/tsconfig.json
Setting up a Node.js project
- Example - other_/node_/
Configuring Webpack and TypeScript
- Enabling source maps
- Using third-party libraries
- Importing non-code assets
- Building the application
Initial setup
- Exercise - webpack_/with_ts
- Compiler and loader
npm install --save-dev typescript ts-loader
- Directories and configuration
- index.ts - new file with content from 'index.js' and change first line:
import * as _ from 'lodash';
- tsconfig.json - 'tsc --init' and later apply these changes
{ "compilerOptions": { "outDir": "./dist/", "noImplicitAny": true, "module": "es6", "target": "es5", "jsx": "react", "allowJs": true, "moduleResolution": "node" } }
- webpack.config.js
const path = require('path'); module.exports = { entry: './src/index.ts', module: { rules: [ { test: /\.tsx?$/, use: 'ts-loader', exclude: /node_modules/, }, ], }, resolve: { extensions: ['.tsx', '.ts', '.js'], }, output: { filename: 'main.js', path: path.resolve(__dirname, 'dist'), }, };
- index.ts - new file with content from 'index.js' and change first line:
Enabling source maps
- Exercise - webpack_/with_ts
- TypeScript will output inline source maps to our compiled JavaScript files
- tsconfig.json - uncomment line with
"sourceMap": true,
- Telling webpack to extract source maps and include in final bundle
- webpack.config.js - put this just below entry:
devtool: 'inline-source-map',
- webpack.config.js - put this just below entry:
Using third-party libraries
- When installing new lib from npm
- Always remember to install it's typing definition (.d.ts files)
- Definitions can be found here Types for TS
- Example -
npm install --save-dev @types/lodash
- Exercise - install jquery with it's typings
- when we click on our div it should shout with popup: "TS rulezzzzz!"
Importing non-code assets
- We need to defer the type
- custom.d.ts - new file
- example setup for .svg
declare module '*.svg' { const content: any; export default content; }
- Same concept applies to other assets - CSS, SCSS, JSON, etc
- Exercise - setup for .jpg and add bear.jpg in our div
- webpack.config.js - add this to rules array
{ test: /\.(png|svg|jpg|jpeg|gif)$/i, type: 'asset/resource', },
- index.ts - new image element
//// at the top import MyBear from './bear.jpg'; (...) //// in 'component()' function // Add the image to our existing div const myIcon = new Image(); myIcon.src = MyBear; element.appendChild(myIcon);
- webpack.config.js - add this to rules array
Building the application
- Some good practices (performance, etc)
npm run build
npm run start
- Homework: read carefully npm run build result messages
- add lazy loading via import()
- improve it with async-await
Creating Custom Data Types
- Union, Intersection, and Tuple Types
- Type Guards, Type Casting, and Type Assertions
- Creating arrays for custom types
- Other types and examples
Custom Data Types
- Usually a combination of primitive types (strings, numbers, Booleans) with objects
- Building blocks of advanced types – type alias, string, and number literals
- Allow to write code
- easier to understand for myself and easier to work with
- and for any others working with me
- or those who are inheriting the project
- Oftenly web applications become more complex
- it is necessary to be able to model that complexity
- TypeScript makes that easy with advanced types
- types that are conditional and flexible
Type Aliases
- Allow to declare references to any type – advanced or primitive
- Make code easier to read - allow to be less verbose
- We declare our type once and reuse it throughout application
- Code is more readable and maintainable
- Syntax:
type OnlyStrings = string;
- The type keyword is followed by the alias, OnlyStrings, and then the string type
- Exercise - customdt_/exerc_/ex1
Type Literals
- Allow to create a type based on a specific string or number
- Not very useful in itself, but with more complex types such as union types
- Syntax:
type Success = 200;
- Example - customdt_/examp_/e2
- Exercise - customdt_/exerc_/ex2
Intersection
- Allows to combine types to form a new type
- with the properties of the combined types
- it is an and type
- Similar to multi-class inheritance
- child object can have more than one parent object that it derives its properties from
- Helps to keep the cod DRY (Don't Repeat Yourself)
- Merged properties should be of the same type
- Syntax:
type CourseEvaluation = TrainingEvaluationForm & CourseEventEvaluationByTrainer;
- Example - customdt_/examp_/e3
- Exercise - customdt_/exerc_/ex3
Union
- Similar to intersection
- but it is an or type
- do not merges types
- Similar to the ternary operator in JavaScript
- types are separated by the | (pipe)
- Syntax:
type Lead = General | Price | Course;
- Example - customdt_/examp_/e4
- Exercise - customdt_/exerc_/ex4
Index Types
- Allow to create objects with flexible number of properties
- We define a signature for our type using an interface
- Syntax:
[ msg: number ]: string;
- Example - customdt_/examp_/e5
- Exercise - customdt_/exerc_/ex5
Tuple
- Array which contains multiple types
- fixed indexed order - the order and length are guaranteed
- data is connected with less syntax than keyed objects
- A good pattern for short bits of connected data or for fixtures
- Example from 'Reactjs' - useState returns a tuple of the value and a setter function
- Syntax:
const closedLead: [Invoice, Payment] = ["Consultancy23032021", {paid:1, paymentType:"transfer"} ];
- Example - customdt_/examp_/e6
- Exercise - customdt_/exerc_/ex6
Type Guards
- Participate in the code flow analysis
- We influence the code flow
- TS uses existing JS behavior which validates our objects at runtime
- We can prep also custom functions - type predicate functions
- Syntax/operators - in, instanceof, typeof, is
- Full list of possible typeof values developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof
- Example - customdt_/examp_/e7
- Exercise - customdt_/exerc_/ex7
Type Casting, Assertions
Two syntaxes
- xml <> - this way won't work with JSX (.tsx, etc.) and Reactjs
- ... as ...
Generics
- Generics basics
- Example - customdt_/examp_/e8_
- Exercise - together with 'Conditional Types'
Conditional Types
- Allow complex type expressions
- drive some of the built-in types
- Really powerful - allow to write logic inside our types
- Similar to the regular JS ternary operator (inline conditions)
- differences: in the syntax (extends keyword), check is done at compile time and not runtime
- Syntax:
T extends U ? X : Y
- Example - customdt_/exerc_/e9
- Exercise - customdt_/exerc_/ex8_9
Applying Decorators
- Enabling decorators
- Creating class, parameter, and method decorators
- Using property descriptors
- Using metadata
Reflection, tightly coupled with
- Reflection is the capability of a certain piece of code to examine and be introspective about itself (navel-gazing)
- a piece of code can have access to things such as the variables, functions, and classes defined inside it
- Most languages provide some kind of reflection API that enables us to treat the code itself as if it was data
- TypeScript is built upon JavaScript - inherits the JavaScript reflection capabilities
Decorators intro
- Decorators (from js proposal)
- can be used to metaprogram and add functionality to a value
- without fundamentally changing its external behavior
- Have three primary capabilities
- Can replace the value that is being decorated with a matching value that has the same semantics
- e.g. a method with another method, a field with another field, a class with another class, etc
- Can provide access to the value that is being decorated via accessor functions (can be shared)
- Can initialize the value that is being decorated, running additional code after the value has been fully defined
- when the value is a member of class, initialized once per instance
- Can replace the value that is being decorated with a matching value that has the same semantics
Decorators intro con't
- Special kind of declaration
- Can be attached to
- a class declaration, method, accessor, property, or parameter
- Uses @expression
- expression must evaluate to a function
- such function will be called at runtime with information about the decorated declaration
- To transpile
tsc --target ES5 --experimentalDecorators
- tsconfig.json
"experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
Decorator types, syntax
@ClassDecorator
class ExampleClass {
@PropertyDecorator
public exampleProperty:number = 0;
private _exampleField: number = 0;
@AccessorDecorator
public get exampleField() { return this._exampleField; }
@MethodDecorator
public exampleMethod(@ParameterDecorator paramName: string) {}
}
//// 'PascalCase' instead of 'lowerCamelCase'
function ClassDecorator (constructor: Function) {}
function AccessorDecorator (target: any, propertyName: string, descriptor: PropertyDescriptor) {}
function MethodDecorator (target: any, propertyName: string, descriptor: PropertyDescriptor) {}
function PropertyDecorator (target: any, propertyName: string) {}
function ParameterDecorator (target: any, propertyName: string, parameterIndex: number) {}
Class Decorator
interface Invoice {
id: string;
clientId: number;
}
interface HasNewProperty {
newProp: string;
}
// decorator definition can look like this
function SignedInv<T extends {new(...args:any[]):{}}>(constructor:T) {
// return class extends constructor {
return class extends constructor implements HasNewProperty {
newProp = "new prop";
invSign = "my_new_name_template";
}
}
// Decorator 'factory' - common practice to pass custom params
function InvoiceDescr(limit: number) {
return function (constructor: Function) {
constructor.prototype.invType = 'Consultancy' + limit
}
}
@SignedInv
@InvoiceDescr(3)
class FranchiseeAccountancyTool {
private _invoice;
invSign: string;
constructor(public accToolKey: string, public taxRate: string) {
this.invSign = accToolKey + 'inv_code';
}
get invoice() {
return this._invoice;
}
set invoice(inv: Invoice) {
this._invoice = inv;
}
}
let franAcc = new FranchiseeAccountancyTool('cnaj837tjdhsu#jd9_fd8', '204');
console.log(franAcc);
console.log(franAcc.invSign);
console.log(franAcc.newProp);
console.log(franAcc.invType);
Class Decorator examples
- decorators_
- In 'Angular' application
- Angular_2_Fundamentals#Example_1_.E2.8C.98
- jwt example - angular-login-jwt
Decorator exercises
- Ex 1-5 (class, method, accessor)
- Act1
- Ex 6-8 (field, param)
- metadata, with 'reflect-metadata' pollyfill-lib
- Act2
Implementing Asynchronous Code and APIs
- Using callbacks, promises, and async/await
- Writing a REST API with Node.js and TypeScript
Using callbacks, promises, and async/await
- JavaScript runtime is single threaded (on both web browser and server via node)
- One, and only one, piece of code will be running at a particular time - main thread
- JavaScript has also been built around an asynchronous approach
- main thread will not pause when requested to load a resource of some sort
- will place request onto an internal queue, eventually be processed at a later point in time
- it does take away the need for in-memory locking mechanisms (other languages)
Callbacks, promises, and async/await con't
- The callback mechanism - we provide a callback function to an asynchronous request
- it will be executed once the asynchronous request has been processed
- The Promise mechanism - provides a simplified syntax for writing asynchronous code
- allows to chain multiple asynchronous calls one after another (fluent syntax)
- Async and await technique - we mark certain functions as asynchronous
- use the await keyword to pause the execution flow until the asynchronous function returns
Callbacks, promises, and async/await examples
- Callbacks
- async_/examp_/callbacks
- Promises
- async_/examp_/promises
- Async/await
- async_/examp_/async_and_await
- Comparison of all approaches
- async_/examp_/callback_vs_..
Callbacks, promises, and async/await exercises
- Callbacks - async_/exerc_/ex1
- Promises - async_/exerc_/ex2
- Optional - async_/exerc_/a2
- Ex3 - async/await
- Optional - async_/exerc_/a3
Writing a REST API with Node.js and TypeScript
- REST is a very common standard for web traffic
- Most websites and web APIs operate using REST
- Representational State Transfer
- Defines concepts
- operations ("methods" or "verbs") - GET, DELETE, POST, PUT, and PATCH
- resources ("path" or "noun")
- Example - server - rest_/e1
- Exercises - client - rest_/ex1
- Add missing functionalities
- Reactjs - deleteOne, searchBy - other_/fe_/react-api-call-ts
- Discussion/homework - migrate from JS to TS - other_/be_
- Add missing functionalities