Lsiron

Type Script 함수 타입 지정 심화(rest parameter, destructing, never) 본문

언어/Type Script

Type Script 함수 타입 지정 심화(rest parameter, destructing, never)

Lsiron 2024. 7. 14. 03:55

함수에 타입을 지정해보자. 전 과는 조금 다른 형태의 함수에 타입을 지정을 해 볼 것이다.

 

첫 번째는 바로 rest parameter에 함수 타입을 지정 할 예정인데. 

 

먼저 rest parameter란? javascript 를 배울 때, 'spread operator' 와 'rest operator' 를 배웠을 텐데 그 rest가 맞다. 

 

먼저 spread 문법의 예시를 보자.

 

JavaScript에서 spread 문법은 아래와 같이 사용 됐었다.

let arr1 = [1, 2, 3];
let arr2 = [4, 5 ];
let arr3 = [...arr1, ...arr2];

console.log(arr3)  // [1, 2, 3, 4, 5] 출력

 

즉, 객체 혹은 배열을 펼치는 문법이다. spread는 펼치는 것을 의미한다. 둘다 '...' 점 세 개를 사용하지만 엄연히 다른 문법이다. 주로 불변성 유지에 많이 사용했었다.

 

다음으로 rest 문법의 예시를 보자.

const lsiron = {
  name: 'siron',
  age: 28,
  country: 'korea'
};

const { color, ...rest } = lsiron;
console.log(name);  // 'siron' 출력
console.log(rest);  // { age : 28, country : 'korea' } 출력

 

즉, rest는 나머지 를 의미 한다. spread와 rest 모두 '...' 점 세 개를 사용하지만 엄연히 다른 문법이다. 주로 불변성 유지에 많이 사용했었다.

 

이 rest를 parameter에 적용한게 바로 rest parameter 이다.

 

보통 함수에 파라미터가 몇 개 들어갈 지 모를 때 '...' 을 사용하여 인자를 설정 해 주는 것이다.

function lsiron(...a) {
  console.log(a)
}

lsiron(1, 2, 3, 4, 5, 6) // [1, 2, 3, 4, 5, 6] 출력

 

즉 '...' 이 점 세 개만 붙이면 파라미터가 몇 억개든지 들어 올 수 있다는 것이다.

 

출력은 array 형태로 나오게 된다.

 

주의할 점은 반드시 들어와야 할 파라미터가 있다면 rest parameter는 맨 뒤에 써 주어야한다.

function lsiron(x, y, ...a) {

}

 

이제 본격적으로 rest parameter에 타입을 지정 해 보자.

당연히 위 코드를 보면 a에 숫자만 넣고 있으니, number 타입이 들어 갈 것이라 생각하여 기존에 함수에 타입을 지정 해 주었던 것 처럼

function lsiron(...a:number) {
  console.log(a)
}

lsiron(1, 2, 3, 4, 5, 6) // [1, 2, 3, 4, 5, 6] 출력

 

이렇게 해 줄 것이다.

 

안된다.

 

rest parameter 함수를 사용했을 때는 출력이 array로 된다고 했다. 즉, 타입도 array 타입으로 지정 해 주어야 하는 것.

function lsiron(...a:number[]) {
  console.log(a)
}

lsiron(1, 2, 3, 4, 5, 6) // [1, 2, 3, 4, 5, 6] 출력

 

이렇게 rest parameter 함수를 사용할 때는 함수의 타입지정 + 배열의 타입지정이 된다.

 

이제 함수의 파라미터에 destructuring 을 적용하여 타입을 지정하는 방법을 알아보자.

destructuring은 각각 배열과 객체에 사용되는 문법이였다.

//배열
let lsiron = ['siron', 28 ]

//한번 사용해보자
console.log(lsiron[0]) // 'siron' 출력 (사용하기 귀찮다)

//한번 이쁘게 나눠보자 destructuring 적용!
let [name, age] = lsiron

//이제 이렇게 쓰면 된다!
console.log(name) // 'siron' 출력


//객체
let lsiron = { name : 'siron' , age : 28 }

//한번 사용해보자
console.log(lsiron.name) // 'siron' 출력 (사용하기 귀찮다)

//한번 이쁘게 나눠보자 destructuring 적용!
let { name : name, age : age } = lsiron
//한번 더 이쁘게 나눠보자 js 문법으로 변수명 통합!
let { name, age } = lsiron

//이제 이렇게 쓰면 된다!
console.log(name) // 'siron' 출력


// 자주 사용되는 예시
let name = lsiron.name 일 경우 let {name} = lsiron 으로 변환 가능하다. 
풀어보면 let {name : name} = {name: 'siron' , age : 28} 이기 때문에
console.log(name)은 'siron'을 출력한다.

 

위와 같이 구조분해할당으로 배열과 객체를 변환 시킬 수 있다.

 

그렇다면 이 destructuring을 함수 파라미터에 적용 시키는 방법은?

 

객체 먼저 알아보자.

let lsiron = { name : 'siron' , age : 28 }

function iron ({name, age}) {
   console.log(name, age)
   }
   
iron(lsiron) //'siron',28 출력

 

함수 형태로 만들어주었으니, rest parameter 함수에 타입지정 했을 때와 같이 이번엔 함수의 타입지정 + 객체의 타입지정이다.

let lsiron = { name : 'siron' , age : 28 }

function iron ({name, age}: {name:string, age:number) {
   console.log(name, age)
   }
   
iron(lsiron) //'siron' 28 출력

 

이번엔 destructuring을 함수 파라미터에 배열 형태로 넣어보자.

let lsiron = ['siron', 28 ]

function iron ([name, age]) {
   console.log(name, age)
   }
   
iron(lsiron) //'siron' 28 출력

 

함수 형태로 만들어주었으니, rest parameter 함수에 타입지정 했을 때와 같이 이번엔 함수의 타입지정 + 배열의 타입지정이다.

let lsiron = ['siron', 28 ]

function iron([name, age]:(string | number)[]){
  console.log(name, age)
}

함수(lsiron) // 'siron' 28 출력

 

당연하게도 type을 따로 만들어서 type alias 를 적용시킬 수 있다.

 

never 타입이란?

function lsiron() :never {

}

 

함수가 값을 반환하지 않을 때 never 타입을 사용할 수 있다. 형태와 쓰임새는 void와 많이 유사하지만 never를 사용하기 위해선 엄격한 조건이 필요하다.

  1. return 값이 없어야한다.
  2. endpoint가 없어야 한다= 함수가 끝나지 않아야 한다. ( return 값이 없어야 한다는 말과 같다.  )

즉, 끝나지 않는 함수에 붙는 타입이 바로 never이다.

 

그렇다면 끝나지 않는 함수는 무엇이 있을까?

 

첫 번째는 에러를 던지는 함수이다.

function lsiron() :never{
    throw new Error()
}

 

정확히는 함수가 끝나는게 아니라 함수가 중단되는 것이라 할 수 있다.

 

두 번째는 while 반복문이다.

function lsiron() :never{
    while (true) {
    
    }
}

 

while 반복문 조건에 true를 사용해 주면 내부에서 무한히 반복된다.

 

그렇다면 이 never를 사용하는 때는 언제일까?

 

사실 never 타입을 쓸 곳이 없다. 함수에서 값을 반환하기 싫을 때는 void 타입을 사용하면 된다.

 

never 타입은 단지 코드를 잘못 짜면 자동으로 등장하는 타입이다.

 

잘못 짜는 경우는 어떤 경우일까?

 

첫 번째는 잘못된 Narrowing 이다.

function lsiron (siron : string) {
    if (typeof siron == 'string'){
        console.log(siron)
    } else {
        console.log(siron)
    }
}

 

(parameter) siron : never 라고 에러가 발생한다. 

 

두 번째는 잘못된 함수표현식이다 이는 return 타입이 자동으로 never 이다.

let lsiron = function(){
    throw new Error()
}

 

let lsiron: () => never 라고 에러가 발생한다.

 

굳이 사용할 일은 없지만 never가 보였을 때 이러한 이유 때문에 발생하는 것으로 알고 있으면 된다.

 

참조: 코딩애플