들어가며
이번 블로그 글은 어떤 주제를 쓸까 고민하다 익명의 선임님께서 주신 이펙티브 타입스크립트 책이 생각나 들여다보다 타입추론 부분을 읽고 그동안 타입스크립트를 제대로 이해하지 못하고 쓴 게 아닌가라는 생각이 들어서, 왜 그렇게 느꼈는지 글로 남겨보려 합니다.
타입추론, 타입명시
3장 타입추론에 이런 구문이 있습니다.
‘타입스크립트 초보자와 숙련자는 타입 구문의 수에서 차이가 납니다. 숙련된 타입스크립트 개발자는 비교적 적은 수의 구문(그러나 중요한 부분에는 사용)을 사용합니다.’
이 부분을 읽고 ‘어라 타입은 많이 지정할수록 좋은 게 아닌가’라는 기존 생각이 흔들렸습니다.
예를 들어보면 변수 x는 12인 코드를 작성해 보겠습니다.
let x: number = 12;
타입스크립트로 작성할 때 위의 방법으로 하고 계시진 않나요?
x: number
라고 타입을 적어주는 형태를 타입명시라고 합니다. 하지만 이 책에서는 number타입을 명시하는 건 오히려 방해되고 불필요하다고 나와있습니다.
아래처럼 간단하게 표현하는 것이 좋다고 합니다.
let x = 12;
왜 이렇게 사용하라고 할까요?
타입스크립트에는 타입추론이라는 개념이 있기 때문입니다.
타입추론은 변수나 함수의 반환값 등을 보고 해당 값이 어떤 타입인지 컴파일러가 문맥까지 자동으로 유추해 주는 것을 말합니다. 이를 통해 프로그래머는 변수나 함수의 반환값에 대해 직접 타입을 명시하지 않아도 되므로 코드 작성이 간편해집니다.
타입추론이라는 개념이 있기 때문에 위의 예제에서 컴파일러가 x = 12;
를 통해 number타입이라는 것을 알고 있다는 것이죠!
코드를 통해 확인해 보면 x에 타입명시를 하지 않았는데 빨간 줄이 그어진 걸 볼 수 있습니다.
이런 타입추론은 Best Common Type 을 이용해 추론합니다.
let x = [0, 1, null];
x의 타입을 추론하려면 각 배열의 요소 타입들을 고려해야 합니다. number, null 중 가장 일반적인 타입 알고리즘은 각각의 타입을 고려 다른 모든 후보와 호환되는 타입을 결정합니다.
이렇게 멋진 타입추론에도 주의할 점이 있습니다.
타입추론이 가능하다면 타입은 쓰지 않는 게 좋은 것일까요? 아닙니다, 추론이 가능한 경우라도 객체 리터럴과 함수 반환에는 타입명시를 고려해야 한다는 것입니다.
객체 리터럴 타입
상품의 id, name을 콘솔로 찍는 logProduct
함수를 이용해 pecil
과 earser
값을 알아보려 합니다.
interface Product {
id: number;
name: string;
}
const logProduct = (product: Product) => {
const { id, name } = product;
console.log(id, name);
};
const pencil: Product = {
id: 1,
name: 'pencil',
};
const eraser = {
id: '2',
name: 'eraser',
};
코드 예제를 보면 eraser
의 id값이 string 타입으로 잘못 들어가 있습니다.
하지만 코드에서 에러를 발견할 수 없죠.
그렇습니다 logProduct
함수를 실행하기 전까지 에러를 알 수 없는 치명적인 상태가 발생하는 것이죠.
이를 예방하기 위해 a처럼 Product
라는 타입으로 명시해야 합니다.
const b: Product = {
id: '2',
name: 'b',
};
타입명시를 통해 logProduct
를 실행하기 전에 에러를 알 수 있습니다.
예제를 통해 테스트 해보세요.
함수반환
코드 구현 단계에서의 오류를 호출하는 곳까지 영향을 미치지 않게 하기 위해서는 함수의 반환값에도 타입명시를 하는 게 좋습니다.
여기 숫자를 넘겨받고 싶은 함수가 있습니다.
하지만 이 함수는 오류가 있습니다! 무엇일까요?
우리가 원하는 number 타입의 값이 아닌 콘솔에 찍힌 값은 ‘5’ 바로 string 값이라는 것입니다.
여기서 중요한 건 우리는 콘솔로 찍기 전까지 오류를 알 수 없다는 것입니다. 여기서 반환값에 타입을 명시하게 된다면
우리가 원하는 건 number값인데 구문이 틀렸어! 라고 미리 알 수 있게 됩니다.코드를 통해 확인해 보세요.
이렇게 반환타입을 명시하게 되면 함수에 대해 더욱 명확히 알 수 있다는 장점이 생기게 됩니다.
만약 실무에서 eslint를 사용하게 된다면 규칙 중 no-inferrable-types
를 통해 작성된 타입 구문이 정말로 필요한지 확인해 볼 수 있습니다.
마치며
타입추론과 타입명시에 대해 알아보았는데요,
그동안 코드작성 시 너무 많은 타입명시를 하지 않았나 되돌아보는 시간이 되었고 실행 단계가 아닌 구현 단계에서의 오류를 잡아내는게 중요하는 것을 깨달았습니다.
이 글을 읽는 분들 모두 타입추론과 타입명시를 적절히 사용하시면서 즐거운 타입스크립트 코딩 하셨으면 좋겠습니다.
감사합니다.
참고자료
- 이펙티브 타입스크립트 책
- Type Inference