[TypeScript] 기본 타입

📌 Type annotation

const val: number = 123

 Type annotation: 변수 뒤에 ': number'로 타입을 지정해주는 것

형식은 다음과 같다.

value: type

 

🐵 원시 타입

Primitive (원시값)

: 불변, 객체가 아닌 값들

  • String
  • Number
  • BigInt
  • Boolean
  • Symbol
  • null
  • undefined
const str: stirng = 'STRING'
const num: number = 123
const bool: boolean = true

const big: bigint = 100n

자바스크립트에서 이런 간단한 타입들은 타입 추론을 할 수 있기 때문에 굳이 타입을 지정하지 않아도 된다.

오히려, 타입 추론을 유도하는 것이 더 좋다.

 

원시값은 다음과 같이 활용하는 것이 좋다.

const str: 'string' = 'string'
const num:123 = 123
const nool: true = true

기본값을 지정해주면, 기본값 이외의 값이 할당되었을 때 오류를 발생시킨다.

 

 

💼 객체 타입

🤔 객체 타입을 지정할 때는 object로 지정하면 될까?

const obj: object = {	
    str: 'str',
    num: 123,
    child: {    	
        str: 'str',
        num: 123,    
    }
}

정답은 ❌이다.

obj.str.trim()

string 타입에만 적용이 되는 trim() 메서드를 호출하면 str에서 찾을 수 없다는 오류 메시지를 발생한다.

num도 마찬가지로 obj 안에서 찾지 못한다.

 

: object로 타입을 지정하는 것은 any와 다른 게 없는 상황이다.

 

🤔 그렇다면 어떻게 타입을 좁힐 수 있을까?

const obj: { str: string, num: number } = {	
    str: 'str',
    num: 123,
}

위와 같이 객체 안 요소들에 대한 타입들을 자세하게 묘사해주어야 한다.

객체 안 객체는 다음과 같다.

const obj: { str: string, 
    num: number, 
    child: {
        str: string,
        num: number,
    }
    } = {	
    str: 'str',
    num: 123,
    child: {
        str: 'str',
        num: 123,       
    }
}

 

 

🚀 함수 타입

Function Type

함수 타입은 두 가지의 타입을 명시해주어야 한다.

  1. 매개변수
  2. 반환
function func(num: number, str: string): string{
    return num + str
}

 

Function이라는 타입을 지정하는 것은 지양❌ 해주는 것이 좋다.

function func2(num1: Function, num2: Function): Function{	
    console.log(num1 + num2)
}

 

🤔 함수 표현식에서는 타입을 어떻게 지정해야 좋을까?

const func3 = (num: number, str: string): string => {
}

위와 같이 매개변수, 반환 타입을 지정해주면 된다.

 

반환 타입은 타입 추론이 잘 되는 편이기 때문에 필히 넣을 필요는 없다.

적어도 매개변수에는 타입을 넣자!

 

🎈 배열 타입

const arr = ['str', 123, false]

위외 같은 배열 타입(여러 타입이 있는 경우)은 튜플(Tuple)로 타입 지정을 해주어야 한다.

 

하나의 타입으로 이루어진 배열을 살펴보자.

const strArr: string[] = ['str', 'str2', 'str3']
const strArr: Array<string> = ['str', 'str2', 'str3']

위와 같이 배열 변수 우측에 타입을 지정해주면 된다.

두 가지 방법에 차이는 없다.

 

🙌 리터럴 타입

Literal Type

하나의 특정한 값을 가질 수 있는 타입

 

let letString = 'Hello'
const constString = 'Hello'

🤔 두 변수의 차이점은 무엇일까?

바로 타입 정의에서 letString은 string 타입이고, constString 은 "Hello"로 정의되어 있다.

 

🤔 왜 이런 차이점이 나타날까?

letString은 재할당할 수 있기 때문에 리터럴 타입으로 지정되어 있다.

반면에 constString은 재할당이 불가능하기 때문에 특정 값으로 지정되어 있다.

 

 

🍒 튜플 타입

Tuple Type

  • 길이 고정 & 인덱스 타입이 고정
  • 여러 다른 타입으로 이루어진 배열을 안전하게 관리
  • 배열 타입의 길이 조절
const tuple: [number, string] = [1, 'A']

배열의 길이를 가변적으로 제어하는 예시를 아래에서 살펴보자.

const tuple: [number, ...string[]] = [0, 'A', 'B']

spread 연산자를 통해 배열의 길이도 2개 이상으로 제어할 수 있다.

 

 

🧛‍♂️ undefined null

  • JavaScript에서와 마찬가지로 고유의 특별한 타입으로 인정한다.
  • 이외에 void, never와 같이 더 세밀한 타입도 제공
  • strictNullchecks가 핵심

예시를 아래에서 살펴보자.

function sayHello(word: string){
    if(word === 'world'){
        return 'hello' + word
    }
    return null
}

 

위의 함수는 에러가 발생하지 않고 함수의 반환 타입이 자동적으로 string | null로 설정되어 있다.

만약 반환 타입을 void로 설정하게 되면 에러가 발생한다.

만약 return; 으로 설정하게 되면 함수의 반환 타입이 자동적으로 string | undefined로 설정 된다.

 

정리

  • return null ➡ null
  • return ➡ undefined
  • 반환하지 않음 ➡ void

팀에서 빈 값을 다루게 될 때, undefined를 사용할 지, null을 사용할 지 정하는 것이 좋다. (둘 중 하나만)

 

 

🧙‍♂️ any

any type

  • 모든 값(타입)의 집합
  • 사용하지 말자 ❌❌
  • noImplicitAny or strict 옵션 true 권장

아래의 예시를 살펴보자.

function func(anyParam: any){
    anyParam.trim()
}

위의 함수에서 trim() 메서드는 문자열에서만 사용이 가능하다.

이때 any 타입을 가진 anyParam이 문자열이 아닐 경우, 런타임에서 오류가 발생한다. 

any 타입은 매우 위험하지 사용을 지양해야 한다. 

 

any 타입을 사용하면 타입 추론이 안 되기 때문에 vs code에서 .을 찍어도 자동 완성이 되지 않지만, 

타입을 지정하면 .을 찍었을 때 자동 완성 기능을 사용할 수 있다.

 

 

🌚 unknown

  • 새로운 최상위 타입
  • any 처럼 모든 값을 허용하지만 상대적으로 엄격하다.
  • TS에서 unknown으로 추론하는 경우는 없으니 개발자가 직접 명시해야 함
  • assertion 혹은 타입 가드와 함께 사용한다.

아래에서 any와 unknown 차이를 살펴보자.

function func(x: any){
    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;
}

any에는 모든 타입들이 포함되어 있기 때문에 에러가 발생하지 않는다.

🤔 함수의 매개변수를 any 대신 unknown으로 변경하면 어떻게 될까?

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;
}

any와 unknown은 에러가 발생하지 않지만, 나머지 타입들에서 에러가 발생하게 된다.

 

또다른 예시를 살펴보자.

let num: any = 99;
num.trim();

any로 타입이 지정된 num 변수는 trim() 메서드를 호출해도 컴파일러에서는 에러가 발생하지 않고, 런타임에서 에러가 발생한다. 

🤔 이를 unknown으로 변경해주면 어떻게 될까?

let num: unknown = 99;
num.trim();

컴파일러에서 에러를 발생시킨다. 

num은 문자열이 아니기 때문에 trim() 메서드를 호출할 수 없다.

 

이럴 때 사용할 수 있는 것이 타입 가드이다.

: 타입을 검증하는 도구

let num: unknown = 99;
if(typeof num === 'string'){
    num.trim();
}

위와 같이 타입 가드를 사용하여 엄격하고 안전하게 제어를 할 수 있다. 

 

assertion : 타입을 강제하는 도구

let num: unknown = 99;
(num as string).trim();

위와 같이 타입을 강제하여 사용할 수 있다.

 

하지만 assertion보다는 타입 가드를 사용하는 것이 좋다.

 

💫 void

  • 함수의 반환이 없는 경우를 명시
  • 타입 추론에 위임하자
  • JavaScript에서는 암시적으로 undefined 반환
  • 그러나 void와 undefined는 TypeScript에서 같은 것이 아님
function voidFunc(){
	//
}

위의 함수는 타입 추론에 의해 void 함수로 정의가 된다. 

결론 : void 타입을 명시할 필요 없이 타입 추론에 위임하자!

'TypeScript' 카테고리의 다른 글

[TypeScript] TypeScript 시작하기  (0) 2022.09.06