Tips TypeScript

Berikuta ini beberapa tips untuk TS.

Partial

Pake Partial untuk bikin tipe yang nggak semua field-nya harus diisi.

type User = {
  name: string;
  age: number;
}

// error: Property 'age' is missing in type '{ name: string; }' 
//   but required in type 'User'.ts(2741)
const u1:User = {
  name: 'aaa'
}

// no error
const u2: Partial<User> = {
  name: 'aaa'
}

Required

Ini kebalikan dari Partial. Dipake untuk bikin field yang opsional jadi wajib diisi.

type User = {
  name: string;
  age?: number; //opsional
}

// error: Property 'age' is missing in type '{ name: string; }' 
//   but required in type 'Required<User>'.ts(2741)
const u2: Required<User> = {
  name: 'aaa'
}

Pick

Kita pake Pick untuk bikin tipe yang field-nya sebagian dari type lain.

type User = {
  name: string;
  address: string;
  age: number;
}

// hanya name & address
type UserShort = Pick<User, 'name' | 'address'>

// ga error biarpun tanpa age
const u: UserShort = {
  name: 'aaa',
  address: 'bbb'
}

Omit

Ini fungsinya sama dengan Pick tapi hasilnya kebalikan. Kalo pake Pick kita pilih field yang kita mau, di sini kita pilih field yang kita nggak mau.

type User = {
  name: string;
  address: string;
  age: number;
}

// nggak pake name & address
type UserShort = Omit<User, 'name' | 'address'>

// error
const u: UserShort = {
  name: 'aaa',
  address: 'bbb'
}

// ga error biarpun tanpa name & address
const u2: UserShort = {
  age: 10
}

Data/Tipe yang Read-Only

Untuk bikin sebuah objek jadi immutable (ga bisa diubah isinya), kita bisa pake as const .

const user = {
  name: 'boss',
  age: 30,
  location:{
    city: 'Malang',
    country: 'Indonesia'
  }
} as const;

// error krn semua field di 
//   objek user jadi read-only (const)
user.age = 50;

Kita juga bisa bikin tipe yang sebagian field-nya read-only.

type User = {
  name: string;
  readonly age: number;
  location:{
    readonly city: string;
    country: string;
  }
}

const user: User = {
  name: 'boss',
  age: 30,
  location:{
    city: 'Malang',
    country: 'Indonesia'
  }
};

// ga error krn country ga readonly
user.location.country = 'Thailand'

// ga error krn location ga readonly
user.location = {
  city: 'Sydney',
  country: 'Australia'
}

// error krn field2 ini readonly
user.age = 50;
user.location.city = 'Bangkok'

Untuk field yang tipenya array, biarpun kita bikin readonly kita tetep bisa ngerubah isi arraynya.

type User = {
  readonly skills: string[];
}

const u: User = {
  skills: ['css']
}

// ga error, krn yg readonly 
//  field skills, bukan isinya
u.skills.push('html')

Biar bisa readonly seisi-isinya, kita pake ReadOnlyArray atau Readonly

type User = {
  // sama dengan: readonly skills: Readonly<string[]>;
  readonly skills: ReadonlyArray<string>;
}

const u: User = {
  skills: ['css']
}

// error: Property 'push' does not exist on type 'readonly string[]'
u.skills.push('html')

Membuat Tipe dari Sebarang Data

const myuser = {
  name: 'boss',
  age: 30,
  location:{
    city: 'Malang',
    country: 'Indonesia'
  }
}

// buat tipe User dari objek myuser
type User = typeof myuser;

// error: Property 'age' is missing 
const user2: User = {
  name: 'boss2',
  location:{
    city: 'Jakarta',
    country: 'Indonesia'
  }
}

Membuat Tipe String dengan Template Literal

Dalam contoh di bawah ini, kalo tipe argumennya pake string biasa, semua string bisa masuk handler().

function handler(event: string){
  console.log(`${event} fired`)
}

handler('onclick') // onclick fired
handler('onenter') // onenter fired
handler('hey')     // hey fired

Misalnya kita mau batasin hanya string yang berawalan on yang bisa masuk:

function handler(event: `on${string}`){
  console.log(`${event} fired`)
}

handler('onclick')
handler('onenter')

// error: Argument of type '"hey"' is not assignable 
//   to parameter of type '`on${string}`'
handler('hey')

Atau hanya onclick & onmouseover.

function handler(event: `on${'click'| 'mouseover'}`){
  console.log(`${event} fired`)
}

handler('onclick')
handler('onmouseover')

//error: Argument of type '"onenter"' is 
//  not assignable to parameter of type '"onclick" | "onmouseover"'
handler('onenter')

Hindari Duplikat Tipe dengan Generic

Misalnya kita punya 2 tipe Card yang satu content-nya string, yang lain number. Kita bisa buat dua tipe yang berbeda:

// card yg contentnya string
type Card = {
  title: string;
  content: string;
}

// card yg contentnya number
type CardWithNumber = {
  title: string;
  content: number;
}

const c1: Card = {
  title: 'card1',
  content: 'yo'
}

const c2: CardWithNumber = {
  title: 'card2',
  content: 10
}

Alternatifnya, pake generic.

type Card<T> = {
  title: string;
  content: T;
}

// card yg contentnya string
const c1: Card<string> = {
  title: 'card1',
  content: 'yo'
}

// card yg contentnya number
const c2: Card<number> = {
  title: 'card2',
  content: 10
}