
뭐든지 할 수 있지만 꼭 필요한 상황이 아니라면 사용하지 않는 것이 좋다.
any를 사용하면 자바스크립트 처럼 동작하기 시작하면서 타입 검사기의 의미가 사라진다.
let a: any = 666;
let b: any = ['hello'];
let c = a + b; // 아무런 문제가 발생하지 않음
let a : unknown = 30
let b = a===123 // boolean let a : unknown = 30
let b = a===123 // boolean
let c = a+10 // 에러: 타입이 unknown이다. 비교연산과 반전연산이 아닌경우 타입 정제가 필요
if(typeof a=== 'number'){
let d = a+10 // number
} let a = true // boolean
const b = false // false모든 숫자 (정수, 소수, 양수, 음수, Infinity, NaN 등)의 집합이다.
덧셈(+), 뺄셈(-), 모듈로(%), 비교(<) 등 숫자 관련 연산을 수행할 수 있다.
꿀팁 : 긴 숫자를 처리할 때는 숫자 분리자를 이용해 숫자를 읽기 쉽게 만들 수 있다. -> let oneMillion = 1_000_000 // 1000000과 같음
자바스크립트, 타입스크립트는 구조기반 타입을 갖도록 설계되어 있다.
구조기반 타입화는 객체의 이름에 상관없이 객체가 어떤 프로퍼티를 갖고 있는지를 따진다.(덕 타이핑)
type Food = {
protein: number;
fat: number;
};
function calculateCalorie(food: Food) {
return food.protein * 4 + food.fat * 5;
}
// Food 형식에 맞는 값
const a = {
protein: 30,
fat: 50,
};
// Food 형식 + sugar 추가
const b = {
protein: 20,
fat: 20,
sugar: 50,
};
// Food 형식에 맞지 않는 값
const c = {
protein: 20,
sugar: 50,
};
calculateCalorie(a);
calculateCalorie(b);
calculateCalorie(c); // 형식에 맞지 않으므로 에러발생
// 단 이 경우는 안됨, 다른 개발자에게 오해를 불러 일으킬 수 있고, 오타가 발생해도 오류가 발생하지 않는 이유 때문에 지원하지 않는다고 함
// 자세한 부분은 -> https://toss.tech/article/typescript-type-compatibility
const tmp = calculateCalorie({
protein: 20,
fat: 20,
sugar: 50,
}); // Food 형식에 sugar가 없습니다.
객체는 let, const로 선언하는 경우 차이가 없다. 즉 객체의 경우 수정 가능성을 염두에 두고 더 넓게 추론하기 때문에 const로 사용한다고 해서 더 좁은 타입으로 추론하지는 않는다.
아래의 4가지 중 2번째가 베스트, 다음은 object가 좋으며, 나머지 2개는 피해야 한다.
object로 선언 ⇒ 좋지 않음
any보다 조금 더 좁은 타입
정보를 거의 알려주지 않고 그저 값 자체가 객체다 라는 정보만 알려준다.
let a:object = {
b:'x'
}
a.b // 에러발생 : 'object' 형식에 'b' 속성이 없습니다.
객체 리터럴 문법
옵셔널 속성 : ?를 추가해서 사용하며 속성이 있어도 되고, 없어도 되도록 사용
인덱스 시그니처 : [key:T]:U의 형태로 사용 ⇒ 모든 T타입의 키는 U타입의 값을 갖는다. ⇒ 단 여기서 키(T)는 number나 string 타입
readonly 한정자를 이용해 특정 필드를 읽기전용으로 정의할 수 있다.⇒ 즉 수정할 수 없도록 함 ⇒ 변수에서 const 역할
아래와 같이 사용
let a: {
b: number;
c?: string; // 옵셔널
[key: number]: boolean; // 인덱스 시그니처
};
빈 객체 리터럴 표기법({})
Object 타입
type Age = number;
type Person = {
name:string,
age:Age
}
let driver:Person = {
name:'Mr.Kim',
age:20
}
| 기호를 사용한다.
type Cat = { name: string; purrs: boolean };
type Dog = { name: string; barks: boolean; wags: boolean };
type CatOrDog = Cat | Dog;
// test가 Cat인 경우
let test: CatOrDog = {
name: 'chiman',
purrs: true,
};
// test가 Dog인 경우
test = {
name: 'chiman',
barks: true,
wags: true,
};
// test가 Dog, Cat 모든 속성을 가진 경우
test = {
name: 'chiman',
purrs: true,
barks: true,
wags: false,
};
함수의 매개변수의 경우 유니온 타입을 사용하면 공통된 부분을 제외하고 나머진 에러가 발생한다.
-> 타입스크립트 관점에서는 prop이 Cat 타입이 올지 Dog 타입이 올지 알 수가 없기 때문에 어느 타입이 들어오든 간에 오류가 안 나는 방향으로 타입을 추론하게 되기 때문입니다.
function unionTest(prop:Cat|Dog){
console.log(prop.name)
console.log(prop.purrs); // 에러 발생 : 'Cat | Dog' 형식에 'purrs' 속성이 없습니다.
console.log(prop.barks); // 에러 발생 : 'Cat | Dog' 형식에 'barks' 속성이 없습니다.
console.log(prop.wags); // 에러 발생 : 'Cat | Dog' 형식에 'wags' 속성이 없습니다.
}
만약 타입가드를 사용하지 않는다면 공통된 속성만 사용할 수 있고, 다른 속성도 사용하기 위해선 타입가드를 통해 정제해서 사용해야 합니다.
function unionTest(prop: Cat | Dog) {
console.log(prop.name);
if ('purrs' in prop) {
console.log(prop.purrs);
}
if ('purrs' in prop) {
console.log(prop.purrs);
}
if ('barks' in prop) {
console.log(prop.barks);
}
if ('wags' in prop) {
console.log(prop.wags);
}
}
&기호를 사용합니다
type Cat = { name: string; purrs: boolean };
type Dog = { name: string; barks: boolean; wags: boolean };
type CatAndDog = Cat & Dog;
let test: CatAndDog = {
name: 'chiman',
purrs: true,
barks: false,
wags: true,
};
사용방법은 2가지가 있다 -> 성능, 의미상 두 표현은 같다.
T[]Array<T>
let a:string[]
let b:Array<string>
객체와 마찬가지로 배열을 const로 만들어도 타입스크립트는 타입을 더 좁게 추론하지 않는다.
const test1 = [1, 2, 3]; // number[]
let test2 = [1, 2, 3]; // number[]
const test3 = [1, 2, 3] as const; // readonly [1,2,3]
let test4 = [1, 2, 3] as const; // readonly [1,2,3]
길이가 고정되었고, 각 인덱스의 타입이 알려진 배열의 일종이다.
let test1: [string, string, number] = ['chiman', 'chiHwan', 1234];
test1 = ['chiman', 'chiHwan', true, 1234]; // // boolean 형식은 'number' 형식에 할당할 수 없습니다.
let test2: [string, string, number, boolean?] = ['chiman', 'chiHwan', 1234];
test2 = ['chiman', 'chiHwan', 1234]; // 선택형이라 없어도 가능
test2 = ['chiman', 'chiHwan', 1234, true]; // 선택형이라 있어도 가능
test2.push(4); // 튜플은 push가 가능
console.log(test2); // [ 'chiman', 'chiHwan', 1234, true, 4 ]
let test3: [string, boolean, ...number[]] = ['chiman', true, 1, 2, 3, 4, 5];
const test1: readonly boolean[] = [true, true, false];
console.log('test1', test1); // [true, true, false]
let test2 = test1.concat(true);
console.log('test2', test2); // [true, true, false, true]
let test3 = test1.push(false); // 'readonly boolean[]' 형식에 'push' 속성이 없습니다.
type A = readonly string[];
type B = Readonly<string[]>;
type C = ReadonlyArray<string>;
// number | null타입
function numberOrNull(x:number){
if(x<10){
return x
}
return null
}
let test = null // any
const test2 = null // null
let test = undefined // any
const test2 = undefined // undefined
function voidFn() {
console.log("This is my warning message");
}
// never를 반환하는 함수는 함수의 마지막에 도달할 수 없다.
function error(message: string): never {
throw new Error(message);
}
// never를 반환하는 함수는 함수의 마지막에 도달할 수 없다.
function infiniteLoop(): never {
while (true) {}
}
enum Language {
English,
Spanish,
Russian,
Korean,
}
console.log(Language.Korean); // 3
console.log(Language['Korean']) // 3
console.log(Language[3]); // Korean
기본적으로는 멤버의 순서대로 0부터 숫자를 할당하지만 다른 숫자로 할당할 수 있습니다.
enum Language {
English = 5,
Spanish,
Russian,
Korean,
}
console.log(Language.Korean); // 8
console.log(Language[3]); // undefined
console.log(Language[8]); // Korean
문자열도 할당 가능합니다.
대신 그 다음부터는 직접 할당해야하며, 할당하지 않으면 에러가 발생합니다.
enum Language {
English = 'english',
Spanish = 'spanish',
Russian = 'russian',
Korean, // 에러발생
}
const enum Language {
English,
Spanish,
Russian,
Korean,
}
console.log(Language.Korean); // 3
console.log(Language[3]); // 에러발생