Web Dev/ELICE

25 (1/2) :: Type Guard, Optional Chaining, 함수 오버로딩, 인덱스 시그니처

HJPlumtree 2021. 11. 27. 11:59

엘리스 SW 엔지니어 트랙 25일차

송현지 강사님 온라인 강의날

다양한 예시 보여주셔서 감사합니다

 

 

타입 심화

Union Type

Or

A타입 이거나 B 타입

A | B

유니온 타입 예시

// Union Type
let one : string | number

one = '1'
one = 1

 

 

인터페이스는 유니온 타입 확장 불가

type과 &를 사용해줘야한다

 

type으로 유니온 타입 확장 예시

type A = string | number

// 이건 에러 나온다
interface StrOrNum extends A {
    a: string
}

// 이렇게 바꿔줘야된다
type StrOrNum = {
    a: string
} & (string | number)

 

 

Union Type은 겹치는 것만 사용가능

type Human = {
    think: () => void
    eat: () => void
}

type Dog = {
    bark: () => void
    eat: () => void
}

declare function getEliceType(): Human | Dog
const elice = getEliceType()

// 이건 가능하지만
elice.eat()

// 이게 오류가 난다는 이야기
elice.think()
elice.bark()

 

 

Intersection Type

And

A타입과 B타입이 있으면

A타입이면서 B 타입

A & B

// Intersection Type
type Human ={
    think: () => void
}

type Developer ={
    work: () => void
}

// Human 이면서 Developer
const elice: Human & Developer = {
    think() {},
    work() {}
}

 

 

Type Guard

타입스크립트가 타입을 추론할 수 있도록 단서를 주는 것 => 구별된 유니온

if문을 사용하는 방법이 있다

 

실무에서 구별된 유니온과 타입가드 자주 사용한다

Discriminated Union(구별된 유니온)

 

구별된 유니온 사용 예시

type SuccessResponse = {
    status: true
    data: any
}

type FailureResponse = {
    status: false
    error: Error
}

type CustomResponse = SuccessResponse | FailureResponse

declare function getData(): CustomResponse

const response: CustomResponse = getData()

if (response.status) {
    console.log(response.data)
} else if(response.status === false){
    console.log(response.error)
}

 

 

타입 가드 종류

1. instanceof 연산자

클래스도 타입인걸 이용

객체가 어떤 클래스 객체인지 구별할 때 사용

worker instanceof Designer

 

2. typeof 연산자

typeof 데이터 === 'string'
typeof 데이터 === 'undefined'
. . .

 

3. in 연산자

문자열 A in 오브젝트

'tail' in elice

 

4. literal type guard

  • switch() { case '타입' } 이용
  • if문 '타입' 이용

 

5. 사용자정의 함수

오픈소스 sindresorhus/is 사용해서 타입체크 가능

둘 중 하나로 설치가능

  • Yarn add @sindersorhus/is
  • npm install @sindersorhus/is

 

 

Optional Chaining

객체가 null 또는 undefined면 undefined 리턴

아니면 데이터 값 리턴

data?.chaining

위의 예는 data가 null이나 nudefined값이 아닐 때 chaining이 실행

 

 

예시를 하나 더 들어보면

dog?.tail?.살랑살랑?.()

// dog이 null, undefined가 아니면 tail
// tail이 null, undefined가 아니면 살랑살랑
// 살랑살랑이 null, undefined가 아니면 비로소 살랑살랑() 실행

 

&&와 ?. 의 차이점
  • &&
    falsy(false, null, undefined, '', 0, -0, Nan)

  • ?.
    null, undefined

 

Optional Chaining 사용 예시

type Cat = {
    sitDown?: () => void
}

function trainCat(cat: Cat) {
    cat.sitDown?.()
}

post.comments?.[0]

 

 

Nullish Coalescing Operator

A??B

좌항이 null, undefined 경우에만 B 리턴

 

A||B
얘는 falsy 값이 전부 포함

 

 

Function Overloading(함수 오버로딩)

같은 이름의 함수를 만들고,

파라미터의 형태가 다양한 여러 케이스에 대응

 

타입 가드 느낌이 나네

 

3가지가 같아야된다

  • 함수 이름
  • 매개변수 순서
  • 변환 타입

arrow function 오버로딩 불가능

 

 

Function Overloading 선언 예시

// Function Overloading
class User {
	constructor(private id: string){}
    
    // 함수 이름 setId,
    // 매개변수 순서 id,
    // 변환타입 string 같다
    setId(id: string): string
    setId(id: number): string

    // error 예시
    setId(id: string): number
    setId(radix: number, id: number):string // radix가 뒤로 가야된다
}

 

Function Overloading 구현 예시

// Function Overloading 구현
class User {
	constructor(private id: string){}

    setId(id: string): void
    setId(id: number, radix: number): void
    // radix가 추가되서 Optional 처리
    setId(id: string | number, radix?: number): void {
        this.id = typeof id === 'number' ? id.toString(radix): id
    }
}

 

 

제네릭 vs 함수 오버로딩

 

타입 추론 시점

  • 제네릭: 타입이 사용 되는 시점
  • 함수 오버로딩: 타입을 선언하는 시점

용도

  • 제네릭: 제네릭, 인터페이스, 클래스, 함수, 메서드
  • 함수 오버로딩: 함수, 메서드

어떤 타입이 올지 모르면 제네릭 사용하자!

 

 

Type Assertion

타입스크립트가 추론 못하는 타입

as 혹은 꺾쇠<> 이용해서

타입스크립트한테 알려주는것

 

 

Type Casting vs Type Assertion
  • Type casting: 데이터 타입 변환
  • Type assertion: 데이터 타입 명시

 

Type Assertion 예시

let someValue: unknown = "this is a string"

let strLength: number = (someValue as string).length
let strLength: number = (<string>someValue).length

 

react의 JSX에서 꺾쇠괄호<> 이녀석이 혼동되서 as가 나왔다

 

결국 Type Assertion을 쓰지말고

타입 선언을 사용하라는 것으로 들린다

type Duck = {
  꽥꽥: () => void;
  헤엄: () => void;
};

// 타입 단언(Type Assertion)
// const duck = {} as Duck;

// 타입 선언
const duck : Duck = {
    꽥꽥(){
        console.log("꽥꽥")
    },
    헤엄(){
        console.log("어푸어푸")
    }
}

duck.꽥꽥(); // "꽥꽥" 출력(console.log 사용)
duck.헤엄(); // "어푸어푸" 출력

 

 

Index Signature

 

자바스크립트의 Index Signature

객체 접근 예시

// JavaScript Index Signature
dog['name']

Index Signature는

객체의 프로퍼티 잘 모를 때 사용

 

타입스크립트의 Index Signature

예시

// TypeScript Index Signature
type ArrStr = {
    [key: string] : string | number
    [index: number]: string
    length: number
}

 

Index Signature 문제점

타입이 인덱스 시그니처로만 되어있으면 에러가 안난다

예시

type ArrStr = {
    [key: string]: string | number
    [index: number]: string
}

const a: ArrStr = {}

a['str'] // 에러가 안난다

 

어떤 타입이 올지 알면

인덱스 시그니처 사용하지 말자

런타임에 객체의 프로퍼티 모를 때만 사용하자

 

 

이렇게도 사용한다

// index Signature

// 이렇게 사용하거나 1
// type HttpHeaders = {
//   [key: string]: string
// }

// 이렇게 사용하거나 2
type HttpHeaders = Record<string, string>

const headers: HttpHeaders = {
  'Host': 'elice.io' ,
  'Connection': 'keep-alive' ,
  'Accept': '*/*' ,
  'Access-Control-Request-Method': 'GET' ,
  'Access-Control-Request-Headers': 'authorization' ,
  'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36' ,
  'Sec-Fetch-Mode': 'cors' ,
  'Sec-Fetch-Site': 'same-site' ,
  'Sec-Fetch-Dest': 'empty' ,
  'Accept-Language': 'ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7' ,
}

console.log(headers['Host']) // elice.io

 

 

궁금

type vs interface