# 2. TypeScript

키워드

* REPL
* TypeScript
  * 타입 추론
  * Interface vs Type
  * Union Type vs Intersection Type
  * Optional Parameter

## 타입스크립트, 왜 쓰는가?

* 편리한 자동완성
* 실시간 오류검사

## REPL

* Read-Eval-Print-Loop
* 사용자의 입력을 받아 평가하고 결과를 리턴하는 인터렉티브 프로그래밍 환경
* ts-node를 실행해 타입스크립트 REPL 사용 가능 `npx ts-node`

## 타입 추론

타입스크립트는 자료의 뒤에 타입을 명시

타입을 명시하지 않아도 값을 통해 자동으로 타입을 결정해주기도 함

```ts
const name: string = '홍길동';
const name = '홍길동';
// 위의 코드와 아래코드는 같다.
```

## 타입

### 원시타입

```ts
let name: string;
let age: number;
let isAdult: boolean;

name = "홍길동";
age = 20;
isAdult = true;
```

### 배열

`number[]` 또는 `Array<number>` 의 형태로 사용

```ts
let numbers: number[];
numbers = [1, 2, 3];
```

### 튜플

길이와 타입이 고정된 배열

순서에 맞지 않게 데이터를 넣으면 에러 표시

```ts
let user1: [number, string, string];
user1 = [1, 'setType77@example.com', '1q2w3e4r'];
```

#### 한계점

`push` 메서드를 사용하면 정의와 상관없이 배열의 길이가 늘어남

```ts
let user1: [number, string, string];
user1 = [1, 'setType77@example.com', '1q2w3e4r'];

user1.push('fake'); // 에러없이 컴파일됩니다.
```

#### 해결방안

튜플 선언시에 `readonly` 사용

```ts
type UserInfo = readonly [number , string, string ,string , boolean]; // 배열 앞에 readonly 적용

let userInfo1 : UserInfo = [1, 'user1@example.com' , 'abcd123' , '1999-01-01' , true];

userInfo1.push('hello'); // Error
```

### any

어떤 값의 타입이 any이면 타입 검사를 실행하지 않음

### 함수

매개변수와 리턴값에 타입을 표기할 수 있음

```ts
// 매개변수 타입 표기
function greet(name: string) {
  console.log("Hello, " + name.toUpperCase() + "!!");
}

// 반환 타입 표기
function getFavoriteNumber(): number {
  return 26;
}
```

문맥을 통해 익명 함수의 타입을 추론할 수 있다면, 자동으로 타입이 부여됨

```ts
const names = ["Alice", "Bob", "Eve"];
 
names.forEach(function (s) {
  console.log(s.toUppercase());
  //Property 'toUppercase' does not exist on type 'string'. Did you mean 'toUpperCase'?
});
 
names.forEach((s) => {
  console.log(s.toUppercase());
  //Property 'toUppercase' does not exist on type 'string'. Did you mean 'toUpperCase'?
});
```

### 객체

```ts
let human: {
  name: string;
  age: number;
};

human = { name: '홍길동', age: 13 };
```

### Optional parameter

객체의 속성을 옵션화하거나 함수의 매개변수를 옵션화할 수 있음

```ts
function printName(obj: { first: string; last?: string }) {
  // ...
}
// 둘 다 OK
printName({ first: "Bob" });
printName({ first: "Alice", last: "Alisson" });
```

```ts
function greeting(name?: string): string {
  return `Hello, ${name || 'world'}`;
}
```

## Union vs. Intersection

기존의 타입을 기반으로 다양한 연산자를 사용해서 새로운 타입을 만들 수 있음

### Union Type

숫자 또는 문자를 받을 수 있는 함수

```ts
function printId(id: number | string) {
  console.log("Your ID is: " + id);
}
// OK
printId(101);
// OK
printId("202");
// 오류
printId({ myID: 22342 });
```

유니언을 사용할 때는 해당 유니언 타입의 모든 멤버에 대해 유효한 작업만 허용됨

`string | number` 유니언 타입의 경우, string 타입에만 유효한 메서드는 사용할 수 없음

```ts
function printId(id: number | string) {
  console.log(id.toUpperCase());
  // Property 'toUpperCase' does not exist on type 'string | number'.
  // Property 'toUpperCase' does not exist on type 'number'.
}
```

typeof를 이용해 분기 처리

```ts
function printId(id: number | string) {
  if (typeof id === "string") {
    // 이 분기에서 id는 'string' 타입을 가집니다
 
    console.log(id.toUpperCase());
  } else {
    // 여기에서 id는 'number' 타입을 가집니다
    console.log(id);
  }
}
```

### Intersection Type

여러 타입을 모두 만족하는 하나의 타입

```ts
interface Person {
  name: string;
  age: number;
}
interface Developer {
  name: string;
  skill: number;
}
type Capt = Person & Developer;
```

`Capt` 타입은 아래와 같이 정의됨

```ts
{
  name: string;
  age: number;
  skill: string;
}
```

## Type vs. Interface

### type

똑같은 타입을 재사용하거나 객체, 유니언 타입 등을 더 간단한 이름으로 부르고 싶은 경우 타입의 별칭을 만들 수 있음

```ts
type Point = {
  x: number;
  y: number;
};
 
function printCoord(pt: Point) {
  console.log("The coordinate's x value is " + pt.x);
  console.log("The coordinate's y value is " + pt.y);
}
 
printCoord({ x: 100, y: 100 });
```

```ts
type ID = number | string;
```

### interface

`type`과 마찬가지로 객체 타입을 만드는 또 다른 방법

```ts
interface Point {
  x: number;
  y: number;
}
 
function printCoord(pt: Point) {
  console.log("The coordinate's x value is " + pt.x);
  console.log("The coordinate's y value is " + pt.y);
}
 
printCoord({ x: 100, y: 100 });
```

### type과 interface의 차이점

인터페이스는 객체에만 사용되며, 원시타입에 이름을 부여하는 데는 사용할 수 없음

인터페이스는 `extends`를 통해 확장, 타입은 교집합을 통해 확장

```ts
interface Animal {
  name: string
}

interface Bear extends Animal {
  honey: boolean
}

const bear = getBear()
bear.name
bear.honey
```

```ts
type Animal = {
  name: string
}

type Bear = Animal & {
  honey: Boolean
}

const bear = getBear();
bear.name;
bear.honey;
```

인터페이스는 새 필드를 추가할 수 있지만, 타입은 생성한 뒤 달라질 수 없음

```ts
interface Window {
  title: string
}

interface Window {
  ts: TypeScriptAPI
}

const src = 'const a = "Hello World"';
window.ts.transpileModule(src, {});
```

```ts
type Window = {
  title: string
}

type Window = {
  ts: TypeScriptAPI
}

 // Error: Duplicate identifier 'Window'
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://haeuns-organization.gitbook.io/megaptera-frontend-course/week1/2.typescript.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
