저번 벨로그에서 타입 선언과 타입 추론에 대해서 알아보았다
[TS] (2) 기초 : 타입 선언과 타입 추론
이제는 타입을 적을 위치에 들어갈 기본적인 타입들에 대해서 공부해보자!!// 여기 들어갈 타입? someVariable: ?????;
// 예시
let unde: undefined;
let e:null;
const obj = {
key: "hello", // 프로퍼티의 값의 타입으로 추론됨
};
const fun4 = (a=1, b:string)=> { // 기본 값이 있고 그 값이 원시 타입인 경우 타입 선언 생략 가능
console.log(a)
console.log(b)
}
fun4(2,"hello")
const objDeep = {
key1: "sdfsdf",
key2: {
name: "kim",
job: "developer",
},
isMale: true,
};
// 객체(타입 선언 필요함) : arr 대응하는 프로퍼티의 타입이 tuple(길이 고정, 각 인덱스의 타입 정해짐)이었으면 좋겠다. 이 때는 타입을 모두 선언해주어야 함.
// 타입 선언을 하지 않으면 arr 프로퍼티의 타입이 유니온 타입(추후 설명)으로 결정됨(x)
const typeNeeded: {
key1: string;
key2: {
name: string;
job: string;
};
arr: [number, boolean, string];
} = {
key1: "sdfsdf",
key2: {
name: "kim",
job: "developer",
},
arr: [2, true, "hello"],
};
우리가 원하는 arr의 타입이 tuple(길이가 고정, 각 인덱스 타입 고정인 배열) 이라면 선언 필요(이후 설명)
- 타입 선언했을 때 arr(tuple 타입)
- 타입을 선언하지 않았을 때 arr(union 타입)
알아야 할 것 : 배열 관련 타입은 원래 자바스크립트에서는 객체 타입에 포함되었으나, 타입스크립트에서는 명시적으로 다른 타입으로써 선언 가능하다. (물론 자바스크립트로 컴파일되면 객체 타입이다 ㅎㅎ)
// 배열 타입 선언하기(추론 없이)
const arr1: string[] = ["Hello","Bye"]; // string으로만 이루어진 배열 타입
const arr2: (string | number)[] = ["Hello",12]; // string이나 number 타입만 가능(union 타입 포함됨. 이후 다룰 것!)
let arr3: string[];
const arr1 = ["Hello","Bye"]; // 사실 위처럼 타입 선언할 필요 없다. 아래 이미지 참고
const arr2 = ["Hello", 12]; // string이나 number 타입 항목이 들어간 배열을 원한다면
// 여기도 마찬가지로 선언할 필요 없다. 아래 이미지 참고
let arr2: string[]; // 변수 선언만 할 때는 타입 선언을 해줘야 함
// Good
const arr4: [number, string, () => number] = [
12,
"Hi",
() => {
return 3;
},
]; // 배열의 길이가 3이고, 배열 내 항목의 타입이 인덱스 순서대로 number, string, number를 return하는 함수(이후 설명 예정)
// 위 코드에서 타입 선언을 제외하면 그저 number 혹은 string 혹은 function 타입을 가지는 유니온 타입의 배열이 되어버린다.
// Bad
const arr4 = [
12,
"Hi",
() => {
return 3;
},
];
// 아래 이미지 참고!
이런 메서드를 안쓰는 것도 좋으나, 아예 이런 걸 막고 싶다면 좀 더 복잡한 타입 선언이 필요할 듯 하다.
아직 나는 초보라서 다음에 알아보자. ㅠㅠ
[stackoverflow] tuple에 적용되는 메서드에 대한 질문
타입 특징
- 가장 자바스크립트처럼 사용할 수 있는 타입이며, 잘못 사용하면 타입스크립트를 사용하는 의미가 희석될 수 있다.
- 모든 타입을 할당받을 수 있다.
- 타입 검사가 필요한 모든 과정을 지나친다. 웬만하면 unknown 타입을 사용하자.
타입 선언 : any
let anyType: any; // any 타입
let b: any[] = [] // any[] 타입
console.log(anyType.push("Hello")); // 컴파일 에러가 발생하지 않음. 런타임 에러 예상됨..
let a; // any 타입 추론
// 'a' 변수는 암시적으로 'any' 형식이지만, 사용량에서 더 나은 형식을 유추할 수 있습니다.
let b = [] // any[] 타입 추론
let unknownType: unknown;
unknownType = 12;
let unknownArray: unknown = ["dfd"];
console.log(unknownType.push("Hello")); // 에러 발생
let unknownType: unknown;
unknownType = 12;
let unknownArray: unknown = ["dfd"];
if (Array.isArray(unknownType)) {
console.log(unknownType.push("Hello")); // 에러 없음!
}
타입 특징 : 두 개 이상의 타입을 할당할 수 있다. 'or'으로 이해하면 편하다.
타입 선언 : 타입 | 타입 | 타입 ...
let stringOrNumber: string | number;
let c = "sdf" || 12 // c: string | number 추론
c = true // 'boolean' 형식은 'string | number' 형식에 할당할 수 없습니다.
const arr5 = [12, "sdf"] // arr5: (number | string)[] 추론 <- 위에서 많이 봤죠?
타입 특징
- 문자열 리터럴 자체를 타입으로 지정하여, 해당 변수가 그 타입의 값만 가질 수 있도록 제한하는 유니크한 타입이다.
- 보통 union 타입과 같이 사용하여 특정 상수만 허용하고 싶을 떄 선언한다.
타입 선언: 문자열 리터럴
let d: "frontend"| "backend";
d = "I love you" // '"I love you"' 형식은 '"frontend" | "backend"' 형식에 할당할 수 없습니다.
IDE(나의 경우 vscode)의 지원 : (큰 / 작은) 따옴표 입력 시
더 자세한 설명은 다른 분이 올려주신 좋은 글이 있다.
TypeScript enum을 사용하는 이유
이론
Handbook - Enums - TypeScript
enum과 tree-shaking 관한 글
TypeScript enum을 사용하지 않는 게 좋은 이유를 Tree-shaking 관점에서 소개합니다.
// 숫자 열거형 : 초기화 안함(기본 0부터)
enum WebDeveloper {
FRONTEND,
BACKEND,
}
console.log(WebDeveloper.FRONTEND) // 0
console.log(WebDeveloper.BACKEND) // 1
// 숫자 열거형 : 초기화 (초기화한 다음 인덱스부터 차례로 1씩 증가. 전 인덱스에는 영향 없음)
enum Browser {
CHROME,
SAFARI,
WHALE = 10,
BRAVE,
}
console.log(Browser.CHROME) // 0
console.log(Browser.SAFARI) // 1
console.log(Browser.WHALE) // 10
console.log(Browser.BRAVE) // 11
// 문자열 열거형 : 초기화 (문자열 초기화된 이후 항목들은 초기화해야 함). 유의미한 정보 전달
enum Browser {
CHROME = "ch",
SAFARI = "sa",
WHALE = "wh",
BRAVE = "br",
}
console.log(Browser.CHROME) // "ch"
console.log(Browser.SAFARI) // "sa"
console.log(Browser.WHALE) // "wh"
console.log(Browser.BRAVE) // "br"
// 이종 열거형 : 여러 개의 타입으로 초기화(굳이 사용할 필요 없음)
enum Browser {
CHROME = "ch",
SAFARI = 10,
WHALE,
BRAVE ,
}
console.log(Browser.CHROME); // "ch"
console.log(Browser.SAFARI); // 10
console.log(Browser.WHALE); // 11
console.log(Browser.BRAVE); // 12
// 함수의 return값 타입을 undefined로 하려면 const undefinedFunc = (): undefined => { return; }
// void
const voidFunc = (): void => {
console.log("Hello");
};
console.log(voidFunc) // undefined
// void
const voidFunc = () => {
console.log("Hello");
};
console.log(voidFunc) // undefined
// never
const neverFunc = (): never => {
throw { message: "에러입니다", errorCode: 500 }; // error 발생
};
const infiniteFunc = (): never => {
while (true) {} // 무한 루프
};
const returnErrorFunc = (): never => {
return neverFunc(); // never값을 return하는 함수
};
// never 타입 추론
const neverFunc = () => {
throw { message: "에러입니다", errorCode: 500 };
};
const infiniteFunc = () => {
while (true) {}
};
const returnErrorFunc = () => {
return neverFunc();
};
let getFunc: () => number;
// 매개변수는 없고, return 값이 number 타입인 함수 타입
let getFunc2: (a: number, b: number) => string;
// 2개의 number 타입 매개변수를 가지고, return 값이 string 타입인 함수 타입
let funcType2 = (a: number, b: string) => {
return a.toString() + b;
};
// return 타입은 선언하지 않았으나 return 값이 string인 것이 명확하므로 string 타입으로 추론된다.
TypeScript Compiler에 대해서...