TypeScript 기본 타입

0. 시작하기

TypeScript란?

타입 구문이 있는 자바스크립트

  • VSCode와의 호환성이 좋아서 오류 캐치가 가능
  • 최근 트렌드에 따르면 인기가 상승중
  • JavaScript로 컴파일 되어서 JavaScript가 지원되는 모든 곳에서 실행 가능
  • 비공식적 가이드라인이 많고 스타일이 다양하다.
  • 타입스크립트 플레이그라운드에서 간단히 실행해 볼 수 있다.

1. 기본 타입 훑어보기

type annotation

*annotate: 주석을 달다

변수명 우측에 콜론붙이고 타입을 명시하는 것

/**
 * Type Annotation
 * 
 * value: type
 */

const val: number = 123 // val 이라는 변수는 숫자 타입이다

원시 타입

문자열, 숫자, 불리언, 빅인트 등…

/**
 * Primitive (원시값)
 * 
 * - 불변
 * - 객체가 아닌 값들
 */
// 각각 문자열, 숫자, 불리언, 빅인트라고 타입을 명시했다
const str: string = 'STRING'
const num: number = 123
const bool: boolean = true
const big: bigint = 100n

// 이렇게 기본값을 지정할 수 있다.
// 정해진 값 외의 값이 들어오면 에러
const str: 'string' = 'string'
const str: string = 'STRING' // error
const num: 123 = 123
const num: 123 = '123' // error
const bool: true = true
const bool: true = false // error

// 타입을 명시하지 않았는데 자동으로 타입추론이 된다. 
const str = 'STRING' // string
const num = 123 // number
const bool = true // boolean

객체 타입

이 외에도 객체에 타입을 다는 방법은 다양하다.

/**
 * Object Type
 */
// any와 다른게 없는 상황
// 타입에러는 없지만, 객체는 내부에 많은 것이 있기 때문에 자세히 묘사하기 어렵다. 
const obj: object = {
  str: "str",
  num: 123,
  child: {
    str: "str",
    num: 123,
  },
};

// obj.num 
// 에러!
// Property 'num' does not exist on type 'object'.

// ---

const obj2: {
  str: string;
  num: number;
  child: {
    str: string;
    num: number;
  };
} = {
  str: "str",
  num: 123,
  child: {
    str: "str",
    num: 123,
  },
};

console.log(obj2.str);

함수 타입

/**
 * Function Type
 * 
 * 1. 매개변수
 * 2. 반환
 */
function func(num: number, str: string): string { // 반환 값이 문자열이라는 것
    return num + str
}

func(123, 'str')

function func2(num1: number, num2: string) {
     return num1 + Number(num2)
}

func2(123, '123')

function func3(num1: number, num2: string): void { // void: 반환하지 않는다
    console.log(num1 + num2)
}

func3(123, '123')

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' })

매개변수와 반환 타입을 명시할 수 있다.

반환 타입은 타입 추론이 잘 돼서 꼭 넣을 필요는 없다.

배열 타입

/**
 * Array Type
 */
// 하나의 타입으로만 지정된 배열
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) // Argument of type 'number' is not assignable to parameter of type 'string'.

numArr.push('str') // Argument of type 'string' is not assignable to parameter of type 'number'.

boolArr.push(false)

// Tuple
// 여러 타입이 있는 배열은 튜플 타입을 이용해야 한다. 
const arr = ['str', 123, false]

리터럴 타입

let으로 선언된 변수는 재할당으로 값이 바뀔 수 있다. ⇒ 이 변수의 값이 변경될 가능성이 있다는 것을 알린다. ⇒ 잠재적으로 무한한 경우의 값이 들어올 수 있다.

반면 const로 선언된 변수는 변경되지 않는다고 타입스크립트에 알린다. ⇒ 변경되지 않기 때문에 타입을 유한한 개수로 좁힐 수 있다.

/**
 * Literal Type
 */
let letString = 'Hello'

letString = letString + ' World'

console.log(letString)

const constString = 'Hello'

constString

// ---

let letNumber = 123

letNumber = letNumber + 123

console.log(letNumber)

const constNumber = 123

constNumber

.D.TS

d.ts는 타입스크립트의 타입 추론을 돕는 파일이다. typescript playground에서는 오른쪽 부분에서 바로 확인 가능하다.

/**
 * Literal Type
 */
declare let letString: string;
declare const constString = "Hello";
declare let letNumber: number;
declare const constNumber = 123;

constString 은 고정되므로 타입을 “Hello”로 정한다.

letString 은 변경될 수 있으므로 타입을 문자열로 선언한다.

튜플 타입

/**
 * Tuple Type
 * 
 * - 길이 고정 & 인덱스 타입이 고정
 * - 여러 다른 타입으로 이루어진 배열을 안전하게 관리
 * - 배열 타입의 길이 조절
 */
const arr: string[] = ['A', 'B', 'C']

const tuple: [number, string] = [1, 'A'] // 0인덱스에는 숫자, 1인덱스에는 문자열

const tuple0: (string | number)[] = [1, 'A'] // Union Type: 변수의 값이 여러 타입을 가질 때

const tuple2: [number, ...string[]] = [0, 'A', 'B'] // 1인덱스 부터는 문자열(가변적 길이)

undefined & null

/**
 * undefined & null
 * 
 * JavaScript에서와 마찬가지로
 * 고유의 특별한 타입으로 인정한다.
 * 
 * 이외에 void, never와 같이 더 세밀한 타입도 제공
 * 
 * strictNullChecks가 핵심
 */
// 둘 중 하나만 사용하는 일관성을 가지는 것을 권장. 
const nu: null = null;
const un: undefined = undefined;

console.log(nu == un) // true
console.log(nu === un) // false

// declare function sayHello(word: string): string | null;
// 리턴 타입을 지정하지 않았지만 string 혹은 null이라고 추론됨
function sayHello(word: string) {
    if (word === 'world') {
        return 'hello' + word
    }

    return null
} 

// eclare function log(message: string | number): void;
// 반환하는 게 없기 때문에 알아서 void로 지정됨
function log(message: string | number) {
    console.log(message)
}

any

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

// declare function func(anyParam: any): void;
// 파라미터의 타입 지정을 안했다. 타입스크립트 컴파일러는 any라고 생각한다..
// 명시적으로 :any를 넣는 것도 지양해야 한다. 
function func(anyParam) {
    anyParam.trim() // 문자열에만 쓸 수 있는 .trim()인데 배열이 들어와도 에러가 나지 않는다.
}

func([1,2,3])

any가 붙으면 타입스크립트가 아닌 자바스크립트처럼 사용 가능하게 된다.

noImplicitAny 옵션이 true 인 경우 “Parameter ‘anyParam’ implicitly has an ‘any’ type.” 이라는 에러가 나온다.

*implicit: 암시된, 내포되는

unknown

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

// 타입 가드: 타입이 맞는 지 검즘 
if (typeof num === 'string') {
    num.trim();
}

// assertion
(num as string).trim();

// x: any일 경우 에러가 나지 않는다. 
// x: unknown일 경우 val1, val2 제외하고 에러가 발생한다. 
function func(x: unknown) {
	let val1: any = x; 
	let val2: unknown = x;
	let val3: string = x; // Type 'unknown' is not assignable to type 'string'.
	let val4: boolean = x; // Type 'unknown' is not assignable to type 'boolean'.
	let val5: number = x; // Type 'unknown' is not assignable to type 'number'.
	let val6: string[] = x; // Type 'unknown' is not assignable to type 'string[]'.
	let val7: {} = x; // Type 'unknown' is not assignable to type '{}'.
}

any에 비해서 비교적 최근 문법.

*assertion: (사실임을) 주장 = claim

void

언제 보이드 타입을 명시하는가? 그냥 타입 추론에 맡기자.

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

function test(): undefined {
    return undefined
}
console.log(test()) // undefined

function test2(): void {

}

function voidFunc() {
    // declare function voidFunc(): void;
		// void로 알아서 타입 추론이 된다. 
}

Leave a comment