Home

Typescript

Installation

npm i -g typescript // global installation

or

npm i -D typescript

Create Configuration file

tsc --init

or

npx tsc --init // if typscript is installed locally

Example entries:

{
"compilerOptions": {
    "target": "ES6",
    "module": "commonjs",
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true
},
"include": ["src"],
"exclude": ["node_modules"]
}

Compilation

tsc --watch

or

npx tsc --watch

Without tsconfig.json

tsc src/index-ts --watch // file to compile

Setting Up An NPM Project

Normal setup with outDir: ./dist and rootDir: ./src

npm install -D typescript // Install typescript

npx tsc --init // Generate a tsconfig.json file

npm install -D @types/node // Install type definitions for node

With nodemon

Two terminals are needed

package.json

"scripts": {
  "build": "tsc",
  "watch": "tsc --watch",
  "start": "node dist/main.js",
  "dev": "nodemon --watch dist --exec 'node dist/main.js'"
}

To start, in terminal 1: npm run watch, in terminal 2: npm run dev

With concurrently

Only one terminal needed

npm install -D concurrently

package.json

"scripts": {
  "build": "tsc",
  "watch": "tsc --watch",
  "start": "node dist/main.js",
  "dev": "concurrently 'npm:watch' 'nodemon dist/main.js'"
}

Start with npm run dev

With tsx

Runs typescript without compilation (it’s a newer alternative for ts-node, which has issues with node v20+)

npm install -D tsx

Create a tsconfig.json

npx tsc --init

package.json

"scripts": {
  "build": "tsc",
  "start": "node dist/main.js",
  "dev": "tsc --noEmit && tsx ./main.ts"
}

Start with npm run dev

Basic Types

Explicit set data types if they can’t be inferred by TypeScript

const age: number;
const name: string;
const isAdmin: boolean;
const something: unknown; // will be defined later
const myArray: string[];
const myObj: {
  name: string,
  age: number,
  phone?: string // "?" marks as not required
}
const myVar: any; // not recommended, allows any type

// union types 
const age: string | number
const myArray: (string | number)[]

// non-null assertion operator (!)
// Tell the compiler the variable is not null or undefined even if typescript cannot infer from the code
const id!: number;

Functions

// Function with no return or undefined return
function logName(name:string):void {
 console.log(name);
}

// Function with no return not even undefined
function logName(name:string):never {
 throw new Error(`Function without a return`);
}

// Function with optional parameter
function logName(num1:number, num2?:number){ // return value is inferred
 return num1;
}

Type Alias

// object
type userType = {
  name: string,
  age: number,
  phone?: string,
  theme: "dark" | "light"
}

myFunction(user:userType){
  console.log(user.name);
}

// function
type myFunc = (a:number, b:string) => void;

const printOut: myFunc = (num, str)=>{
  console.log(num + "times" + str);
}

Interface

Similar to types but can be extended

interface User {
  name: string,
  email: string,
  age: number
}

interface Employee extends User {
  employeeId: string
}

const employee: Employee = {
  name: "John",
  email: "john@work.com",
  age: 50,
  employeeId: "sskl1000"
}

Generics

Data changing the type based on what is returned

// Name inside of "<>" is random but often as "T"
function getFirstElement<T>(array: <T>[]){
  return array[0];
}

// or as an arrow function
const getFirstElement = <T>(array:<T>[]) => array[0]

const firstNum = getFirstElement([1, 2, 3]);
const firstStr = getFirstElement(["a", "b", "c"]);

type ApiResponse<Data> = {
  data: <Data>,
  isError: boolean
}

const response: ApiResponse<{name: string, age: number}> = {
  data: {
    name: "John",
    age: 40
  },
  isError: false
}

Record

Record<K, V> is a more generic type that allows to dynamically define the structure of an object without explicitly listing all of the keys

  • K: The type of the keys of the object (often a string or number).
  • V: The type of the values associated with those keys.

Record can be used when a mapping object is created where the keys are of a certain type and the values are of a uniform type, but you don’t know or want to list all the keys in advance

const users: Record<string, { name: string; age: number }> = {
  "user1": { name: "Alice", age: 25 },
  "user2": { name: "Bob", age: 30 }
};

// Possible use case: Mapping User IDs to User Objects
interface User {
  id: string;
  name: string;
  email: string;
}

const users: Record<string, User> = {
  "user1": { id: "user1", name: "Alice", email: "alice@example.com" },
  "user2": { id: "user2", name: "Bob", email: "bob@example.com" },
  // More users can be added dynamically
};

TypeScript Definitions (for installed packages)

  1. Some packages include their own definitions (e.g. axios, no extra installation needed)

Built-in types have a types or typings filed in in the package.json, pointing to a .d.ts file

"types": "index.d.ts"

  1. Packages without built-in definitions have type definitions published as @types/

npm install @types/express

  1. Some packages may not have built-in types and may not have a corresponding @types/ package

Typical warning message: Could not find a declaration file for module ‘some-new-library’.

Solution: declare the module as any in a declaration file (e.g., global.d.ts):

declare module 'some-new-library';

React

Put types in a separate folder: src/types/types.ts and import them where needed

export type PostProps = {
  id: number,
  title: string,
  body: string
}

// Props
const PostCard = ({title, body}:PostProps) => {...}

// Map
const data: PostProps = await getData();
{data.map((post)=>(
  <PostCard key={post.id} {...post}/>
))}

Children Props

const Parent = ({children}:{children:React.ReactNode}) => {...}

Click Events (hover over “click” in event to see the type)

const handleClick = (event:React.MouseEvent<HTMLButtonElement>)=>{}

Example for event with target.id

// Here HTMLHeadingElement is used because the onClick is on a header (h2)
function handleClick(evt: React.MouseEvent<HTMLHeadingElement>){
        const target = evt.target as HTMLHeadingElement; /use type assertion
        console.log(target.id);
}

<h2 onClick={handleClick}>Title</h2>

Change Events (hover over “change” in event to see the type)

const handleChange = (event:React.ChangeEvent<HTMLInputElement>)=>{}

useState

type UserType = {sessionId:string, name:string);

const [user, setUser] = useState<UserType | null >(null);

Express

Dependencies/Type Definitions:

npm install -D typescript @types/node @types/express @types/mongoose ts-node-dev

ts-node-dev: Automatically restarts the server on changes while compiling TypeScript.