Typescript - 고급타입

런던행·2020년 6월 30일
0

TypeScript(기초)

목록 보기
4/4
// 타입간의 관계 

class Animal {}

class Bird extends Animal {
  chirp() {}
}

class Crow extends Bird {
  caw() {
  }
}

function chirp(bird: Bird): Bird {
  bird.chirp()
  return bird
}

// chirp(new Animal) // 에러..
chirp(new Bird)
chirp(new Crow)


// 타입 넓히기

const af = 'x'  // 'X'
let bf = af    // string

const c: 'x' = 'x'  // 'x'
let d = c  // 'x'

// null 이나 undefined로 초기화된 변수는 any 타입으로 넓혀진다.
let a = null  // any
a = 3 // any

// null or undefined로 초기화된 변수가 선언 범위를 벗어나면 타입 스크립트는 확실한(좁은) 타입을 할당한다.

function xString() {
  let a = null // any
  a = 3  // any
  a = 'b'  // any
  return a 
}

xString()  // string

// const 타입 
// 타입스크립트는 타입이 넓혀지지 않도록 해주는 const라는 특별 타입을 제공한다.

// 초과 프로퍼티 확인

type Options = {
  baseURL: string,
  cacheSize?: number,
  tier?: 'prod' | 'dev'
}

class API {
  constructor(private options: Options) {}
}

new API({
  baseURL: 'https://api.mysite.com',
  tier: 'prod'
})

new API({
  baseURL: 'https://api.mysite.com',
  tierr: 'prodprod'  // 에러가 발생
})

type Unit = 'cm' | 'px' | '%'

// 정제
type Width = {
  unit: Unit,
  value: number
}

let units: Unit[] = ['cm', 'px', '%']

function parseUnit(value: string): Unit | null {
  for (let i = 0; i < units.length; i++) {
    if (value.endsWith(units[i])) {
      return units[i]
    }
  }
  return null
}
function parseWidth(width: number | string | null | undefined): Width | null {
  if (width == null) {
    return null
  }

  if (typeof width === 'number') {
    return { unit: 'px', value: width}
  }

  let unit = parseUnit(width)
  if (unit) {
    return { unit, value: parseFloat(width)}
  }
  return null
}

type UserTextEvent = { value: string, target: HTMLInputElement }
type UserMouseEvent = { value: [number, number], target: HTMLElement }
type UserEvent = UserTextEvent | UserMouseEvent

function handle(event: UserEvent) {
  if (typeof event.value === 'string') {
    event.value //string
    event.target // HTMLInputElemnt | HTMLElement
    return
  }

  event.value // [number, number]
  event.target // HTMLInputElemt | HTMLElement (!!!)
}


type UserTextEvent = { type: 'TextEvent' value: string, target: HTMLInputElement }
type UserMouseEvent = { type: 'UserMouseEvent' value: [number, number], target: HTMLElement }

type UserEvent = UserTextEvent | UserMouseEvent

function handle(event: UserEvent) {
  if (event.type === 'TextEvent') {
    event.value //string
    event.target // HTMLInputElemnt
    return
  }

  event.value // [number, number]
  event.target // HTMLElement (!!!)
}

// 종합성
type Weekday = 'Mon' | 'Tue' | 'Wed' | 'Thu' | 'Fri'
type Day = Weekday | 'Say' | 'Sun'

function getNextDay(w: Weekday): Day {
  switch (w) {
    case 'Mon' : return 'Tue'
  }
}

function isBig(n: number) {
  if (n > 100) {
    return true
  }
}

// 키인 연산자
type APIResponse = {
  user: {
    userId: string
    friendList: {
      count: number: {
        firstName: string
        lastName: string
      }
    } []
  }
}

function renderFriendList(friendList: unknown) {
}

type FriendList = {
  count: numberfriends: {
    firstName: string
    lastName: string
  }
}

type APIResponse = {
  user: {
    friendList: FriendList
  }
}

function renderFriendList(friendList: FriendList) {

}

type FriendList = APIResponse['user']['friendList']

function renderFriendList(friendList: FriendList) {

}

// keyof 연산자
// keyof를 이용하면 객체의 모든 키를 문자열 리터럴 타입 유니온으로 얻을 수 있다. 

type ResponseKeys = keyof APIResponse // 'user'
type UserKeys = keyof APIResponse['user']  // 'userId' | 'friendList'
type FriendListKeys = keyof APIResponse['user']['friendList'] // 'count' | 'friends'

function get<O extends object, K extends key of O> (o: 0, k: K): O[K] {
  return o[k]
}

// 여기 까지 수정
type ActivityLog = {
  lastEvent: Date
  events: {
    id: string
  }
}

// Record 타입간의 - 타입스크립트의 내장 Record 타입을 이용하면 무언가를 매핑하는 용도로 객체를 활용할 수 있다. 

type Weekday = 'Mon' | 'Tue' | 'Wed' | 'Thu' | 'Fri'

type Day = Weekday | 'Sat' | 'Sun'

let nextDay: Record<Weekday, Day> = {
  Mon: 'Tue'
}

// 내장 매핑된 타입간의

// Record<Keys, Values> : keys타입의 키와 values 타입의 값을 갖는 객체

// Partial<Object> Object의 모든 필드를 선택형으로 표시

// Required<Object> Obejct의 모든 필드를 필수형으로 표시

// Readonly<Object> 

// Pick<Object, Keys>

// 6.3.4 컴패이언 객체 패턴 : 스칼라에서 유래한 기능으로 같은 이름을 공유하는 객체와 클래스를 쌍으로 연결한다. 타입스크립트에는 타입과 객체를 쌍으로 묶는, 비슷한 기능의 비슷한 패턴이 존재하는데 이 역시도 컴패니언 객체 패턴의 예다.

type Currency = {
  unit: 'EUR' | 'GBP' | 'JPY' | 'USD'
  value: number
}

let Currency = {
  DEFALT: 'USD'
  from(value: number, unit = Currency.DEFAUTL): Currency {
    return { unit, value }
  }
}

let amountDue: Currency = {
  unit: 'JPY',
  value: 83733.10
}

let otherAmountDue = Currency.from(330, 'EUR')

// 고급 함수 타입들

// 튜플의 타입 추론 개선

function isString(a: unknown): boolean {
  return typeof a === 'string'
}

function isString2(a: unknown): a is string {
  return typeof a === 'string'
}


// 6.5 조건부 타입 
type IsString<T> = T extends string ? true | false
type A = IsString<string> // true
Type B = IsString<number> // false

// 6.5.1 분배적 조건부

type ToArray<T> = T[]
type A = ToArray<number>        // number[]
type B = ToArray<number | string> // (number | string)[]

type ToArray2<T> = T extends unknown ? T[] : T[]
type A = ToArray2<number> // number[]
type B = ToArray2<number | string> // number[] | string[]


profile
unit test, tdd, bdd, laravel, django, android native, vuejs, react, embedded linux, typescript

0개의 댓글