[TypeScript] 기초

비트·2023년 7월 27일
0

CodeStates

목록 보기
52/54
post-thumbnail
post-custom-banner

TypeScript의 열거형(Enum)

JavaScript에서는 기본적으로 열거형을 지원하지 않지만, TypeScript에서는 문자형 열거형숫자형 열거형을 지원한다.

  • TypeScript에서 열거형
    • enum Color {
        Red,
        Green,
        Blue,
      }
    • Color라는 열거형을 정의
    • 열거형의 값은 Red, Green, Blue

숫자형 열거형(Enum)

열거형은 숫자형과 문자열형, 혹은 이 둘의 조합으로 정의될 수 있다.

  • 디폴트 값으로 숫자형을 사용
    • 각 값은 자동으로 0부터 시작하여 1씩 증가
    • 그러나 수동으로 값을 지정할 수도 있다.
    • enum Color {
        Red = 1,
        Green = 2,
        Blue = 4,
      }
    • Red가 1, Green이 2, Blue가 4로 정의
  • 열거형의 값에 대해 산술 연산을 수행할 수도 있다.

    • enum Color {
         Red = 1,
         Green = 2,
         Blue = 4,
      }
      
       let c: Color = Color.Green;
       let greenValue: number = Color.Green;
       let blueValue: number = Color.Blue;
      
       console.log(c);          // 출력: 2
       console.log(greenValue);  // 출력: 2
       console.log(blueValue);   // 출력: 4
    • 열거형은 일반적으로 상수값을 대신하여 사용되므로, 타입스크립트에서는 열거형이 많이 사용.

    • 열거형은 코드를 더욱 가독성 높게 만들어주고, 오타와 같은 실수를 방지.

문자형 열거형(Enum)

문자형 열거형은 열거형의 값을 전부 다 특정 문자 또는 다른 열거형 값으로 초기화해야 한다.

  • 숫자형 열거형과 개념적으로는 거의 비슷.

    • enum Direction {
        Up = "UP",
        Down = "DOWN",
        Left = "LEFT",
        Right = "RIGHT",
      }
      
       let myDirection: Direction = Direction.Up;
       console.log(myDirection); // 출력: "UP"
    • Direction이라는 문자열 기반의 열거형(Enum)을 정의

    • Up, Down, Left, Right 각각에는 문자열 값이 할당되어 있다.

    • myDirection 변수를 Direction.Up으로 초기화하고 있다.

    • 출력 결과로는 "UP"

  • 문자형 열거형에는 숫자형 열거형과는 다르게 auto-incrementing이 없다.
    • 대신 디버깅을 할 때 숫자형 열거형의 값은 가끔 불명확하게 나올 때가 있지만, 문자형 열거형은 항상 명확한 값이 나와 읽기 편하다.
  • 문자열 기반의 열거형은 주로 외부에서 가져온 값을 TypeScript에서 다루기 위해서 사용.

    • 예를 들어, HTTP 요청 방식을 나타내는 열거형을 정의할 수 있다.

    • enum HttpMethod {
        Get = "GET",
        Post = "POST",
        Put = "PUT",
        Delete = "DELETE",
      }
      
       function makeRequest(url: string, method: HttpMethod) {
        // ...
      }
      
       makeRequest("/api/data", HttpMethod.Post);
    • HTTP 요청 방식을 나타내는 HttpMethod 열거형을 정의.

    • makeRequest 함수는 URL과 HTTP 요청 방식을 인자로 받는다.

    • HTTP 요청 방식을 지정할 때는 HttpMethod.Post와 같이 열거형 값을 사용.

  • 이렇게 열거형을 사용하면 오타와 같은 실수를 방지할 수 있으며, 코드의 가독성과 안정성을 높일 수 있다.

역 매핑 (Reverse mappings)

  • 역 매핑은 숫자형 열거형에만 존재하는 특징
    • 열거형의 키(key)값(value)을 얻을 수 있고 값(value)으로 키(key)를 얻을 수도 있다.
    • enum Enum {
          A
      }
      let a = Enum.A;
      let nameOfA = Enum[a]; // "A"
    • 열거형의 키로 값을 얻을 수 있지만, 값으로도 열거형의 키를 얻을 수 있다.
    • 이는 숫자형 열거형에만 존재하며, 문자형 열거형에서는 존재하지 않는 특징.



TypeScript의 인터페이스(Interface)

  • TypeScript에서 인터페이스(Interface)는 일반적으로 타입 체크를 위해 사용
    • 인터페이스는 변수, 함수, 클래스에 사용할 수 있으며, 인터페이스에 선언된 프로퍼티 또는 메서드의 구현을 강제하여 일관성을 유지하도록 한다.
    • TypeScript의 예약어인 interface를 사용하여 TypeScript 인터페이스를 생성할 수 있습니다.

예약어 (reserved word)

컴퓨터 프로그래밍 언어에서 이미 문법적인 용도로 사용되고 있기 때문에 식별자로 사용할 수 없는 단어를 의미.
예를 들어 return, import, const, let 등이 있으며, 이런 단어들은 함수의 이름이나 변수의 이름으로 사용할 수 없다.

변수와 인터페이스

TypeScript에서 인터페이스는 객체(Object)의 구조를 정의하기 위해 주로 사용되는 예약어

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

// 정상적으로 선언됩니다.
const user: User = {
	name: "anna",
	age: 20
}

// 프로퍼티의 순서를 지키지 않아도 정상적으로 선언됩니다.
const user: User = {
	age: 20,
	name: "anna"
}

// 정의된 프로퍼티보다 적게 작성했기 때문에 에러가 납니다.
const user: User = {
	name: "anna"
}

// 정의된 프로퍼티보다 많이 작성했기 때문에 에러가 납니다.
const user: User = {
	name: "anna",
	age: 20,
	job: "developer"
}
  • 사용자 정보를 정의하기 위해 interface 예약어를 사용하여 User 인터페이스를 만들었다.

    • 인터페이스를 만들 때 예약어를 작성하고, 인터페이스의 이름을 대문자로 작성.

    • 이렇게 인터페이스의 이름을 대문자로 시작하는 것은 *네이밍 컨벤션.

      네이밍 컨벤션 (Naming Convention)

      이름을 짓는 일종의 관례.
      TypeScript로 개발할 때 대부분의 개발자는 인터페이스의 이름을 대문자로 시작하도록 작성.
      인터페이스는 객체의 타입을 정의하고, 객체가 대문자로 시작하는 것과 유사하기 때문에 일관성 있는 코드 작성을 위해 이러한 관례를 따르는 것.

    • 인터페이스 내에는 nameage가 정의되어 있기 때문에, User 인터페이스를 사용하여 변수를 선언할 때는 반드시 정의된 프로퍼티를 전부 작성해야 한다.

    • interface로 정의된 속성만 지정할 수 있으며, 그 외 프로퍼티를 추가로 작성하고자 해도 인터페이스 내에 정의되어 있지 않기 때문에 추가로 프로퍼티를 더 작성하여 선언할 수 없다.

  • 그러나 인터페이스 안의 모든 프로퍼티가 필요한 것은 아니며, 어떤 조건에서만 존재하거나 아예 없을 수도 있기 때문에 ? 연산자를 사용하여 선택적 프로퍼티를 작성할 수도 있다.

    • interface User {
      	name: string;
      	age?: number;
      }
      
       // 정상적으로 선언됩니다.
      const user: User = {
      	name: "anna"
      }

함수와 인터페이스

  • 인터페이스를 사용하여 객체의 프로퍼티 이름과 타입을 정의하고, 함수의 매개변수 타입과 반환 타입도 정의할 수 있다.

    • interface User {
      	name: string;
      	age: number;
      	job: string;
      }
      
       interface Greeting {
      	(user: User, greeting: string): string;
      }
      
       const greet: Greeting = (user, greeting) => {
      	return `${greeting}, ${user.name}! Your job : ${user.job}.`;
      }
      
       const user: User = {
      	name: "anna",
      	age: 30,
      	job: "developer"
      };
      
       const message = greet(user, "Hi");
      
       console.log(message);
    • User 인터페이스 외에도 Greeting 인터페이스를 추가로 작성하여 함수 타입을 정의.

    • Greeting 인터페이스는 User 타입과 문자열 타입을 매개변수로 받아 문자열 타입을 반환.

    • greet 함수는 Greeting을 사용하여 구현되었으며, user 객체와 문자열 "hi"를 전달인자로 전달받아 문자열을 반환.

  • Greeting 인터페이스에서 이미 greet의 매개 변수인 usergreeting의 타입과 반환 타입이 작성되어 있기 때문에, greet 함수는 string 타입을 반환한다고 명시하지 않아도 되며, 매개 변수의 타입 또한 작성하지 않아도 된다.

클래스와 인터페이스

  • 클래스에서도 인터페이스를 사용할 수 있다.

    • interface Calculator {
      	add(x: number, y: number): number;
      	substract(x: number, y: number): number;
      }
      
       class SimpleCalculator implements Calculator {
      	add(x: number, y:number) {
      		return x + y;
      	}
      
      	substract(x: number, y: number) {
      		return x - y;
      	}
      }
      
       const caculator = new SimpleCalculator();
      
       console.log(caculator.add(4, 9)); //13
       console.log(caculator.substract(10, 5)); //5
    • Calculator 인터페이스는 addsubstract 메서드를 정의.

    • SimpleCaculator 클래스는 Calculator 인터페이스를 사용하여 작성되었다.

    • Caculator 인터페이스를 사용하고 있기 때문에 SimpleCaculator 클래스 내에는 Calculator 인터페이스 내에 정의된 두 메서드를 반드시 작성해야 한다.

  • 또한 클래스를 구현할 때 인터페이스에서 정의된 함수나 메서드의 매개변수 타입과 반환 값과 일치하도록 구현해야 하므로, 클래스 내부에서 해당 메서드의 매개변수 타입을 다시 한번 더 명시해 주지 않으면 컴파일 에러가 발생하게 된다.

인터페이스와 상속

  • JavaScript에서 클래스를 확장할 때 extends라는 키워드를 사용해 기존에 존재하던 클래스를 상속해 새로운 클래스를 정의할 수 있다.
class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }

  sayHello() {
    console.log(`Hello, my name is ${this.name} and I'm ${this.age} years old.`);
  }
}

//Person 클래스를 extends 키워드를 사용해 상속하여 새로운 클래스인 Student를 정의했습니다.
class Student extends Person {
  constructor(name, age, grade) {
    super(name, age);
    this.grade = grade;
  }

  study() {
    console.log(`${this.name} is studying hard for the grade ${this.grade}.`);
  }
}

  • 이같이 인터페이스도 extends라는 키워드를 사용하여 기존에 존재하던 인터페이스를 상속해 확장이 가능.

  • 이렇게 하면 기존에 존재하던 인터페이스의 프로퍼티를 다른 인터페이스에 복사하는 것을 가능하게 해 주며, 인터페이스의 재사용성을 높여준다.


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

interface Developer extends Person {
    language: string;
}

const person: Developer = {
    language: "TypeScript",
    age: 20,
    name: "Anna",
}
  • 기존에 존재하던 Person 인터페이스를 extends 키워드로 상속해 새로운 인터페이스인 Developer를 만들고,
  • Developer 인터페이스를 사용하여 person이라는 객체를 구현.
  • Developer 인터페이스는 Person 인터페이스를 상속하고 있으므로, Person 내부의 프로퍼티를 그대로 받아올 수 있다.

마찬가지로 여러 인터페이스를 상속받아 확장할 수도 있다.

interface FoodStuff {
    name: string;
}

interface FoodAmount {
    amount: number;
}

interface FoodFreshness extends FoodStuff, FoodAmount {
	   isFreshed: boolean;
}

const food = {} as FoodFreshness;

food.name = "egg";
food.amount = 2;
food.isFreshed = true;
  • food 변수의 값으로 빈 객체를 할당하는 부분
    • as라는 키워드를 이용하여 해당 값에 FoodFeshness라는 타입으로 정의
    • 이러한 문법을 타입 단언(type assertion)

      타입 단언 (type assertion)

      컴파일러에게 특정 타입 정보의 사용을 강제하게 함으로써, 컴파일러가 가진 정보를 무시하고 프로그래머가 원하는 임의의 타입을 값에 할당할 수 있다.

    • 주의할 점은 타입 단언은 타입 에러만 없애줄 뿐, 런타임 에러까지는 막아주지 못하기 때문에, 타입 단언이 꼭 필요한 경우가 아니라면 안전성 체크도 되는 타입 선언을 사용하는 것이 좋다.
profile
Drop the Bit!
post-custom-banner

0개의 댓글