미미의 메모장

[Typescript] 빠르게 마스터하는 타입스크립트 part 2 본문

memo/Front-End💙

[Typescript] 빠르게 마스터하는 타입스크립트 part 2

mimi memo 2024. 6. 10. 18:29

함수 rest 파라미터, destructuring 할 때 타입지정

//다른 파라미터 있으면 맨 뒤에만 사용 가능
function 전부더하기(...작명:number[]){
  console.log(작명)
}

전부더하기(1,2,3,4,5)

 

... spread operator는 괄호 벗겨주세요 문법

 

destructuring 개념

let { student, age } = { student : true, age : 20 }

let [a, b] = ['안녕', 100]

 

Destructuring 문법도 함수 파라미터에 사용가능

let person = { student : true, age : 20 }

function 함수({student, age} :{student : boolean, age : number}){
  console.log(student, age)
}
함수({ student : true, age : 20 })

 

 

Narrowing 할 수 있는 방법 더 알아보기

null& undefined 타입체크하는 경우 매우 잦음1. && 연산자null& undefined 타입체크하기 2. in 키워드로 object narrowing 가능

type Fish = { swim: string };
type Bird = { fly: string };
function 함수(animal: Fish | Bird) {
  if ("swim" in animal) {
    return animal.swim
  }
  return animal.fly
}

 

3. instanceof 연산자로 object narrowing 가능

object 타입이 둘다 비슷할 때 literal type 강제로 만들어두면 나중에 도움됨

type Car = {
  wheel : '4개',
  color : string
}
type Bike = {
  wheel : '2개',
  color : string
}

function 함수(x : Car | Bike){
  if (x.wheel === '4개'){
    console.log('the car is ' + x.color)
  } else {
    console.log('the bike is ' + x.color)
  }
}

 

 

함수에 사용하는 never 타입 = :void 로 대체가능

function 함수() :never{
  while ( true ) {
    console.log(123)
  }
}

function 함수() :never{
  throw new Error('에러메세지')
}

어떤 함수가

조건 1) 절대 return을 하지 않아야하고

조건 2) 함수 실행이 끝나지 않아야한다 (전문용어로 endpoint가 없어야함)

 

public 키워드: 항상 사용되고 있음, 생략 되어있음

private 키워드: 자식이 수정할 수 없음. class 안에서만 수정, 이용 가능

class User {
  public name: string;

  constructor(){
    this.name = 'kim';
  }
}

let 유저1 = new User();
유저1.name = 'park';  //가능

 

class에서 사용가능한 protected, static 키워드

private인데 약간 보안을 해제하고 싶을 때 

protected를 달아놓으면 1. private 이거랑 똑같은데 2. extends 된 class 안에서도 사용가능하게 약간 보안을 풀어 준다. 자식 사용 불가능

 

static 키워드 붙이면 부모 class에만 직접 부여됨, 자식 못 씀(안 물려줌). 부모를 쓰면 사용가능. private/protected/public 동시 사용가능

숨기고 싶으면 protected,private이게 났다

class User {
  static x = 10;
  y = 20; // 자식만 사용 가능
  console.log(User.x+' 10')
}

let john = new User();
john.x //불가능
User.x //가능
User.y //불가능

 

 

타입 import export 

(a.ts)

export var 이름 = 'kim';
export var 나이 = 30;

(b.ts)

import {이름, 나이} from './a'
console.log(이름)

 

namespace : TypeScript 타입 변수 숨기기 문법 (옛날 방법임) = module 이랑 같은 소리

(a.ts)

namespace MyNamespace {
  export interface PersonInterface { age : number };
  export type NameType = number | string;
}

(b.ts)

/// <reference path="./a.ts" />

let 이름 :MyNamespace.NameType = '민수';
let 나이 :MyNamespace.PersonInterface = { age : 10 };

 

 

타입을 파라미터로 입력하는 Generic

function 함수<MyType>(x: MyType[]) :MyType {
  return x[0];
}

let a = 함수<number>([4,2])
let b = 함수<string>(['kim', 'park'])

 

Generic 타입 제한하기 (constraints) : extends

function 함수<MyType extends number>(x: MyType) {
  return x - 1
}

let a = 함수<number>(100)

 

React + TypeScript 사용할 때 알아야할 점

설치

npx create-react-app 프로젝트명 --template typescript
//기존 프로젝트에 타입스크립트만 더하고 싶으면 

npm install --save typescript @types/node @types/react @types/react-dom @types/jest

 

let 박스 :JSX.Element = <div></div>

 

Redux toolkit

redux 왜 쓰냐면

1. state를 한 곳에서 관리할 수 있어서 컴포넌트들이 props없이 state 다루기 쉽고, 

2. 수정방법을 미리 reducer라는 함수로 정의해놔서 state 수정시 발생하는 버그를 줄일 수 있음

 

전통방식

npm install redux react-redux

 

(전통방식 redux) state와 reducer 만들 때 타입지정 필요  

 

import { Provider } from 'react-redux';
import { createStore } from 'redux';

interface Counter {
  count : number
}

const 초기값 :Counter  = { count: 0 };

function reducer(state = 초기값, action :any) {
  if (action.type === '증가') {
    return { count : state.count + 1 }
  } else if (action.type === '감소'){
    return { count : state.count - 1 }
  } else {
    return initialState
  }
}

const store = createStore(reducer);

// store의 타입 미리 export 해두기 
export type RootState = ReturnType<typeof store.getState>

ReactDOM.render(
  <React.StrictMode>
    <Provider store={store}>
      <App />
    </Provider>
  </React.StrictMode>,
  document.getElementById('root')
)

 

(전통방식 redux) state를 꺼낼 때 

import React from 'react';
import { useDispatch, useSelector } from 'react-redux'
import { Dispatch } from 'redux'
import {RootState} from './index'

function App() {
  const 꺼내온거 = useSelector( (state :RootState) => state );
  const dispatch :Dispatch = useDispatch();

  return (
    <div className="App">
      { 꺼내온거.count }
      <button onClick={()=>{dispatch({type : '증가'})}}>버튼</button>
      <Profile name="kim"></Profile>
    </div>
  );
}

 

(신규방식 redux) state와 reducer 만들 때 타입지정 필요  

npm install @reduxjs/toolkit
import { createSlice, configureStore } from '@reduxjs/toolkit';
import { Provider } from 'react-redux';

const 초기값 = { count: 0, user : 'kim' };

const counterSlice = createSlice({
  name: 'counter',
  initialState : 초기값,
  reducers: {
    increment (state){
      state.count += 1
    },
    decrement (state){
      state.count -= 1
    },
    incrementByAmount (state, action :any){
      state.count += action.payload
    }
  }
})

let store = configureStore({
  reducer: {
    counter1 : counterSlice.reducer
  }
})

//state 타입을 export 해두는건데 나중에 쓸 데가 있음
export type RootState = ReturnType<typeof store.getState>

//수정방법 만든거 export
export let {increment, decrement, incrementByAmount} = counterSlice.actions

 

(신규방식 redux) state를 꺼낼 때

import { useDispatch, useSelector } from 'react-redux'
import {RootState, increment} from './index'

function App() {

  const 꺼내온거 = useSelector( (state :RootState) => state);
  const dispatch = useDispatch();

  return (
    <div className="App">
      {꺼내온거.counter1.count}
      <button onClick={()=>{dispatch(increment())}}>버튼</button>
    </div>
  );
}

 

 

array 자료에 붙일 수 있는 tuple type

let 멍멍이 :[string, boolean];
멍멍이 = ['dog', true]

//tuple 안에도 옵션가능
type Num = [number, number?, number?];
let 변수1: Num = [10];
let 변수2: Num = [10, 20];
let 변수3: Num = [10, 20, 10];

 

함수에서 쓰는 tuple : rest parameter

function 함수(...x :string[]){
  console.log(x)
}

 

 

array 합칠 때, spread 연산자 사용

let arr = [1,2,3]
let arr2 :[number, number, ...number[]] = [4,5, ...arr]

 

 

외부 파일 이용시 declare & 이상한 특징인 ambient module

(data.js)

var a = 10;
var b = {name :'kim'};

(index.ts)
//declare로 정의한 내용은 js로 변환 되지 않음
declare let a :number;
console.log(a + 1);

 

ts 이상한 특징

- 모든 ts파일은 ambient modul(글로벌 모듈)임 => import export 없어도 다른 파일에 있던 변수 쓸 수 있음

- 파일에 import export 키워드 있으면 자동으로 로컬 모듈로 된다

-로컬 모듈에서 글로벌로 쓰고 싶은 변수가 있으면,

declare global {
  type Dog = string;
}

 

d.ts 파일 이용하기

-타입정의 보관용 파일

-자동 생성 옵션

-자동으로 글로벌 모듈 아님. 로컬모듈이라 import

- export 없이 d.ts 파일을 글로벌 모듈 만들려면  "typeRoots": ["./types"] 이런 옵션을 추가

(tsconfig.json)

{
    "compilerOptions": {
        "target": "es5",
        "module": "es6",
        "declaration": true,
         "typeRoots": ["./types"] //폴더명. 여기있는 타입들은 글로벌하게 이용가능. 자동으로 라이브러리 @types포함 안해줌. 그래서 라이브러리 사용하려면 이걸 지우던가 포함시켜줘야함
    }
}
 
implements 키워드 :  class가 특정 필드와 함수를 가지고 있는지 확인하고 싶은 경우 간혹 사용

implements라는건 interface에 들어있는 속성을 가지고 있는지 확인만하라는 뜻

interface CarType {
  model : string,
  tax : (price :number) => number;
}

class Car implements CarType {
  model;   ///any 타입됨
  tax (a){   ///a 파라미터는 any 타입됨 
    return a * 0.1
  }
}

 

 

object index signatures

interface StringOnly {
//모든속성은 string을 가진다. 한번에 타입 지정하고 싶을 때 사용
  [key: string]: string
  
//또는
  age : number,
  [key: string]: string | number
}

let obj :StringOnly = {
  name : 'kim',
  age : '20',
  location : 'seoul'
}

 

 

Recursive Index Signatures

interface MyType {
  'font-size': MyType | number
}


let obj :MyType = {
  'font-size' : {
    'font-size' : {
      'font-size' : 14
    }
  }
}

 

 

keyof 키워드

interface Person {
  age: number;
  name: string;
}
type PersonKeys = keyof Person;   //"age" | "name" 리터럴 타입됩니다
let a :PersonKeys = 'age'; //가능
let b :PersonKeys = 'ageeee'; //불가능

 

object 타입 변환기 만들기 Mapped Types [ 자유작명 in keyof 타입파라미터 ] : 원하는 타입

type Car = {
  color: boolean,
  model : boolean,
  price : boolean | number,
};

type TypeChanger <MyType> = {
  [key in keyof MyType]: string;
};

 

조건문으로 타입만들기 extends

type Age<T> = T extends string ? string : unknown;
let age : Age<string> //age는 string 타입
let age2 : Age<number> //age는 unknown 타입

 

조건문에서 쓸 수 있는 infer 키워드: 타입을 왼쪽에서 추출

type Person<T> = T extends infer R ? R : unknown; 
type 새타입 = Person<string> // 새타입은 string 타입

-언제쓰는지 ... 확실하게 감이 잡히지 않음 😅

 

 

 

 

 

/강의 출처: 코딩애플/ 

'memo > Front-End💙' 카테고리의 다른 글

[Typescript] 빠르게 마스터하는 타입스크립트 part 1  (1) 2024.06.10
[Websocket] 웹소켓  (0) 2023.11.22
[Typescript] 기본  (1) 2023.11.09
[Next.js] 프로젝트 셋업  (0) 2023.06.22
[Next.js] Headless CMS란?  (0) 2023.06.19