코딩애플 Typescript - 타입 확정하기 Narrowing & Assertion

김원종·2024년 4월 2일
0

TypeScript 학습

목록 보기
5/28

Type이 아직 하나로 확정되지 않았을 경우 Type Narrowing을 사용해야한다.
이런식으로 if문을 사용하여 변수의 타입이 string이면 number이면 이라는 확실한 타입을 Narrowing해줘야한다. Narrowing 이라는 단어를 DeepL에 번역해보면 좁히기/축소 등의 뜻이 나온다. 즉 타입을 하나로 거른다 정한다 라고 생각하면 될것같다.

정리하면 union type 등 어떤 변수가 타입이 아직 불확실하면 if문 등으로 Narrowing 해줘야 조작이 가능하다. typeof를 사용할땐 항상 문자열로 정리해야한다 number 가 아닌 'number'이런식으로 말이다.if문을 사용하면 끝까지 써야 안전하다. else,else if를 사용하지 않으면 에러로 잡아줄수도 있다.

Narrowing할수있는 문법은 여러가지 키워드를 사용할수있다.Narrowing으로 판정해주는 문법들은 그냥 현재 변수의 타입이 뭔지 특정지을 수 있기만 하면 다 인정해준다.
만약 Narrowing 문법을 사용하지 않는다면 Assertion이라는 방법도 존재한다.


Assertion문법이라는 문법은 타입을 잠깐 덮어 씌우는것이다. 위 코드를 보면 x as number라고 작성 되어 있는데 이 뜻은 왼쪽의 x라는 변수를 number로 덮어 써달라는 문법이다.그럼 실제 ts의 컴파일러가 x를 number로 인식을 한다.그럼 타입이 정해지게 되는것이고 if문을 사용할 필요 없을것이다.

하지만 as문법의 용도를 잘 알아야한다. 무작정 사용하지 말아야한다.

  1. Narrowing할때 사용한다 =>

    여러개의 타입이 얽힌 union 타입을 하나의 타입으로 확정하고 싶을때 사용하는게 as문법이다.위와 같이 사용하면 안된다.as 문법은 union타입을 하나의 타입으로 확정을 시키고 싶을때 사용하는 것이지 이미 타입이 정해진 변수의 타입을 변경하는것은 불가능하다. 즉 string타입을 number로 바꿀려고 사용하면 안된다는 뜻이다.

  1. 무슨 타입이 들어올지 100% 확실할때 사용한다 =>

    만약 내가 만든 함수의 변수가 100%의 확률로 number가 들어오는 상황이라고 가정해보자. 해당 상황에서 function 내함수 (x :number |string ) 이런식으로 union타입으로 지정되어있을때 number로 들어오는걸 알기에 as로 확정시킬수 있다. 하지만 if문을 사용하는 방법이 더 올바른 방법이다. 왜냐면 as문법을 사용하면 변수값이 문자 즉 string이여도 버그를 캐치할수 없다.as문법 자체가 거짓으로 타입을 확정하는것이기 때문에 number가 아닌 타입을 넣어도 타입 에러로 잡아주지를 않는다. 왜냐? number로 덮어 씌우기 때문이다.

  • 그렇기 때문에 if문을 애용하자! as문법은 디버깅용 비상용으로 사용하자!

as 문법이 유용한경우

가끔 타입을 강제로 부여하는 기계를 하나 만들어쓰고 싶은 때가 있다.

그럴 때 함수에 데이터를 넣으면 as 타입명을 붙여서 return 하는 함수를 만들어서 사용하면 된다.

type Person = {
    name : string
}
function 변환기<T>(data: string): T {
    return JSON.parse(data) as T;
}
const jake = 변환기<Person>('{"name":"kim"}');

변환기라는 함수를 만들었는데

이 함수에 자료를 입력하면 as 키워드로 타입을 하나 붙여준다.

하지만 아직 배우지 않은 문법이 등장합니다.

<타입을 파라미터로 넣는 방법> 그리고 type 키워드 이런게 등장하는데

지금은 그렇구나~ 까지만 느끼면 되고 나중가면 알게될 것이다.


숙제1) 숫자여러개를 array 자료에 저장해놨는데

가끔 '4', '5' 이런 식의 문자타입의 숫자가 발견되고 있습니다.

이걸 클리닝해주는 함수가 필요합니다.

클리닝함수( ['1', 2, '3'] ) 이렇게 숫자와 문자가 섞인 array를 입력하면

[1,2,3] 이렇게 숫자로 깔끔하게 변환되어 나오는 클리닝함수를 만들어오고 타입지정까지 확실히 해보십시오.

모르는 부분은 구글검색해도 봐드림

나의 풀이

function ar1(x:(number|string)[]){
    let arr :number[]=[];
    x.forEach(t=>{
        if(typeof t =='string'){
            arr.push(Number(t))
        }else{
            arr.push(t)
        }
        console.log(arr.sort());
    })

}

ar1(['1',2,'3','6',5,'4'])

센세 풀이

function 클리닝함수(a :(number|string)[]){

  let 클리닝완료된거 :number[] = [];

  a.forEach((b)=>{
    if (typeof b === 'string') {
      클리닝완료된거.push(parseFloat(b))
    } else {
      클리닝완료된거.push(b)
    }
  })

  return 클리닝완료된거
}

console.log( 클리닝함수([123,'3']) )

저는 파라미터로 집어넣은 array 자료를 반복문 돌려서

하나하나 숫자로 바꿔서 새로운 array에 집어넣는 방식으로 코드를 짰습니다.

 

1. 클리닝 함수를 만들었습니다. 파라미터로 array를 집어넣을 수 있다고 해놨습니다.

2. 클리닝완료된 array를 클리닝완료된거라고 작명해서 만들어뒀습니다. 

3. 저는 집어넣은 array를 반복문을 돌리려고 forEach()를 썼습니다. 

4. 그리고 반복문 돌리면 array 안에 있던 하나하나의 자료가 b라는 파라미터로 나오는데 

그게 string 타입이면 parseFloat(b)에 넣어서 숫자로 바꾸고 클리닝완료된거 array에 집어넣었습니다.

number 타입이면 그냥 클리닝완료된거 array에 집어넣었습니다. 

숙제2) 다음과 같은 함수를 만들어보십시오.
let 철수쌤 = { subject : 'math' }
let 영희쌤 = { subject : ['science', 'english'] }
let 민수쌤 = { subject : ['science', 'art', 'korean'] }

지금 여러 변수에 선생님이 가르치고 있는 과목이 저장이 되어있습니다.
과목 1개만 가르치는 쌤들은 문자 하나로 과목이 저장이 되어있고
과목 2개 이상 가르치는 쌤들은 array 자료로 과목들이 저장되어있습니다.

'철수쌤' 같은 object 자료를 파라미터로 집어넣으면
그 선생님이 가르치고 있는 과목중 맨 뒤의 1개를 return 해주는 함수를 만들어봅시다.
그리고 타입지정도 엄격하게 해보도록 합시다.

(동작예시)

만들함수( { subject : 'math' } )  //이 경우 'math'를 return
만들함수( { subject : ['science', 'art', 'korean'] } ) //이 경우 'korean'을 return
만들함수( { hello : 'hi' } )  //이 경우 타입에러 나면 됩니다 

나의 풀이

function teacher(x:{subject:string|string[]}){
    if(typeof x.subject==='string'){
        return x.subject;
    }else if(Array.isArray(x.subject)){
        return x.subject[x.subject.length-1];
    }
}
console.log(teacher( { subject : 'math' } ));
console.log(teacher( { subject : ['science', 'art', 'korean'] } ));

센세 풀이

function 만들함수( x :{subject : string | string[]} ){
  if (typeof x.subject === 'string') {
    return x.subject
  } else if (Array.isArray(x.subject) ){
    return x.subject[x.subject.length - 1]
  } else {
    return '없쪄'
  }
}

console.log( 만들함수( { subject : ['english', 'art'] }  ) )

1. 함수에 object 자료를 입력할 수 있다고 써야하는데 저는 type alias를 만들어사용했습니다. 
2. 그리고 만들함수()를 디자인했다고 합니다.
3. 지금 x.subject 라는 파라미터는 케이스가 2개니까 if문을 두개 썼는데 안전하게 마지막 else 문도 추가했습니다. 
아니면 그냥 if 한개 else 한개 이렇게 해도 똑같을 듯요 
4. 이 변수가 array 자료인지 확인하려면 typeof 이거는 못사용하고 Array.isArray() 이거나 아니면 다른 여러 방법을 쓰셔야합니다.
5. 그래서 실제 실행해보니 { subject : ['english', 'art'] } 입력해보면 'art'가 잘 나옵니다. 

심심하면 함수가 어떤 값을 return 해야할 지도 타입지정할 수 있겠군요. 
profile
개린이

0개의 댓글