typescript

기본 문법 익히기 (2.7) - 타입스크립트의 타입

케케_ 2024. 9. 20. 18:48

2.7 타입스크립트에만 있는 타입을 배우자

 

 


2.7 타입스크립트에만 있는 타입을 배우자

타입스크립트에는 any처럼 보지 못한 타입들이 존재한다. 이번 글에서 하나씩 살펴보자.

 

 

 


2.7.1 any

: 타입스크립트에서 지양해야 할 타입

 

원칙 

any 타입은 타입 검사를 포기한다는 선언과 같다. 타입스크립트가 any로 추론하면 타입을 직접 표기해준다.

 

let str : any = 'hello'
const result = str.tofixed();
  • 위와 같이 코드 작성 시 오류가 나지 않음
    • 문자열에 tofixed 메서드이 가능해짐
  • any 타입은 모든 동작을 허용 -> 타입 검사 불가 -> 타입스크립트 의미 퇴색

 

아래와 같이 any 타입은 파생 결과물도 any 타입 (사용 지양)

 

 

any 타입을 직접 쓸일은 별로 없음 --> 타입스크립트가 타입을 any로 추론할 경우

function (x,y) {
    return x+y;
}
  • 위와 같이 코드 작성 시

  • any 타입으로 추론함

 

배열

빈 배열을 선언하면 any 타입으로 추론, 에러는 나지 않음

  • 하지만 배열에  대한 정확한 타입 검사가 이뤄지지 않음
  • 원칙에 따라 직접 타입을 표기해준다.
const arr : string[]= [];

 

 

배열에 추가할 경우 -> 타입 바뀜

const arr =[];
arr.push('1');
arr;		//1
arr[1] = 3;
arr;		//2
  • 1 arr은 string[]으로 추론
  • 2 arr은 (string | number)[]로 추론

 

배열 요소 제거할 경우 -> 이전으로 돌아가지 않음

const arr =[];
arr.push('1');
arr;
arr[1] = 3;
arr;

arr.pop();
console.log(arr)
  • pop()을 이용해 요소를 제거해도

  • 변함없음

 

연산

숫자나 문자열 타입과 연상할 때 타입이 바뀌기도 함

const a : any = '123';
const an1 = a + 1;
const nb2 = a - 1;
const st1 = a + '1';
  • + 연산 --> any (다른 피연산자가 숫자인 경우 a따라 다르기 때문)
    1. a 가 숫자일지도? --> 결과 숫자
    2. a가 문자열일지도? --> 결과 문자열
  • - , / , * 연산 --> number
  • 문자열과 --> string

 

 

명시적으로 any 반환하는 경우

fetch('url').then((response)=>{
    return response.json();
}).then ((result)=>{});

const result = JSON.parse('{"hello":"json"}')

  • 두 result가 모두 any로 추측됨

 

방지하기

fetch('url').then<{data : string}>((response)=>{
    return response.json();
}).then ((result)=>{});

const result : {hello: string} = JSON.parse('{"hello":"json"}')

 

 

 

 


2.7.2 unknown

: any와 비슷하게 모든 타입을 대입할 수 있지만, 그 후 어떤 동작도 수행 불가

 

const a : unknown = 'hello';
const b : unknown = 'world';

a+b;
a.slice();
  • unknown 타입을 사용해 동작을 시도할 경우

  • 모두 에러로 처리됨
  • any와 같이 모든 동작을 허용하는 상황은 발생하지 않음

 

 

unknown 역시 직접 표시할 경우는 거의 없고, try catch문에서 unknown을 보게됨

try {
} catch (e) {
    console.log(e.message)
}

  • e가 unknown이므로 어떠한 동작도 불가능
  • catch 문의 e에는 any, unknown 외 타입 표기 불가능

 

as로 타입을 주장(type assertion) 가능

try {
} catch (e) {
    const error = e as Error;
    console.log(error.message);
}

 

 

또 다른 타입 주장 방법 : <>

--> 나중에 React의 JSX와 출동하므로 <> 대신 as 사용 권장

try {
} catch (e) {
    const error = <Error>e;
    console.log(error.message);
}

 

 

 

항상 as를 사용해 다른 타입으로 주장하는 건 불가!

  • 위와 같은 행위는 실수일 것이라는 에러 메세자

 

강제 변환 방법

const a : number ='123' as unknown as number
  • unknown으로 주장 후 원하는 타입으로 다시 주장

 

 

!(non-null assertion) 연산자

: null 과 undefined 가 아님을 주장하는 연산자

  • param이 null 또는 undefined일 수도 있으니, slice 사용 불가
function a(param : string | null| undefined) {
    param!.slice(3);
}
  • !를 사용해 해결

 

 


2.7.3 void

 - 함수의 반환값을 무시하도록 하는 특수한 타입

 - 목적

  • 사용자가 함수의 반환값을 사용하지 못하도록 제한
  • 반환값을 사용하지 않는 콜백 함수를 타이핑할 때 사용

 

  • 반환값이 없는 경우 void 타입으로 추론
  • 자바스크립트 - undefined 반환
    • 타입스크립트로 마찬가지지만, 타입은 void

 

 

const func: () => void = () => 3;
const value = func();
const func2 = () : void => 3;
const func3: () => void | undefined = () => 3;
  • func 
    • 함수 전체의 타입을 표기한 코드
    • 반환값 타입이 void 임에도 3 반환시 에러 X  --> undefined 외의 값 반환을 막지 않음

 

  • value
    • void를 반환받은 값의 타입은 void가 됨 --> 사용자의 함수 반환값 사용을 막음

 

  • func2
    • 반환값만 따로 표기하는 경우 --> 반환값 무시 X

 

  • func3
    • void와 다른 타입의 유니언이면 반환값 무시 X

 

 

void의 반환값 무시 특성 활용 --> 콜백함수

[1,2,3].forEach((v)=>v);
[1,2,3].forEach((v)=> console.log(v));
  • forEach 메서드 : 배열을 순회하며 각 요소에 적용하게 될 콜백함수를 전달
  • [1,2,3].forEach((v)=>v);
    • 숫자 반환
  • [1,2,3].forEach((v)=> console.log(v));
    • undefined 반환 (console.log의 반환값이 undefined) 

 

 --> 콜백함수의 타입은?    

[1,2,3].forEach((v)=> v.toString());
  • 위와 같이 사용한 경우는 어떻게??

 

--> 콜백함수는 미리 타이핑하기 곤란 -> 어떠한 반환값이든 다 받을 수 있는 void 등장!

(v : number) => void
  • 콜백함수를 위와 같이 타이핑해 해결

 

 

 


2.7.4 {}, Object

: null과 undefined를 제외한 모든 값

: object와 다른 타입으로 대문자 Object

: 사용할 일은 별로 없지만, if문 안에 unknown 타입을 넣을 때 볼 수 있음

 

 

const obj : {} = {name:'zero'}
const arr : {} = []
const func : {} = () => {};
console.log(obj.name)
arr [0]
fun()

  • {}타입 변수를 실제로 사용하면 에러 발생

 --> 실제로 사용할 수 없어 {} 타입은 대부분 쓸모 없는 타입

 

객체를 의미하는 object 타입도 마찬가지

  • 타입스크립트엔 object가 아닌 객체 리터럴 타입으로 지정하면 객체를 사용 가능하다

 

 

{} 타입 + null, undefined 타입 -> unknown과 비슷

const unk : unknown = 'hello';
unk;
if (unk){
    unk;
    console.log(1)
}
else {
    unk;
    console.log(2)
}

  • 실제로 unknown 타입을 if 문으로 걸러보면 {} 타입이 나옴

 

 

 


2.7.5 never

: 어떠한 타입도 대입 불가

 

함수 선언문

function neverFunc1(){
    throw new Error('에러')
}

const result1 : never = neverFunc1();

  • 함수 선언문의 경우 throw를 해도 void 타입 반환
  • 에러 발생 : never 타입 변수에 void 타입 변수 대입 불가

 

 

함수 표현식

const neverFunc2 = () => {
    throw new Error('에러')
}

const result2 : never = neverFunc2();
  • 함수 표현식은 never 타입 반환
  • never 타입인 변수 result2에 대입 가능

 

무한 반복문을 가진 함수 (함수 표현식)

const infinite = () => {
    while(true){
        console.log('무한 반복')
    }
}

  • 함수가 값을 반환하지 않음 --> 이 경우에도 never 타입 반환
  • 함수 선언문일 경우 void 반환

 

 

function strOrNum (param : string|number){
    if (typeof param === 'string'){}
    else if (typeof param === 'number'){}
    else{
        param;
    }
}

  • 위의 경우 param은 string 아니 number임
  • else 문이 실행될 일은 없어 param은 never로 추론

 

 

never 직접 쓰는 경우

function neverFunc1() : never {
    throw new Error('에러');
}

function infinite() : never {
    while(true){
        console.log('무한 반복')
    }
}
  • 함수 선언문의 경우 void를 반환하므로 never로 직접 표기

 

 

 


2.7.6 타입 간 대입 가능표