포스트

[TypeScript] 기본 문법

1️⃣ 타입스크립트 기본 타입

String

1
let color: string = "blue";

Number

1
let decimal: number = 6;

Boolean

1
let isDone: boolean = true;

Array

1
2
let list: number[] = [1, 2, 3];
let list: Array<number> = [1, 2, 3];

Object

1
const user:object = { name:"민또", age:19 }

Tuple ➡️ 고정된 개수의 요소를 가지며 각 요소의 타입이 지정된 배열

1
const arr: [string, number] = ['Bellingham', 22];

Null / Undefined

1
2
let u: undefined = undefined;
let n: null = null;

Any ➡️ 어떤 타입이든 상관 X

1
let notSure: any = 4;

그 외 ➡️ Enum, Never, Void

🚀 함수 타입

1️⃣ 매개변수 타입 지정

1
2
3
function add(x: number, y: number): { return x + y };
add(10, 20); // 가능
add("x", "y") // 불가능

2️⃣ 반환 값 타입 지정

1
function add(x, y):number { return x + y }; // 반환 값 반드시 Number 형

3️⃣ 옵셔널 파라미터

선택적 매개변수는 "?"를 사용하여 정의

1
2
3
4
5
6
7
8
9
10
function optionalName(firstName: string, lastName?: string): string {
  if(lastName) {
    return firstName + " " + lastName;
  } else {
    return firstName;
  }
}

console.log(optionalName("Minddo", "Heo")); // Minddo Heo
console.log(optionalName("Minddo")); // Minddo

🚀 타입 오퍼레이터

1️⃣ 유니언 타입

  • 유니언 타입은 여러 개의 타입을 결합하여 변수에 할당할 수 있는 값을 다양하게 만들 수 있음
  • 유니언 타입은 연결된 타입 중 1개만 만족하면 됨
1
2
3
4
let value: string | number;

value = "minddo"; // OK
value = 19; // OK
  • But 특정 타입의 메소드를 사용하려고 하면 에러가 발생 할 수 있음
  • ☝🏻 때문에 Type Guard 사용하기

Type Guard

➡️ 런타임에 변수의 타입 확인 후, 그에 따라 해당 타입의 메소드 사용할 수 있도록 해줌

  • typeof 연산자 사용한 타입 가드
    • 원시 타입 확인에 유용
      1
      2
      3
      4
      5
      6
      7
      8
      9
      
      function printId(id: number | string) {
      if (typeof id === "string") {
      // id가 string 타입인 경우
      console.log(`ID (string): ${id.toUpperCase()}`);
      } else {
      // id가 number 타입인 경우
      console.log(`ID (number): ${id}`);
      }
      }
      
  • instanceof 연산자 사용한 타입 가드
    • 객체가 특정 클래스의 인스턴스인지 확인할 때 사용
코드 보기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class ManchesterUTD {
  utd() {
    console.log("근본");
  }
}

class ManchesterCity {
  city() {
    console.log("노근본");
  }
}

type Club = ManchesterUTD | ManchesterCity;

function favorite(club: Club) {
  if (club instanceof ManchesterUTD) {
    club.utd();
  } else {
    club.city();
  }
}

let mu = new ManchesterUTD();
let mc = new ManchesterCity();

favorite(mu); 
favorite(mc); 

2️⃣ 인터섹션 타입

  • 인터섹션 타입은 여러 타입을 결합하여 하나의 복합 타입을 만들 수 있음
  • 인터섹션 타입은 연결된 타입을 모두 만족해야함
1
2
3
4
5
const introduce: { name: string; age: number } & { job: string } = {
  name: "Bellingham",
  age: 22,
  job: "Soccer Player",
};

🚀 인터페이스

객체의 타입을 정의할 때 사용하는 도구

1️⃣ 기본 인터페이스 정의

1
2
3
4
5
6
7
8
9
interface Person {
  name: string;
  age: number;
}

let person: Person = {
  name: "minddo",
  age: 29
};

2️⃣ 인터페이스 병합

1
2
3
4
5
6
7
8
9
10
11
12
interface Person {
  name: string;
}

interface Person {
  age: number;
}

const player: Person = {
  name: "Bellingham",
  age: 22
};

3️⃣ 인터페이스 상속

1
2
3
4
5
6
7
8
9
10
11
12
interface Club {
  uniformColor: string;
}

interface ManUtd extends Club {
  country: string;
}

const player: Person = {
  uniformColor: "Red",
  country: "England"
};

4️⃣ 인덱스 시그니처

객체가 임의의 속성을 가질 수 있도록 정의

1
2
3
4
5
6
7
8
9
10
11
12
interface ClubDictionary {
  [key: string]: string | number;
}

let manU: ClubDictionary = {
  name: "ManchesterUtd",
  rank: 1,
  country: "England",
  stadium: "Old Trafford"
};

console.log(manU);

🐥 변수에 인터페이스 적용

1
2
3
4
5
6
7
8
9
interface User {
  username: string;
  password: string;
}

const user: User = {
  username: "mingddo",
  password: "1234"
}

🐥 함수에 인터페이스 적용

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
interface Login {
  (username: string, password: string): boolean;
}

let login: Login;
login = (username: string, password: string) => {
  // 로그인 로직
  return username === "mingddo" && password === "1234";
};

console.log(login("mingddo", "1234")); // true

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

const averageAge = (people: IPerson[]): number => {
  return people.reduce((acc, person) => acc + person.age, 0) / people.length;
};

const average = averageAge([
  { name: "Mingddo", age: 30 },
  { name: "CutieMingddo", age: 10 },
  { name: "You", age: 50 },
]);

console.log(average); // 30

🚀 타입 별칭(Type Aliases)

type 키워드를 사용해 타입을 지정

  • 특정 타입에 별명을 붙여 재사용 가능하게 함
  • 코드의 가독성 증가
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/* 객체 타입에 타입 별칭 */
type Minddo = {
  name: string;
  age: number;
};

const minddo: Minddo = {
  name: "minseok",
  age: 25
};

/* 유니언 타입에 타입 별칭 */
type Color = "Red" | "Blue" | "Yellow";
const color: Color = "Red";

/* 함수 타입에 타입 별칭 */
type Stacks = {
  name: string;
  period: number;
};

const stacks = (stack: Stacks): string => {
  return `Name: ${stack.name}, Period: ${stack.period}`;
};

const myStack: Stacks = { name: "Java", period: 8 };
console.log(stacks(myStack)); // Name: Java, Period: 8

🚀 Enum

enum은 관련된 값의 집합에 이름을 붙여주는 방법

1️⃣ 숫자 열거형

1
2
3
4
5
6
7
8
9
enum Direction {
  Up,
  Down,
  Left,
  Right
}

let direction: Direction = Direction.Up;
console.log(direction); // 0

2️⃣ 문자 열거형

1
2
3
4
5
6
7
8
9
enum Direction {
  Up = "UP",
  Down = "DOWN",
  Left = "LEFT",
  Right = "RIGHT"
}

let direction: Direction = Direction.Left;
console.log(direction); // "LEFT"

3️⃣ 이니셜라이즈된 열거형 (Const Enum)

const enum은 컴파일 타임 상수로 최적화되는 열거형

  • const enum은 런타임에 실제 객체로 존재하지 않음
  • 컴파일 시점에 열거형 값이 상수로 대체 !
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const enum HttpStatus {
  OK = 200,
  BadRequest = 400,
  Unauthorized = 401,
  NotFound = 404
}

function handleResponse(status: HttpStatus): string {
  switch (status) {
    case HttpStatus.OK: 
      return "Request was successful.";
    case HttpStatus.BadRequest: 
      return "Bad request.";
    case HttpStatus.Unauthorized:
      return "Unauthorized access.";
    case HttpStatus.NotFound:
      return "Resource not found.";
    default:
      return "Unknown error.";
  }
}

const status = HttpStatus.OK;
console.log(handleResponse(status)); // "Request was successful."
  • 위의 코드는 아래와 같이 컴파일된다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function handleResponse(status) {
  switch (status) {
    case 200 /* OK */:
      return "Request was successful.";
    case 400 /* BadRequest */:
      return "Bad request.";
    case 401 /* Unauthorized */:
      return "Unauthorized access.";
    case 404 /* NotFound */:
      return "Resource not found.";
    default:
      return "Unknown error.";
  }
}

var status = 200 /* OK */;
console.log(handleResponse(status)); // "Request was successful."
  • 컴파일 타임에 상수 값으로 대체되어, 성능 최적화 가능
  • But, 디버깅 시에 원래 열거형 이름 확인 불가

4️⃣ 문자열 및 숫자 혼합 열거형

1
2
3
4
5
6
7
enum Mixed {
  No = 0,
  Yes = "YES"
}

console.log(Mixed.No); // 0
console.log(Mixed.Yes); // "YES"

🚀 제네릭

코드 작성 시점이 아닌 사용 시점에 타입을 정의하는데 이러한 점은 재사용 가능한 컴포넌트를 작성할 때 유용하고 타입 안정성을 유지하면서 유연하게 작성할 수 있음

1️⃣ 제네릭 함수

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const identity = <T>(value: T): T => {
  return value;
};

// 호출 시점 타입 지정 !
let output1 = identity<string>("myString");
let output2 = identity<number>(123);

console.log(output1); // "myString"
console.log(output2); // 123

// 타입 추론
console.log(identity(42));       // 42
console.log(identity("hello"));  // "hello"

2️⃣ 제네릭 인터페이스

1
2
3
4
5
6
7
8
9
10
interface PlayerIdentityFn<T> {
  (arg: T): T;
}

const playerIdentity: PlayerIdentityFn<string> = (playerName) => {
  return playerName;
};

console.log(playerIdentity("Marcus Rashford")); // Marcus Rashford
console.log(playerIdentity("Bruno Fernandes")); // Bruno Fernandes

3️⃣ 제네릭 클래스

1
2
3
4
5
6
7
8
9
10
11
12
13
class PlayerStats<T> {
  initialStat: T;
  add: (x: T, y: T) => T;

  constructor(initialStat: T, add: (x: T, y: T) => T) {
    this.initialStat = initialStat;
    this.add = add;
  }
}

const goalStats = new PlayerStats<number>(0, (x, y) => x + y);

console.log(goalStats.add(goalStats.initialStat, 5)); // 5

4️⃣ 제네릭 제약 조건

1
2
3
4
5
6
7
8
9
10
11
interface Player {
  name: string;
  goals: number;
}

const printPlayerGoals = <T extends Player>(player: T): T => {
  console.log(`${player.name} has scored ${player.goals} goals.`);
  return player;
};

printPlayerGoals({ name: "Marcus Rashford", goals: 10, team: "Man Utd" });
  • Player 인터페이스는 name, goals 두 개의 속성을 가짐
  • printPlayerGoals 함수는 제네릭 타입 변수 T를 사용하며, 이 제네릭 타입은 Player 인터페이스를 확장함
    • ➡️ T는 Player 인터페이스와 동일하거나 이를 확장하는 타입이어야 함
  • printPlayerGoals 함수를 호출 할 때, Player 인터페이스는 namegoals 속성만 포함하고 있기때문에 함수에서 player.team에 접근하려 하면 타입스크립트는 team 속성이 인터페이스에 정의되어 있지 않아 에러가 발생하는데 이러한 것이 타입 제약이라고 함
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.