Type Annotation 이란 다음과 같이 타입을 지정해주는 것을 말한다.
const num = 123;
변수명 뒤에 : [타입]
을 붙여 타입을 지정해준다.
const num: number = 123;
💡 Primitive
• 불변
• 객체가 아닌 값
JavaScript의 원시값으로는 7가지가 존재한다.
- string
- number
- bigint
- boolean
- undefined
- null
- symbol
const str: string = 'STRING'
const num: number = 123
const bool: boolean = true
// 타입 추론 가능
const str = 'STRING'
const num = 123
const bool = true
// 값 자체를 갖도록 할 수 있다.
// 이때 지정한 타입과 다른 값을 할당하면 Error
const str: 'STRING' = 'STRING'
const num: 123 = 123
const bool: true = true
object
타입을 지정해주는 것은 any
를 지정하는 것과 다를바 없다.
const obj: object = {
str: "str",
num: 123,
child: {
str: "str",
num: 123,
},
};
obj.num // --> num 을 찾지 못함
더 상세하게 타입을 지정해줄 필요가 있다.
객체 리터럴 / 싱글 리터럴 방법을 활용하여 다음과 같이 타입을 지정해준다.
// 객체 리터럴 | 싱글 리터럴
const obj2: { str: string, nu: number } = {
str: "str",
num: 123
};
console.log(obj2.num); // 123
const obj3: {
str: string;
num: number;
child: {
str: string;
num: number;
};
} = {
str: "str",
num: 123,
child: {
str: "str",
num: 123,
},
};
console.log(obj3.child.str); // str
함수의 타입을 지정할 때는 매개변수 와 리턴 2 가지 타입을 명시해 주어야 한다.
여기서 리턴 타입의 경우 어느정로 타입 추론을 유도할 수 있다.
function func(num: number, str: string): string {
return num + str
}
func(123, 'str')
function func2(num1: number, num2: string): number {
return num1 + Number(num2)
}
func2(123, '123')
▶ void 타입
리턴 타입이 void
이면 아무것도 반환하지 않는다.
function func3(num1: number, num2: string): void {
console.log(num1 + num2)
}
func3(123, '123')
▶ Function 타입
Function 타입을 사용하는 것은 좋지 않다.
되도록 사용하지 않도록 한다.
function func3(num1: Function, num2: Function): Function {
console.log(num1 + num2)
}
func3(123, '123')
▶ 함수 표현식
const func4 = (str1: string, str2: string): string => {
return str1 + ' ' + str2
}
func4('hello', 'world')
리턴은 타입 추론이 잘 되는 편이므로 모조건 타입을 지정해야 하는 것은 아니다.
적어도 매개변수에는 타입을 지정해주는 것이 좋다.
const func4 = (str1: string, str2: string) => {
return str1 + ' ' + str2
}
func4('hello', 'world')
const func5 = (obj: { str1: string, str2: string }) => {
return obj.str1 + ' ' + obj.str2
}
func5({ str1: 'hello', str2: 'world' })
배열 자체는 JavaScript 에서 객체로 취급된다.
▶ 한 가지 타입으로만 이루어진 배열
배열의 타입을 지정하는 방법은 2 가지가 있다.
: 타입[]
: Array< 타입 >
const strArr: string[] = ['str', 'str2', 'str3']
const strArr2: Array<string> = ['str', 'str2', 'str3']
const numArr: Array<number> = [1, 2, 3]
const boolArr: boolean[] = [false, true, false, true]
strArr.push(1) // 동작 x
numArr.push('str') // 동작 x
boolArr.push(false) // 동작 o
▶ Tuple
하나의 배열 안에 여러 타입이 섞여 있을 경우, Tuple 로 만들어야 한다.
💡 Tuple 파트에서 살펴보도록 하자.
const arr = ['str', 123, false]
💡 Literal Type
TypeScript에서 특정 타입이 가질 수 있는 하나의 값을
리터럴 타입( Literal Type ) 이라고 한다.
다음 예시의 각 변수 타입을 잘 살펴보자.
let
으로 정의한 변수는 string 과 number 타입이고,
const
로 정의한 변수는 할당한 값 자체로 지정되어 있다.
// --- Ex 1 --- //
let letString = 'Hello'
letString // type: string
const constString = 'Hello'
constString // type: "Hello"
// --- Ex 2 --- //
let letNumber = 123
letNumber // type: number
const constSNumber = 123
constSNumber // type: 123
그 이유는 let
으로 정의한 변수는 재할당이 가능하지만,
const
로 정의한 변수는 재할당이 불가하기 때문이다.
// --- Ex 1 --- //
// let
let letString = 'Hello'
letString = letString + ' World' // 재할당 가능
console.log(letString) // Hello World
letString // type: string
// const
const constString = 'Hello'
constString // type: 'Hello'
// --- Ex 2 --- //
// let
let letNumber = 123
letNumber = letNumber + 123 // 재할당 가능
console.log(letNumber) // 246
letNumber // type: number
// const
const constNumber = 123
constNumber // type: 123
💡 Tuple Type
- 길이 고정 & 인덱스 타입 고정되는 배열
- 여러 다른 타입으로 이루어진 배열을 안전하게 관리 가능
- 배열 타입의 길이 조절
▶ 한 가지 타입으로만 이루어진 배열
다음은 앞서 살펴보았던 한 가지 타입으로만 구성된 배열이다.
const arr: string[] = ['A', 'B', 'C']
▶ 여러 타입으로 구성된 배열
여러 타입으로 구성된 배열은 다음과 같이 타입을 지정한다.
const tuple: [number, string] = [1, 'A']
▶ 길이 조절
Tuple 타입은 배열의 길이를 가변적으로 제어할 수 있다.
// 첫 번째에는 number 타입이 와야 하고,
// 그 뒤로는 string 타입이 얼마든지 들어올 수 있다.
const tuple2: [number, ...string[]] = [0, 'A', 'B']
▶ 읽기 전용
Tuple 타입은 "읽기 전용"으로 지정할 수 있다.
💡 이 내용은 조금 뒤에 살펴보도록 하자.
▶ Union Type 으로 변경
Tuple 타입이 변환되면 Union type 으로 바뀌는 경우가 있다.
💡 이 내용도 조금 뒤에 살펴보도록 하자.
const tuple0: (string | number)[] = [1, 'A']
💡 undefined & null
undefined
와null
은 JavaScript 의 원시값이다.
이 둘은 TypeScript 에서도 고유한 특별한 타입으로 인정된다.
이외에도 TypeScript 는void
,never
같은 더 세밀한 타입도 제공한다.
any, unknown, strictNullChecks 등의 기능이 있다.
( 특히, strictNullChecks가 핵심이다..!! )
const nu: null = null;
const un: undefined = undefined;
// 리턴 type : string | null (자동적으로 추론됨)
function sayHello(word: string) {
if (word === 'world') {
return 'hello' + word;
}
return null;
}
// 리턴 type : string | undefined ( 자동적으로 추론됨 )
function sayHello(word: string) {
if (word === 'world') {
return 'hello' + word;
}
return;
}
// 리턴 type : void ( 반환하는 것이 없으므로 자동으로 void 가 붙음 )
function log(message: string | number) {
console.log(message)
}
💡 any
any
타입은 모든 값의 집합 이다.
any 는 되도록 사용하지 않는 것을 추천한다.
그 이유는 any 를 사용하게 되면 JavaScript 사용하는 것과 마찬가지이기 때문이다. 즉, TypeScript 를 사용할 이유가 사라진다.
TypeScript 는 noImplicitAny 과 strict 를 제공한다.
TypeScript 설정파일에서 noImplicitAny 혹은 strict 옵션을true
로 지정하면any
없이 사용할 수 있도록 하는 환경을 제공한다.
// 여기서 매개변수 anyParam 의 타입은 any 로 인식된다. (1)
function func(anyParam) {
// 배열에 없는 메서드를 사용해도 에러가 발생하지 않는다. (3)
// 런타임에서는 당연히 에러가 발생한다.
anyParam.trim()
}
func([1,2,3]) // 여기서 매개변수는 배열 (2)
💡 unknown
• 새로운 최상위 타입
• any처럼 모든 값을 허용하지만 상대적으로 엄격하다.
• TS에서 unknown으로 추론하는 경우는 없으니 개발자가 직접 명시해야 함
• assertion 혹은 타입 가드와 함께 사용
let num: unknown = 99;
if (typeof num === 'string') {
num.trim();
}
// (num as string).trim();
// function func(x: unknown) {
// let val1: any = x;
// let val2: unknown = x;
// let val3: string = x;
// let val4: boolean = x;
// let val5: number = x;
// let val6: string[] = x;
// let val7: {} = x;
// }
💡void 타입은 아무것도 리턴하지 않는다는 것을 의미한다.