PB138 Lab: Introduction to TypeScript
Node.js
As an asynchronous event driven JavaScriptruntime, Node is designed to build scalablenetwork applications.
npm
is the package manager for JavaScript and theworld's largest software registry.
Initiate npm project
- Creates package.json
-
Package.json contains:
- Project description
- Dependencies
- Runnable commands
npm init
Working with dependencies
npm install -–save-dev typescript
npm i –D typescript
npm install -–save react react-dom
npm i –S typescript react react-dom
Those commands:
- Add entry to package.json
- Create/update lock file
Dev packages only available during develepoment
Regular dependencies also in dist package
Global Dependencies
npm install --global -–save typescript
Installed in node folder
Available as cmd app
In most cases not recommended
Lock file
npm install package-a@3.0.0 --package-lock-only
When packege was installed one day in version 1 on other machine next day could be installed in version 2
Lock prevents it
Also garantues installation order. Npm packages are not necessary installed in same order and this caused problems sometimes.
Carret and tilde
npm install express@latest --save --force
You can you install or update for updating packages
Please not update is not updating dev dependencies unless you add –dev flag
"*"
"^1.4.3" -> match any major 4.x.x
"3.4.1"
"~4.2.1" -> match any minor 4.2.x
Carret and tilde
{
"name": "my-project",
"version": "1.0",
"dependencies": {
// install update
"already-installed-versionless-module": "*", // ignores "1.0" -> "1.1"
"already-installed-semver-module": "^1.4.3" // ignores "1.4.3" -> "1.5.2"
"already-installed-versioned-module": "3.4.1"// ignores ignores
"not-yet-installed-versionless-module": "*", // installs installs
"not-yet-installed-semver-module": "~4.2.1" // installs installs
"not-yet-installed-versioned-module": "2.7.8"// installs installs
}
}
Javascript ES6+ & Typescript
What‘s the difference? (JS vs TS)
Typescript is superset of Javascript. It compiles Javascript but also give you option to use strong typing, additional syntactic suggar and transpiles to supported JS.
Using let and const
vars are hoisted and therefore should be avoided
var is replaced by:
- mutable let
- immutable const
console.log(a); // what value is a here?
a = 5;
var a;
Using let and const
let and const both keep their scope since declaration
const a = 5;
let b = 6;
String templates
- you don‘t have to concatenate strings if you need to add variable content into text
- you can add any JS expression
- you can use also quotes there
let text = `string text ${expression} string text`;
Null assertion
- there is nice syntax to check for null and undefined and get valu
function(input: any) { // we expect some object with value prop
let num: number? = input && input.value;
}
Arrow functions
- shorter function syntax
- no problems with this and binding it
function(input: number) {
return input * 5;
}
can be rewritten to
(input: number): number => ({ input * 5});
Modules
- basic structuring concept of Javascript code
- you can use function from other files or packages
import { ZipCodeValidator as ZCV } from "./ZipCodeValidator";
// or later
const validator = await import { ZipCodeValidator } from "./ZipCodeValidator";
Exports
- export gives option to use function in other file
- default give you fallback or exports single function
export function add(a: number, b: number): number {
return a + b;
}
export default function substract(a: number, b: number): number {
return a - b;
}
// or export default {add};
Classes
- Shall I introduce you to basic OOP concepts?
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() {
return "Hello, " + this.greeting;
}
}
let greeter = new Greeter("world");
Abstract classes
- They can‘t be instantiated.
abstract class Greeter {
// same code as previous example
}
let greeter = new Greeter("world"); // can‘t do this!!!
class MyGreeter extends Greeter {
// some additional code
}
let greeter = new MyGreeter("world"); // possible now
Interfaces
- You define variables and DECLARE functions.
- Used either for polymorphism or as a „structures“
interface IGreeter {
greeting: string;
greet();
}
class Greeter implements IGreeter { }
Abstract or interface?
Mostly use interfaces
Avoid abstract classes
Class inheritance?
Try to avoid it
Also avoid base classes in most cases
Try to use aggregates
Spread operator
- Used on arrays, objects or functions
- Copy object, change props immutably, merge arrays…
let obj1 = { foo: 'bar', x: 42 };
let obj2 = { foo: 'baz', y: 13 };
let clonedObj = { ...obj1 };
// Object { foo: "bar", x: 42 }
let mergedObj = { ...obj1, ...obj2 };
// Object { foo: "baz", x: 42, y: 13 }
Destructuring
- Same operator as spread
- It gets you variables from same structure/object
var o = {p: 42, q: true};
var {p: foo, q: bar} = o;
console.log(foo); // 42
console.log(bar); // true
var {a = 10, b = 5} = {a: 3};
console.log(a); // 3
console.log(b); // 5
map()
every()
filter()
find()
findIndex()
reduce()
some()
Iterate through array
Async/await
There are synchronous and asynchronous operations.
Like: working with file system, network requests, ...
Before request is fulfilled (a lot of waiting involved), system can do other stuff. This is why you need async.
Promise
const myPromise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('foo');
}, 300);
});
myPromise
.then(handleResolvedC, handleRejectedC);
myPromise
.then(handleResolvedC)
.catch(handleRejectedAny);
Async/await
function resolveAfter2Seconds() {
return new Promise(resolve => {
setTimeout(() => {
resolve('resolved');
}, 2000);
});
}
async function asyncCall() {
try {
console.log('calling');
const result = await resolveAfter2Seconds();
console.log(result);
} catch (e) {
// ...
}
}
ORM
= object-relational mapping
- Usually, there is no need to write SQL with ORM.
- But it can lead to inefficient queries
- For complex things or perf optimizations, there is still a need to write SQL by hand
- ORN helps to avoid common vulnerabilities
Prisma
one of better Node ORM tools
It is written in Rust btw.
Install to project
npm install prisma -D
npx prisma init
This creates .env and schema.prisma files.
.env
DATABASE_URL = 'postgresql://johndoe:randompassword@localhost:5432/mydb?schema=public'
Important: do NOT commit this to source control
schema.prisma
model Post {
id Int @default(autoincrement()) @id
title String @db.VarChar(255)
createdAt DateTime @default(now()) @db.Timestamp(6)
content String?
published Boolean @default(false)
author User @relation(fields: [authorId], references: [id])
authorId Int
}
model Profile {
id Int @default(autoincrement()) @id
bio String?
user User @relation(fields: [userId], references: [id])
userId Int @unique
}
model User {
id Int @default(autoincrement()) @id
email String @unique @db.VarChar(255)
name String? @db.VarChar(255)
posts Post[]
profile Profile?
}
Setup node part
npm install @prisma/client
npx prisma generate
index.ts
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
async function main() {
// ... you will write your Prisma Client queries here
}
main()
.catch(e => {
throw e
})
.finally(async () => {
await prisma.$disconnect()
})
select
async function main() {
const allUsers = await prisma.user.findMany()
console.log(allUsers)
}
insert
async function main() {
await prisma.user.create({
data: {
name: 'Alice',
email: 'alice@prisma.io',
posts: {
create: { title: 'Hello World' },
},
profile: {
create: { bio: 'I like turtles' },
},
},
});
}
update
async function main() {
const post = await prisma.post.update({
where: { id: 1 },
data: { published: true },
})
console.log(post)
}
That's it. Now let's write some code
PB138 Lab: Introduction to TypeScript
By Lukáš Grolig
PB138 Lab: Introduction to TypeScript
- 375