A Typescript cheat sheet repository
- Typescript
- Table of Contents
- HOW TO RUN this project
- Install Typescript
- File extensions
- Compile
- Run
- Run with nodemon
- Config file
- Basic Types
- Union
- Objects
- Array of my defined objects
- Functions
- Interfaces
- Function interfaces
- Type assertion
- Classes
- Extending Classes
- Class Interface
- Generics
- Enum
- Pick and Omit
- Partial and Required
- Record
- Exclude
- ReturnType
- Parameters
- Readonly
- keyof
- Optional Chaining
- Nullish Coalescing
- Null Assertion
- Definitely Typed
- Template Literal Types
- Resources
Make sure you have Node.js installed on your machine
-
Clone the repository and
cd
into it:git clone https://github.com/emanuelefavero/typescript.git cd typescript
-
Install the dependencies:
npm install
-
Run the typescript file:
npm run dev
-
Globally:
npm install -g typescript
-
Or locally in your project (better for version control and teams):
npm install --save-dev typescript
.ts
.tsx
(for react jsx files)
TIP: You can use
tsc --init
to generate atsconfig.json
file with default settings
-
Compile typescript files to javascript
tsc --watch
-
Use
nodemon
in another terminal to automatically run the compiled javascript file after each changenodemon index.js
-
You can also use
ts-node
to run typescript files directly without compiling them firstnpm install -g ts-node ts-node index.ts
-
Node.js v24
supports typescript natively, so you can run typescript files directly withoutts-node
ortsc
BEWARE: Some typescript features are not supported yet in Node.js, as typescript will run in
strip-only mode
node index.ts
This is the easiest way to develop typescript files, as it will automatically restart the server when you make changes
nodemon index.ts
Note: If you get an error when running nodemon with typescript files, make sure you also have
ts-node
installed with:npm install -g ts-node
- You can generate the config file with
tsc --init
- Config file:
tsconfig.json
- use the tsconfig file in this repo as a reference
- specify the
outDir
to compile to a specific folder - specify the
rootDir
to compile from a specific folder - tell typescript to compile to es6 with
target: "es6"
let number: number = 32
let string: string = 'John'
let boolean = true
let any: any = 'this could be any type'
let arrayOfNumbers: number[] = [1, 2, 3]
let arrayOfStrings: string[] = ['a', 'b', 'c']
let arrayOfAny: any[] = [1, 'a', true]
let arrayOfObjects: object[] = [{ a: 1 }, { b: 2 }]
let tuple: [string, number] = ['a', 1]
let tupleArray: [string, number][] = [
['a', 1],
['b', 2],
]
let union: string | number = 'a'
union = 1
TIP: You can also use interfaces (interface User {...}) -see below
type User = {
name: string
age: number
}
const user: User = {
name: 'Jack',
age: 32,
}
use this instead of
{}
**
interface User = Record<string, never>
interface User = {
[key: string]: any
}
interface User = {
name: string
age?: number
}
interface User = {
readonly id: number
}
const arrayOfUsers: User[] = [
{
name: 'Jack',
age: 32,
},
{
name: 'John',
age: 47,
},
]
function add(a: number, b: number): number {
return a + b
}
const subtract = (a: number, b: number): number => a - b
function log(message: string | number): void {
console.log(message)
}
TIP: Useful when declaring objects
interface UserInterface {
// define a readonly property (the id cannot be reassigned, e.g. user1.id = 2)
readonly id: number
name: string
// define an optional property (the age property is optional)
age?: number
}
const user1: UserInterface = {
id: 1,
name: 'John',
}
user1.age = 47
TIP: Define the shape of a function
interface MyMathFunction {
(a: number, b: number): number
}
// When implementing a function from an interface, all types must match the interface
const multiply: MyMathFunction = (a: number, b: number): number => a * b
let customerID: any = '123'
// Treat customerID as a number
let customerIDAsNumber = customerID as number
// Alternatively, you can use the angle-bracket syntax (not always recommended, especially in JSX files):
// let customerIDAsNumber2 = <number>customerID
TIP: Try to avoid using
any
type as much as possible
class Person {
constructor(public id: number, public name: string) {}
register() {
return `${this.name} is now registered`
}
}
const person1 = new Person(1, 'Jack')
const person2 = new Person(2, 'John')
-
use the one you prefer
class Person { id: number name: string constructor(id: number, name: string) { this.id = id this.name = name } }
-
property that can not be modified
class Person { constructor(public readonly name: string) {} }
-
property that can only be accessed within the class
class User { private _fullName: string = '' }
TIP: class properties are public by default. We can also define protected properties (those will be only accessible within the class and its subclasses)
e.g.
protected _fullName: string = ''
-
property that can only be accessed without creating an instance of the class
class User { static userName = 'John' } User.userName
class User {
private _fullName: string = ''
get fullName(): string {
return this._fullName
}
set fullName(value: string) {
this._fullName = value
}
}
const user1 = new User()
user1.fullName = 'John Doe'
console.log(user1.fullName)
Getters and setters can be used to perform additional tasks when a property is accessed or modified
class Employee extends Person {
constructor(id: number, name: string, public position: string) {
super(id, name)
}
// Overriding a method
register() {
return `${this.name} is now registered as an employee`
}
}
const employee1 = new Employee(1, 'James', 'Developer')
interface FruitInterface {
name: string
isFavorite: boolean
favorite(): string
}
class Fruit implements FruitInterface {
constructor(public name: string, public isFavorite: boolean) {}
favorite() {
if (this.isFavorite) {
return `${this.name} is my favorite fruit`
} else {
return `${this.name} is my NOT favorite fruit`
}
}
}
const banana = new Fruit('banana', false)
const mango = new Fruit('mango', true)
-
allow us to create reusable components that can work with any data type
<T>
is a placeholder that allows to later define the type of the genericfunction getId<T>(id: T): T { return id } const numberId = getId<number>(1) // this function call will only accept numbers const stringId = getId<string>('1') // this function call will only accept str
-
Allows to define a set of enumerated named constants
enum Color { Red, Green, Blue, } let color: Color = Color.Blue // 2 let colorName: string = Color[2] // 'Blue' enum Color2 { Red = 1, Green, Blue, } let color2: Color2 = Color2.Blue // 3 enum Color3 { Red = '#ff0000', Green = '#00ff00', Blue = '#0000ff', } let color3: Color3 = Color3.Blue // '#0000ff'
-
Pick
: create a new type from an existing type by picking some properties -
Omit
: create a new type from an existing type by omitting some propertiesinterface User { id: number name: string lastName: string age?: number } type Username = Pick<User, 'name' | 'lastName'> type UserWithoutId = Omit<User, 'id'>
-
Partial
: allows to make all properties of an object type optional -
Required
: allows to make all properties of an object type requiredinterface User { id: number name: string lastName?: string // optional property age?: number // optional property } // All properties are optional in PartialUser type type PartialUser = Partial<User> // All properties are required in RequiredUser type type RequiredUser = Required<User>
-
Record
: allows to create an object type with a specific set of keys and valueslet products: Record<string, number> = { 'MacBook Air': 12, 'AirPods Pro': 18, }
-
Exclude
: creates a new type by excluding specified types from a union typetype Theme = 'light' | 'dark' | 'system' let themeSwitch: Exclude<Theme, 'system'> = 'light' // light | dark
-
ReturnType
: allows to extract the return type of a function typefunction getUser(): { name: string; age: number } { return { name: 'Jane', age: 28, } } let userReturnType: ReturnType<typeof getUser> = { name: 'Bob', age: 25, }
-
Parameters
: allows to extract the parameter types of a function typefunction add2(a: number, b: number): number { return a + b } let addParams: Parameters<typeof add2> = [5, 10] // [number, number] // Use addParams to call the function let sum = add2(...addParams) console.log(sum) // 15, (5 + 10)
-
Readonly
: allows to create a type with all properties of an object type as read-onlyinterface Username2 { firstName: string lastName: string } let user4: Readonly<Username2> = { firstName: 'John', lastName: 'Doe', } // Error: Cannot assign to 'firstName' because it is a read-only property: // user4.firstName = 'Jane'
-
keyof
: creates a union type of the keys of an object typefunction printUser(user: User, key: keyof User) { console.log(`User ${key}: ${user[key]}`) } printUser(user, 'name') // User name: Jack printUser(user, 'age') // User age: 32
-
?.
: allows to safely access nested properties of an object without throwing an error if a property isundefined
ornull
interface Address { street?: { name: string number: number } } const address: Address = { street: { name: 'Main St', number: 123, }, } const streetName = address.street?.name // 'Main St'
-
??
: allows to provide a default value when a variable isnull
orundefined
const userAge = user.age ?? 18 // if user.age is null or undefined, use 18
-
!
: allows to assert that a variable is notnull
orundefined
const streetNumber = address.street!.number // using ! asserts that street is not null or undefined
-
Definitely Typed is a repository of high-quality TypeScript type definitions for popular libraries and frameworks.
-
You can install types for a library using npm:
npm install --save-dev @types/library-name
TIP: VSCode will often suggest installing types for libraries you use, so you can just click on the suggestion to install them.
-
Template literal types allow you to create string types that are based on other string types, similar to template literals in JavaScript.
type Greeting = `Hello, ${string}` // Hello, followed by any string let greeting: Greeting = 'Hello, John' // valid // let invalidGreeting: Greeting = 'Hi, John' // invalid, will cause a type error