[typescript] Advanced types

Suyeon·2020년 11월 12일
0

Typescript

목록 보기
7/12

Intersection Type

It allows to combine multiple types.

// 1️⃣ Object
type Admin = {
   name: string;
   priviledges: string[];
}

type Employee = {
   name: string;
   startDate: Date;
}

type ElevatedEmployee = Admin & Employee; // (*)

const el = ElevatedEmployee {
   name: 'Suyeon',
   priviledges: ['create-server'],
   startDate: new Date()
};

// 2️⃣ Any value
type Combinable = string | number;
type Numeric = number | boolean;
type Universal = Combinable & Numeric; // (*)

Alternative
you can also implement it using interface

interface Admin {
   name: string;
   priviledges: string[];
}

interface Employee = {
   name: string;
   startDate: Date;
}

interface ElevatedEmployee extends Admin,  Employee {}

Type Guards

When you want to implement different actions based on types(type checking).

1️⃣ typeof

type Combinable = string | number;

function add(a: Combinable, b:Combinable) {
  if(typeof a === 'string' && typeof b === 'string') { // (*)
     return a.toString() + b.toString();
  }
  return a + b;
}

2️⃣ property in obj

type Admin = {
   name: string;
   priviledges: string[];
}

type Employee = {
   name: string;
   startDate: Date;
}

type ElevatedEmployee = Admin & Employee; 
type UnknownEmployee = Employee | Admin; 

function printEmployee(emp: UnknownEmployee) {
   if('priviledges' in emp) { // (*) if(emp.priviledges) not working!
      console.log(emp.priviledges);
   }
}

3️⃣ instanceof

  • class works but not interface.
class Car {
   drive() {
      console.log('driving...');
   }
}

class Truck {
   drive() {
      console.log('driving a truck...');
   }
  
   loadCargo(amount: number) {
       console.log('Loading cargo...' + amount);
   }
}

type Vehicle = Car | Truck;

const v1 = new Car();
const v2 = new Truck();

function useVehicle(vehicle: Vehicle) {
   vehicle.drive();
  
   if(vehicle instanceof Truck) { // (*)
      vehicle.loadCargo(1000);
   } 
  
  // OR if('loadCargo' in vehicle)
} 

4️⃣ Descriminated unions

  • It is useful when working with object and union type.
  • Give common property interface or an object to distinguish them.
interface Bird {
  type: 'bird'; // (*) Literal type. Namining(type) is up to you.
  flyingSpeed: number;
}

interface Horse {
  type: 'horse'; 
  runningSpeed: number;
}

type Animal = Bird | Horse;

function movingAnimal(animal: Animal) {
   let speed;
   switch(animal.type) { // (**)
     case 'bird':
       speed = animal.flyingSpeed;
       break;
     case 'horse':
       speed = animal.runningSpeed;
       break;
   }
  
  console.log(speed);
}

movingAnimal({ type: 'bird', flyingSpeed: 10 });

Type Casting

When you want to inform TS that a centain value is of a specific type.

  • ! tells typescript that it will never return null(we know it exists).
  • Typescript doesn't know specific html element when select them by an id or etc not by html tag (it recognize as HTMLElement).
  • It provides <> syntax or as syntax.
<input type="text" id="userName" />
/* Not working
const userName = document.querySelector('userName')!;  // HTMLElement 
userName.value = 'Suyeon';
*/

// 1️⃣ <> syntax
const userName = <HTMLInputElement>document.querySelector('userName')!; 

// 2️⃣ as syntax
const userName = document.querySelector('userName')! as HTMLInputElement; 
userName.value = 'Suyeon';

// with if statement
const userName = document.querySelector('userName');
if(userName) {
   (userName as HTMLInputElement).value = 'Suyeon'
}

Index Property

  • It is useful when we don't know property names in advance and how many perperty will be there.
  • [property name's type]: value type
interface ErrorContainer {
   [props: string]: string;
}

const errorBag: ErrorContainer = {
   email: 'Not a valid email!',
   userName: 'Must start with capital character!'
}

Function Overloads

When you need to set function's return type with union types in order to use specific methods.

  • You can use multiple function overloads.
/*
addFunc return value is Combinable. 
So when actual return value is string, typescript doesn't know.
Then you cannot use string method.
*/

type Combinable = string | number;

function addFunc(a: number, b: number): number; // (*)
function addFunc(a: string, b: string): string;  
function addFunc(a: string, b: number): string; 
function addFunc(a: Combinable, b:Combinable) {
  if(typeof a === 'string' && typeof b === 'string') {
     return a.toString() + b.toString(); 
  }
  return a + b;
}

const result = add('Suyeon', 'Kang'); 
result.split(' '); // working!

// const result = add('Suyeon', 'Kang') as string;  Alternative

Optional Chaining

Optional chaining helps us to access safely to the data of nested object or nested property. If data is undefined, it will not continue. It is useful when fetching some data from server.

const fetchedData = {
 id: 'u1',
 name: 'Suyeon',
 job: { title: 'chef', des: 'cooking' }
};

console.log(fetchedData?.job?.title); // (*)

// console.log(fetchedData.job && fetchedData.job.title); Alternative

Nullish Coalescing

if value is exactly null or undefined(not 0 or ''), then it use fallback.

const userInput = '';
const storedData = userInput ?? 'DEFAULT'; // (*)
// const storedData = userInput || 'DEFAULT'; Alternative(null, undefined, 0, '')
profile
Hello World.

0개의 댓글