📌 타입스크립트로 여러 프로젝트를 진행해왔는데, 제대로 정리한 적이 없어 차근차근 학습하며 기록하려고 한다. 이번 기회에 타입스크립트를 깊게 학습해보고 '제대로' 사용하는 법을 익혀야겠다.
이미 잘 설명되어있는 글이 많기 때문에, 간략하게 소개와 사용 이유에 대해 기록하고 가겠다.
타입스크립트
자바스크립트 기반 슈퍼셋(superset)으로, 동적 언어인 자바스크립트에
정적 타이핑을 지원하여 컴파일 단계에서 오류를 포착할 수 있게 도와준다.
=> 결국 돌아갈 때는 자바스크립트로 컴파일되어 사용된다.
타입스크립트를 사용하는 이유
1. 잠재적 버그 방지, 안정성 향상
2. 개발자 경험(DX), 협업 측면에서의 편리함
3. 바벨, 트랜스파일러를 사용하지 않아도, JS를 낮은 버전으로 컴파일 해줌
처음 접할 때에는 일일히 타입 지정해주고 오류 고치는게 너무 화났다. 하지만 프로젝트에서 사용해오다 보니 제대로 알고 사용했을 때 사람들이 말하는 장점에 공감할 수 있을 것 같다고 느꼈다.
타입스크립트는 제대로 알고 사용해야 장점을 모두 누릴 수 있다고 생각한다. 차근차근 학습하다보면.. 나도 타입스크립트 잘 쓰는 개발자? 🤔
제목에서 알 수 있다시피 이 글에선 타입스크립트에서 간단한 타입 지정을 어떻게 하는지, 그리고 유니언 타입과 타입 단언에 대해서 알아볼 것이다.
타입을 하나씩 다 설명하기 때문에 분량은 많지만 어려운 내용들은 아니니 심심하면(?) 쭉 읽어보기 좋을 것 같다.
const isModalOpen: boolean = true;
const money: number = 0;
const age: number = 3.119;
const userName: string = 'thisisname';
가장 흔하게 사용되는 세가지의 원시 타입이다. 위 예제에선 변수에 일일이 변수의 타입을 지정해줬지만, 사실 이렇게 할 필요가 없다. 변수를 생성하면, 타입스크립트는 타입 추론을 통해 알아서 타입을 부여해준다.
const userName = 'thisisname'; // const userName: string
const typeList = [1, '2', true];
// const typeList: (string | number | boolean)[]
위처럼 타입 지정을 안해줘도, 마우스를 올려보면 알아서 타입이 지정된걸 볼 수 있다. 이런 간단한 경우에는 타입 지정을 안해줘도 된다.
(모든 변수를 명시적으로 나타내는게 좋으면 해줘도 상관없다.)
const userID: number[] = [1, 2, 3];
or
const userID: Array<number> = [1, 2, 3];
배열 타입은 배열 요소들의 타입 뒤에[]
를 쓰는 것과 제네릭 배열 타입 두가지 방법으로 지정해줄 수 있다.
let message: [string, boolean];
message = ['thisisname', true];
message[5]; // 인덱스 '5'에 요소가 없습니다.
message[1].toLowerCase(); // boolean' 형식에 'toLowerCase' 속성이 없습니다.
튜플은 배열 요소의 타입, 개수가 고정된 배열을 표현할 때 사용한다. 인덱스를 넘어가는 값에 접근하거나 타입에 맞지 않는 메소드를 사용하면 오류가 발생한다.
열거형은 어떤 값이 이름이 있는 상수 집합에 속한 값 중 하나일 수 있도록 제한하는 기능입니다.
라고는 하는데, Enum 문서가 따로 있는 것을 보아 간단하게 어떤 타입인지만 알아보고 다음에 따로 글을 더 작성해야 할 것 같다.
enum List {
A = 1,
B = 3,
C = 4,
}
const A: List = List.A; // A === 1
console.log(List[4]); // C
Enum의 기본 동작으로, 멤버들의 번호을 0부터 순서대로 매긴다.
위 예제 코드에서는 값을 전부 지정해줬지만, 값을 지정해주지 않거나 멤버 중 하나에게 값을 줘 번호를 바꿀 수 있다.
또한, 매겨진 값을 이용해 위 예제처럼 멤버의 이름을 알아낼 수 있다.
const dontKnowType: any = 'dontKnowThisType';
dontKnowType.toFixed(); // 에러 발생 X
const dontKnownList: any[] = ['a', 1, true];
any는 특정 값을 모르거나, 어떤 값으로 인해 타입 검사 오류가 발생하는 것을 원하지 않을 때 사용할 수 있다. 즉, 타입 검사를 하지 않고, 구문 상 유효한 모든 동작을 할 수 있다.
정말 알지 못하거나 타입을 지정해줄 수 없을 때 사용하면 좋겠지만.. 오류가 뜬다고 무작정 any 타입을 사용하면 타입스크립트를 사용하는 이유가 사라진다. 되도록 사용을 지양하자.
알지 못하는 값을 처리하는덴 any보다 unknown 타입이 안전하다.
// 추론된 반환 타입은 void이다.
function doNothing() {
console.log('do Nothing!');
}
void 타입은 값을 반환하지 않는 함수의의 반환 값을 의미한다.
명시적으로 값을 반환하지 않거나, return 문이 없을 때 추론되는 타입이다.
const unknownData: unknown = 'unknownData';
unknownData.toLowerCase();
// 'unknown' 형식에 'toLowerCase' 속성이 없습니다.
unknown 타입은 '모든 값'을 나타낸다. any와의 차이점은, unknown 타입에 어떤 것을 대입하는 것이 유효하지 않다는 것이다. 때문에 any보다 안전하다는 특징이 있다.
function fail(msg: string): never {
throw new Error(msg);
}
function checkType(x: string | number) {
if (typeof x === 'string') {
x; // string 타입
} else if (typeof x === 'number') {
x; // number 타입
} else {
x; // 'never' 타입이 됨!
}
}
never 타입은 절때 관측될 수 없는 값을 의미한다.
ex) 함수 표현식에서 오류(예외)를 발생시킴, 프로그램 종료
또한 유니온 타입에 아무것도 남아있지 않는 상황(타입이 좁혀지는 상황)에도 나타난다. 타입 가드(Narrowing)과 관련이 있는 개념인 것 같다.
null과 undefined 타입의 동작 방식은, 개발 환경에서 tsconfig.json
파일에 strictNullChecks 옵션의 설정 값에 따라 달라진다.
strictNullChecks가 설정되지 않았을 때
- 어떤 값이 null, undefined여도 접근이 가능하다.
- 모든 타입의 변수에 할당이 가능하다.
.
이러한 검사의 부재는 보통 버그의 원인이 되기 때문에, 공식 문서에서도 해당 옵션을 설정하고 사용하는 것을 권장하고 있다.
strictNullChecks가 설정되었을 때
- 어떤 값이 null or undefined이면, 메서드나 프로퍼티를 사용하기 전 값을 테스트해야한다.
- 옵셔널 프로퍼티로 undefined 여부를 검사하는 것과 같이,
좁히기(Narrowing)을 통해서 null일 수 있는 값에 대한 검사가 가능하다.
// strictNullChecks가 설정되었을 때
function loggingPlus(a: number | undefined, b: number) {
if (a === undefined) return; // a가 undefined면, 아무 동작도 하지 않는다.
console.log(a + b);
}
// x는 null, undefined가 아니다.
function isNotNull(x: number | undefined) {
console.log(x!.toFixed());
}
또한 위 예제와 같이 단언 연산자 !
를 활용하여, x값이 null 또는 undefined가 아니라고 타입을 단언할 수 있다. (명시적 검사 X)
function loggingData(data: { a: string; b: number }) {
console.log(data.a, data.b);
}
loggingData({ a: 'A', b: 2 });
객체의 타입을 정의하려면, 해당 객체의 프로퍼티 / 각 프로퍼티의 타입을 지정해주면 된다. (위 예제와 같이 똑같은 형태의 복사본 느낌)
타입을 지정하지 않으면, 해당 프로퍼티는 any 타입으로 간주되니 주의하자.
function optionalData(data: { a: string; b?: number }) {
if (data.b !== undefined) console.log(data.a, data.b.toFixed());
// 혹은
console.log(data.a, data.b?.toFixed());
}
optionalData({ a: 'A' });
optionalData({ a: 'A', b: 2 });
또한 옵셔널 체이닝 ?
을 통해서 프로퍼티가 필수인지, 선택인지 지정해줄 수 있다.
자바스크립트에선 존재하지 않는 프로퍼티에 접근하면, 런타임 오류가 아닌 undefined 값을 얻는다. 때문에 옵셔널 프로퍼티를 읽을 때, 해당 값을 사용하기 전, undefined인지 확인해야한다.
이렇게 해서 기본적인 데이터 타입에 대한 정리가 끝났다. 사실 다른 내용이 더 있었는데, 쓰다보니 글이 생각보다 길어져 글을 두개로 나눠야할 것 같다. 다음 글에서는 유니온, 리터럴 타입과 타입 단언, 별칭에 대해서 알아볼 것이다. 👍
참고 문서