타입스크립트 기본 - (1)

DevSeong2·2023년 9월 5일
0

TypeScript

목록 보기
2/4
post-thumbnail

"한 입 크기로 잘라먹는 타입스크립트 - 인프런" 강의를 요약하고 덧붙인 글입니다.

기본 타입(Basic Types)

타입스크립트가 자체적으로 제공하는 타입을 뜻합니다. 자바스크립트에서 이미 사용하고 있는 타입들과 타입스크립트에서만 제공하는 독특한 타입들도 있습니다.

원시 타입

원시 타입은 하나의 값만 저장하는 타입으로 불변 값(변경할 수 없는 값)을 정의합니다. 값을 교체할 수는 있지만, 직접 변형할 수는 없습니다.

var bar = "baz";
console.log(bar); // baz
bar.toUpperCase();
console.log(bar); // baz

number

숫자를 의미하는 모든 값을 포함하는 타입입니다. 정수 뿐만 아니라 소수, 음수 그리고 세 가지 특별한 값도 표현할 수 있습니다.

  • Infinity: 양의 무한대
  • -Infinity: 음의 무한대
  • NaN: 산술 연산 불가 (not-a-number)
let num1: number = 123;
let num2: number = -123;
let num3: number = 0.123;
let num4: number = -0.123;
let num5: number = Infinity;
let num6: number = -Infinity;
let num7: number = NaN;

string

텍스트 데이터를 나타낼 때 사용합니다. 문자열은 작은따옴표(''), 큰따옴표("") 또는 백틱(``)으로 텍스트를 감싸서 표기합니다. 템플릿 리터럴로 만든 문자열도 포함합니다.

let str1: string = "hello";
let str2: string = 'hello';
let str3: string = `hello`;
let str4: string = `hello ${str1}`; // 템플릿 리터럴

템플릿 리터럴이란?

boolean

논리 요소를 나타내며 참과 거짓만을 저장하는 타입입니다. truefalse 두 가지 값만 가질 수 있습니다.

let bool1 : boolean = true;
let bool2 : boolean = false;

null

오직 null 값만 포함하는 타입입니다. null은 어떤 값이 의도적으로 비어있음을 표현하며 불리언 연산에서는 거짓으로 취급합니다.

let null1: null = null;
(+) 엄격한 Null 검사 옵션 - strictNullChecks

아직 값이 정해지지 않은 상태에서는 변수에 null을 할당하고 싶은 경우가 있습니다. 그러나 다른 타입의 변수에 null을 할당하면 오류가 발생합니다.

let numA: number = null;  // ❌

null 값을 변수의 임시값으로 활용하고 싶을 때 tsconfig.json의 strcitNullChecks 옵션을 false로 설정하면 됩니다. strictNullChecks 옵션은 타입스크립트에서 null 값을 null 타입 이외의 타입의 변수에 할당하는 것을 금지할지 허락할지 여부를 결정하는 옵션입니다.

{
  "compilerOptions": {
    ...
    "strictNullChecks": false,
		...
  },
  "include": ["src"]
}

undefined

null 타입과 마찬가지로 undefined만 포함하는 타입입니다. 값을 할당하지 않은 변수는 undefined 값을 가집니다.

let unde1: undefined = undefined;

symbol

고유한 참조값을 생성하는데 사용할 수 있는 타입입니다. symbol은 외부에 노출되지 않고 다른 값과 중복되지 않는 유일한 값입니다. 다른 원시 값은 리터럴을 통해 생성하지만 symbol은 Symbol 함수를 호출해 생성합니다.

let sym1: symbol = Symbol();

리터럴

하나의 값만 포함하도록 값 자체로 만들어진 타입입니다. 리터럴을 사용하면 다양한 종류의 값을 생성할 수 있습니다. 변수의 타입을 값 자체로 정의하면 정의한 값 외에는 다른 값을 사용할 수 없습니다.

let numA: 10 = 10;
let strA: "hello" = "hello";
let boolA: true = true;
let boolB: false = false;

배열과 튜플

배열

배열을 저장하는 변수의 이름 뒤에 타입 주석의 시작을 의미하는 콜론(:)을 작성한 다음 배열요소타입[] 형식으로 배열 타입을 정의합니다.

let numArr: number[] = [1, 2, 3]
let strArr: string[] = ["hello", "world"];

Array<배열요소타입> 형태로도 배열의 타입을 정의할 수 있습니다. 꺽쇠와 함께 타입을 작성하는 문법을 타입스크립트에서는 ‘제네릭’ 이라고 부릅니다.

let boolArr: Array<boolean> = [true, false, true];

배열의 타입을 정의하는 두 형식 모두 모양만 다를뿐 기능은 동일하기에 타이핑하기 쉬운 첫 번째 방식을 주로 사용합니다.

배열에 들어가는 요소들의 타입이 다양할 경우에는 소괄호와 바(|) 를 이용해 배열 요소가 둘 중 하나의 타입에 해당하도록 타입을 정의합니다.

// 배열 요소의 타입이 string이거나 number
let multiArr: (number | string)[] = [1, "hello"]; 

바(|)를 이용해 여러 타입중 하나를 만족하는 타입을 정의하는 문법을 유니온(Union) 타입 이라고 부릅니다.

튜플

튜플은 자바스크립트에는 없는 타입스크립트의 특수한 타입으로 길이와 타입이 고정된 배열을 의미합니다. 타입스크립트의 배열은 배열에 들어가는 타입은 고정시킬 수 있지만 길이까지 고정할 수는 없습니다.

let tup1: [number, number] = [1, 2];
let tup2: [number, string, boolean] = [1, "hello", true];

튜플은 별도로 존재하는 자료형이 아닌 자바스크립트 배열입니다. 타입스크립트 코드를 컴파일 해 보면 자바스크립트 배열로 변환됩니다. 그러므로 배열 메서드를 이용해 튜플을 다룰 수 있습니다.
그러므로 튜플을 배열 메서드를 이용해 요소를 추가하거나 삭제 등의 연산을 할 때에는 주의해야 합니다.

let tup1: [number, number] = [1, 2];
tup1.push(1);
tup1.pop();

튜플의 사용 예

회원 정보를 2차원 배열로 저장하는 상황을 가정해 보겠습니다. 회원의 이름과 아이디를 저장해두는 배열을 만들어 두었습니다.

const users = [
  ["Lee", 1],
  ["Park", 2],
  ["Kim", 3],
];

그런데 동료가 요소의 순서가 헷갈려 반대로 저장하였습니다. 이로 인해 오류가 발생합니다.

const users = [
  ["Lee", 1],
  ["Park", 2],
  ["Kim", 3],
  [4, "Choi"] // 추가
];

function makeUpperCase(inputString) { return inputString.toUpperCase(); }
makeUpperCase(users[3][0]) // ❌ Error
]

튜플을 사용하면 이러한 문제를 쉽게 해결할 수 있습니다. 배열을 사용할 때 인덱스에 따라 넣어야 할 값이 정해져 있고 순서가 중요할 때 튜플을 사용하여 실수를 방지할 수 있습니다.

const users: [string, number] = [
  ["Lee", 1],
  ["Park", 2],
  ["Kim", 3],
  [4, "Choi"] // ❌ Error
];

객체

원시 타입을 제외하고 가장 많이 마주치는 타입입니다.

자바스크립트의 객체는 키(key)과 값(value)으로 구성된 프로퍼티(Property)들의 집합이다.

타입스크립트에서는 2가지 방식으로 객체의 타입을 정의합니다.

object로 정의

let user: object = {
  id: 1,
  name: 'cs',
};

그러나 타입스크립트에서 객체의 특정 프로퍼티에 접근하려고 하면 오류가 발생합니다.

let user: object = {
  id: 1,
  name: 'cs',
};

user.id; // ❌ Error

그 이유는 타입스크립트의 object 타입은 값이 객체임을 표현하는 것 외에는 아무 정보도 제공하지 않는 타입이기 때문입니다. 객체의 프로퍼티에 대한 정보가 없기 때문에 프로퍼티에 접근하려 하면 오류가 발생합니다. 객체의 모양을 정확히 타입으로 만드려면 다른 방법을 사용해야 합니다.

객체 리터럴 타입

객체 리터럴 타입은 다음과 같이 중괄호를 열고 객체가 갖는 프로퍼티를 직접 나열합니다. 객체 리터럴과 비슷한 문법으로 객체 타입을 정의한 타입을 객체 리터럴 타입이라고 부릅니다.

let user: {
  id: number;
  name: string;
} = {
  id: 1,
  name: "cs",
};

user.id;

객체의 타입을 정의할 때에는 object 보다는 객체 리터럴 타입을 사용하는 것이 좋습니다. 타입스크립트에서는 객체의 타입을 정의할 때 프로퍼티를 기준으로 객체의 구조를 정의하듯 타입을 정의합니다. 이런 특징을 구조적 타입 시스템이라고 부릅니다.

(+) 명목적 타입 시스템

명목적 타입 시스템은 구조적 타입 시스템과는 대조적으로 변수나 객체의 타입을 해당 타입의 이름 또는 명칭으로 식별합니다. 객체의 타입이 명시적으로 선언되어야 한다는 의미입니다. 클래스의 이름이 타입을 나타냅니다.

class Animal:
    def make_sound(self):
        pass

class Dog(Animal):
    def make_sound(self):
        print("멍멍")

def sound_maker(animal: Animal):
    animal.make_sound()

my_dog = Dog()
sound_maker(my_dog)  # "멍멍" 출력

구조적 타입 시스템의 예)

interface Animal {
    makeSound: () => void;
}

interface Dog extends Animal {
    bark: () => void;
}

function soundMaker(animal: Animal) {
    animal.makeSound();
}

const myDog: Dog = {
    makeSound: () => console.log("멍멍"),
    bark: () => console.log("왈왈")
};

soundMaker(myDog); // "멍멍" 출력

객체의 구조가 중요하며 객체가 특정 인터페이스 또는 구조를 따르면 해당 타입으로 간주됩니다. 타입의 이름이나 클래스의 이름은 중요하지 않습니다.

선택적 프로퍼티(Optional Property)

객체를 다루다보면 특정 프로퍼티를 사용하지 않는 경우도 있습니다. 특정 프로퍼티를 상황에 따라 생략하도록 만들고 싶다면 프로퍼티의 이름 뒤에 ? 붙여 선택적 프로퍼티로 만들어줍니다.

let user: {
  id?: number;
  name: string;
} = {
  id: 1,
  name: "cs",
};

user = {
  name: "jh",
};

읽기전용 프로퍼티(Readonly Property)

특정 프로퍼티를 읽기 전용으로 만들고 싶다면 다음과 같이 프로퍼티의 이름 앞에 readonly 키워드를 붙입니다. 읽기전용 프로퍼티를 사용하면 의도치 않은 프로퍼티의 수정을 방지할 수 있습니다.

let user: {
  id?: number;
  readonly name: string;
} = {
  id: 1,
  name: "cs",
};

user.name = "dskfd"; // Error

Reference

profile
차근차근

0개의 댓글