[TypeScript] 타입스크립트 기본 문법 정리

김진영·2022년 11월 13일
3

TypeScript

목록 보기
1/3
post-thumbnail

📋 타입스크립트 기본 문법

개발 공부를 시작하고 지금까지 자바스크립트를 공부하고, 또 자바스크립트로 다양한 프로젝트를 진행해왔다.

하지만 타입스크립트라는 언어를 알게 된 후부터 자바스크립트의 단점이 내게 부각되기 시작했고, 결국 에러 및 버그의 사전 확인, 유지 보수의 장점 등등 다양한 이유로 타입스크립트라는 언어를 공부해야겠다는 생각이 들었다.

때문에 지금부터 그 첫 단계인 기본 문법부터 차근차근 정리해 보려고 한다.

참고 문서
TypeScript-Handbook 한글 문서
타입스크립트 핸드북
다른 많은 블로그들


📌 1. 기본 타입 선언

프로그램이 유용하려면 숫자, 문자열, 구조체, 불리언 값과 같은 간단한 데이터 단위가 필요합니다. TypeScript는 JavaScript와 거의 동일한 데이터 타입을 지원하며, 열거 타입을 사용하여 더 편리하게 사용할 수 있습니다.

1-1. 문자열

let hello: string = "helloWorld!";

1-2. 숫자

let tripleSeven: number = 777;

1-3. 배열

let arr1: number[] = [10, 20, 30];
let arr2: Array<number> = [10 , 20, 30];
let arr3: Array<string> = ["hello", "world"];
let arr4: [string, number] = ["jinyoung", 24];

1-4. 객체

let jinyoung: object = { name: "jinyoung", age: 24 };
let person: { name: string; age: number } = {
  name: "jinyoung",
  age: 24
};

1-5. 불리언 (Boolean)

let isThatTrue: boolean = true;

📌 2. 함수 선언

TypeScript 함수는 JavaScript와 마찬가지로 기명 함수(named function)과 익명 함수(anonymous function)로 만들 수 있습니다. 이를 통해 API에서 함수 목록을 작성하든 일회성 함수를 써서 다른 함수로 전달하든 애플리케이션에 가장 적합한 방법을 선택할 수 있습니다.

2-1. 함수 타입 선언

TypeScript에선 parameter와 return 값의 타입 선언을 할 수 있다.

function add(x: number, y: number): number {
  return x + y;
}

2-2. 선택적 매개변수 (optional parameter)

optional parameter(있어도 되고 없어도 되는 parameter)?를 앞에 추가해주면 된다.

function buildName(firstName: string, lastName?: string) {
    if (lastName)
        return firstName + " " + lastName;
    else
        return firstName;
}

let result1 = buildName("Bob"); // 문제 없음
let result2 = buildName("Bob", "Adams", "Sr."); // 에러!
let result3 = buildName("Bob", "Adams"); // 문제 없음

📌 3. 인터페이스 (Interface)

TypeScript의 핵심 원칙 중 하나는 타입 검사가 값의 형태에 초점을 맞추고 있다는 것입니다. 이를 "덕 타이핑(duck typing)" 혹은 "구조적 서브타이핑 (structural subtyping)"이라고도 합니다. TypeScript에서, 인터페이스는 이런 타입들의 이름을 짓는 역할을 하고 코드 안의 계약을 정의하는 것뿐만 아니라 프로젝트 외부에서 사용하는 코드의 계약을 정의하는 강력한 방법입니다.

interface는 자주 사용하는 타입들을 object 형태의 묶음으로 정의해 새로운 타입을 만드는 기능이다.

3-1. interface 선언

interface User {
  age: number;
  name: string;
}

3-2. 변수 활용

const jinyoung: User = { name: "jinyoung", age: 24 }

3-3. 함수 인자로의 활용

function getUser(user: User) {
  console.log(user);
}

getUser({ name: "jinyoung", age: 24 });

3-4. 함수 구조 활용

interface Add {
  (x: number, y: number): number;
}

let addFunc: Add = (a, b) => a + b;

console.log(addFunc(14, 7));

3-5. 배열 활용

interface StringArr {
  [index: number]: string;
}

let arr: StringArr = ["a", "b", "c"];

3-6. 객체 활용

interface Obj {
  [key: string]: string;
}

const obj: Obj {
  person1: "jinyoung",
  person2: "kanye"
}

3-7. Interface 확장

interface Person {
  name: string;
  age: number;
}

interface Developer extends Person {
  position: string;
}

const jinyoung: Developer = {
  name: "jinyoung",
  age: 24,
  position: "FE"
};

📌 4. 타입 (type)

type 키워드는 interface와는 다르게 새로운 타입을 생성하는 것이 아닌 별칭을 부여하는 것이다. extends 키워드는 사용할 수 없다.

4-1. 타입 별칭 선언

type StrOrNum = string | number;

const str1: StrOrNum = "hello world";
const str2: StrOrNum = 77777;

4-2. type vs interface

타입 별칭과 인터페이스의 가장 큰 차이점은 타입의 확장 가능 / 불가능 여부이다.
인터페이스는 확장이 가능한데 반해 타입 별칭은 확장이 불가능하다. 따라서, 가능한한 type 보다는 interface로 선언해서 사용하는 것을 추천한다.


📌 5. 연산자 (Operator)

5-1. 유니언 타입 (Union Type)

한 개 이상의 type을 선언할 때 사용할 수 있다.
| 키워드를 사용한다.

function strOrNum (value: string | number) {
  if(typeof value === 'string') {
    value.toString();
  } else if(typeof value === 'number') {
    value.toLocaleString();
  } else {
    throw new TypeError('문자열 또는 숫자를 넣어주세요!');
  }
}

strOrNum('hello world');
strOrNum(777);

5-2. 교차 타입 (Intersection Type)

합집합과 같은 개념이다.
함수 호출의 경우, 함수 인자에 명시한 type을 모두 제공해야 한다.
& 키워드를 사용한다.

interface Person {
  name: string;
  age: number;
}

interface Developer {
  name: string;
  skill: string;
}

type Capt = Person & Developer;

let devPerson: Capt = {
  name: "kim",
  age: 777,
  skill: "FE"
};

📌 6. Class

6-1. 접근 제한자

클래스 기반 객체 지향 언어가 지원하는 접근 제한자(Access modifier) public, private, protected를 지원하며 의미 또한 동일하다.

접근 제한자를 명시하지 않았을 때

  • 다른 클래스 기반 언어 : protected로 지정
  • TypeScript : public으로 지정
접근 가능성publicprotectedprivate
클래스 내부OOO
자식 클래스 내부OOX
클래스 인스턴스OXX

6-2. Class에서의 타입 선언

class Person {
  // constructor 위에 선언
  private name: string;
  public age: number;
  readonly log: string;
  
  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }
}

📌 7. Enum

열거형(Enums)으로 이름이 있는 상수들의 집합을 정의할 수 있습니다. 열거형을 사용하면 의도를 문서화 하거나 구분되는 사례 집합을 더 쉽게 만들수 있습니다. TypeScript는 숫자와 문자열-기반 열거형을 제공합니다.

enum 키워드를 사용하면 default 값을 선언할 수 있다.

7-1. 숫자형 enum

자동으로 0에서 1씩 증가하는 값을 부여한다.

enum Brands {
  Nike,		    // 0
  Adidas,		// 1
  NewBalance	// 2
}

const myShoes = Brands.Nike;	// 0

7-2. 문자형 enum

enum Player {
  kim = '김',
  park = '박'
}

const player = Player.park;	// 박

📌 8. 제네릭(generics)

C#과 Java 같은 언어에서, 재사용 가능한 컴포넌트를 생성하는 도구상자의 주요 도구 중 하나는 제네릭입니다, 즉, 단일 타입이 아닌 다양한 타입에서 작동하는 컴포넌트를 작성할 수 있습니다. 사용자는 제네릭을 통해 여러 타입의 컴포넌트나 자신만의 타입을 사용할 수 있습니다.

제네릭을 활용하면 같은 기능의 함수를 또 만들 필요가 없고, 타입 추론에 있어서 강점을 가진다는 장점이 있다.

8-1. 제네릭 선언

<T>와 같이 타입을 선언한다. 알파벳은 대부분 T를 사용한다.

function logText<T>(text: T): T {
  consol.log(text);
  return text;
}

logText<string>('Hello World!');

8-2. interface에 제네릭 선언

interface Menu<T> {
  value: T;
  price: number;
}

const hamburger: Menu<string> = { value: 'hamburger', price : 5000 };

8-3. 제네릭 타입 제한

8-3-1. 배열 힌트

function textLength<T>(text: T[]): T[] {
    console.log(text.length);
    return text;
}

textLength<string>(['hello', 'world']);

8-3-2. 정의된 타입 이용 (extends)

interface LengthType {
    length: number;
}

function logTextLen<T extends LengthType>(text: T): T {
    console.log(text.length);
    return text;
}

logTextLen('hello world'); // 11
logTextLen(100); // 에러!
logTextLen({ length: 100 }); // 100

8-3-3. keyof

interface에 정의된 key 값만을 허용

interface Item {
    name: string;
    price: number;
    stock: number;
}

function getItemOption<T extends keyof Item>(itemOption: T): T {
    return itemOption;
}

// 'name', 'price', 'stock'만 인자로 사용 가능
getShoppingItemOption('price');

0개의 댓글