[TypeScript] 인터페이스

JINJIN·2023년 4월 25일
1

TypeScript

목록 보기
5/6
post-thumbnail

TypeScript에 대해서 하나씩 차근차근 배우면서 작성하는 글입니다.

✨ 인터페이스

TypeScript인터페이스(Interface)는 객체의 구조를 정의하는 방법입니다.
인터페이스는 변수, 함수, 클래스 등에서 사용할 수 있는 타입을 명시해주며, 여러가지 타입을 갖는 프로퍼티로 이루어진 새로운 타입을 정의하는 것과 유사합니다!

쉽게 비유하자면 인터페이스를 건축표준이나 청사진이라고 생각할 수 있습니다. 건물을 짓기 전에 청사진이 필요하듯이, TypeScript에서 객체를 생성하거나 함수를 정의할 때 인터페이스를 통해 구조와 기대되는 타입을 명시할 수 있습니다.

인터페이스는 객체가 가져야 할 프로퍼티와 메소드, 그리고 해당 타입을 정의해주는 역할을 하며, 이를 통해 코드의 안정성과 가독성이 향상됩니다. 실제 객체는 인터페이스에 정의된 청사진을 따라 구현되고, 이를 통해 일관된 구조를 유지할 수 있습니다.


😎 인터페이스 사용 방법

예를 들어, 다음과 같은 인터페이스와 객체가 있다고 가정해봅시다.

// 인터페이스 생성
interface Car {
  make: string;
  model: string;
  year: number;
  start(): void;
}

const myCar: Car = {
  make: 'Toyota',
  model: 'Camry',
  year: 2020,
  start() {
    console.log('Engine started.');
  },
};

위 예시 코드에서 Car 인터페이스는 자동차 객체의 구조를 정의하고 있습니다.
그리고 myCar 객체는 Car 인터페이스를 구현하는 구체적인 인스턴스입니다.

인터페이스와 객체는 관련이 있지만, 엄밀히 말하면 같은 개념은 아닙니다. 인터페이스는 객체의 구조를 정의하는 것이고, 객체는 그 구조를 따르는 실제 데이터와 메소드를 가진 인스턴스입니다.

인터페이스는 객체의 형태를 규정하며, 어떤 프로퍼티와 메소드가 있어야 하는지 명시합니다!

또 다른 예시 코드를 보여드리겠습니다.

// 인터페이스 생성
interface Todo {
  id: number;
  content: string;
  completed: boolean;
}

// 변수 todo의 타입으로 Todo 인터페이스를 선언하였다.
let todo: Todo;

// 변수 todo는 Todo 인터페이스를 준수하여야 한다.
todo = { id: 1, content: 'typescript', completed: false };
// 인터페이스 생성
interface Todo {
  id: number;
  content: string;
  completed: boolean;
}

// 변수 todo의 타입으로 Todo 인터페이스를 선언과 동시에 객체 생성
let todo: Todo = {
  id: 1,
  content: 'typescript'
  completed: false,
};

첫 번째 방식은 변수의 타입을 명시적으로 선언하고 나중에 값을 할당하는 방식입니다.
이 방식은 변수의 타입을 먼저 확인하고 싶을 때나, 나중에 값을 할당하는 경우에 유용할 수 있습니다.

두 번째 방식은 변수를 선언함과 동시에 값을 할당하는 방식입니다.
이 방식은 코드를 간결하게 작성할 수 있으며, 변수를 선언하면서 바로 값을 할당하고 싶을 때 사용하기 좋습니다.

두 가지 방식 모두 올바르게 사용된 예시이므로, 상황과 취향에 맞게 선택하여 사용하면 됩니다.
중요한 것은 코드의 일관성과 가독성을 유지하는 것입니다.


😎 함수와 인터페이스

또한 인터페이스는 함수의 타입으로도 사용할 수 있습니다.
이를 통해 함수가 가져야 할 매개변수의 타입과 반환값의 타입을 명시적으로 정의할 수 있습니다.

함수 타입 인터페이스를 정의하려면 인터페이스 내부에 호출 시그니처(Call Signature)를 작성해야 합니다. 호출 시그니처는 함수의 매개변수 타입과 반환 타입을 나타냅니다.

예를 들어, 두 숫자를 더하는 함수의 타입을 정의하는 인터페이스를 작성해봅시다.

interface AddFunction {
  (a: number, b: number): number;
}

위 예제 코드에서 AddFunction 인터페이스는 두 개의 숫자 매개변수를 받고 숫자를 반환하는 함수의 타입을 정의하고 있습니다.

이제 이 인터페이스를 사용하여 함수를 구현할 수 있습니다.

const add: AddFunction = (x, y) => x + y;

const result = add(10, 20); // 30

add 함수는 AddFunction 인터페이스를 따르기 때문에, 매개변수와 반환 타입이 인터페이스에서 정의한 것과 일치해야 합니다.

함수 타입 인터페이스를 사용하면 함수의 매개변수와 반환값의 타입을 명시적으로 정의하여, 코드의 가독성을 높이고 오류를 줄일 수 있습니다.


😎 클래스와 인터페이스

아직 제 포스팅에서는 클래스 기능에 대해서 소개를 드리지는 않았지만 TypeScript에서 클래스와 인터페이스는 타입스크립트에서 서로 밀접한 관계를 가지고 있습니다.

쉽게 설명하자면 인터페이스는 객체의 구조를 정의하는 역할을 하며, 클래스는 객체의 구현을 제공합니다.

클래스가 인터페이스를 구현하려면 implements 키워드를 사용합니다. 이를 통해 클래스는 인터페이스에 정의된 프로퍼티와 메소드를 반드시 구현해야 합니다.

예를 들어, Person이라는 인터페이스와 이를 구현하는 Employee 클래스를 작성해보겠습니다.

interface Person {
  name: string;
  age: number;
  greet(): void;
}

class Employee implements Person {
  name: string;
  age: number;

  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }

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

const employee = new Employee('John Doe', 30);
employee.greet(); // Hello, my name is John Doe and I am 30 years old.

여기서 Person 인터페이스는 name, age, greet라는 프로퍼티와 메소드를 정의하고 있습니다.
그리고 Employee 클래스는 Person 인터페이스를 구현하므로, 이 클래스는 인터페이스에 정의된 모든 프로퍼티와 메소드를 반드시 포함해야 합니다.

클래스와 인터페이스를 함께 사용하면 코드의 일관성과 안정성을 높일 수 있습니다.
인터페이스는 코드의 구조를 정의하고, 클래스는 이를 구현함으로써 명확한 규약을 만들 수 있습니다.


🙄 선택적 프로퍼티

TypeScript에서 인터페이스의 프로퍼티는 반드시 구현해야 합니다.
하지만 프로퍼티가 선택적으로 필요한 경우가 있을 수 있습니다.

선택적 프로퍼티는 인터페이스에서 프로퍼티가 있어도 되고 없어도 되는 경우에 사용합니다. 선택적 프로퍼티는 프로퍼티 이름 뒤에 물음표(?)를 붙여서 정의합니다.

이렇게 정의된 프로퍼티는 해당 인터페이스를 구현하는 객체에서 해당 프로퍼티의 존재 여부가 선택적이 됩니다.

예를 들어, 사용자 정보를 나타내는 인터페이스에서 age 프로퍼티가 선택적인 경우를 생각해봅시다.

interface UserInfo {
  username: string;
  email: string;
  age?: number; // 선택적 프로퍼티
}

이제 UserInfo 인터페이스를 구현하는 객체에서 age 프로퍼티는 있어도 되고 없어도 됩니다!

const user1: UserInfo = {
  username: 'JohnDoe',
  email: 'john.doe@example.com',
  age: 30, // age 프로퍼티가 있는 경우
};

const user2: UserInfo = {
  username: 'JaneDoe',
  email: 'jane.doe@example.com',
  // age 프로퍼티가 없는 경우
};

선택적 프로퍼티를 사용하면 인터페이스를 더 유연하게 정의할 수 있습니다.
프로퍼티의 존재 여부가 명확하지 않은 경우에 유용하며, 다양한 상황에서 동일한 인터페이스를 사용할 수 있습니다.

하지만 선택적 프로퍼티를 사용할 때에는 객체의 프로퍼티 존재 여부를 확인하거나 기본값을 제공하는 등의 추가 처리가 필요할 수도 있습니다.


🙄 읽기 전용 프로퍼티

TypeScript의 읽기 전용 프로퍼티는 인터페이스에서 프로퍼티 값을 변경할 수 없게 하려는 경우 사용합니다.

읽기 전용 프로퍼티는 readonly 키워드를 사용하여 정의합니다!
이렇게 정의된 프로퍼티는 해당 인터페이스를 구현하는 객체에서 해당 프로퍼티 값을 변경할 수 없으며 값이 할당되는 시점에만 초기값을 지정할 수 있습니다.

예를 들어, ID 값이 변경되면 안 되는 사용자 정보를 나타내는 인터페이스에서 id 프로퍼티를 읽기 전용으로 정의해봅시다.

interface UserInfo {
  readonly id: number;
  username: string;
  email: string;
}

이제 UserInfo 인터페이스를 구현하는 객체에서 id 프로퍼티는 읽기 전용이므로 값을 변경할 수 없습니다.

const user: UserInfo = {
  id: 1,
  username: 'JohnDoe',
  email: 'john.doe@example.com',
};

user.id = 2; // 오류: Cannot assign to 'id' because it is a read-only property.

위 예시 코드처럼 읽기 전용 프로퍼티의 값을 변경하려고 하면 오류가 나옵니다!

읽기 전용 프로퍼티는 변경되지 않아야 하는 값이나 상수 값을 나타낼 때 유용합니다.
객체의 프로퍼티 값을 변경하지 못하도록 제한할 수 있어, 코드의 안정성을 높일 수 있습니다.

또한 읽기 전용 프로퍼티는 인터페이스뿐만 아니라 클래스에서도 사용할 수 있습니다.


🙄 인터페이스 확장(상속)

인터페이스 확장 또한 많이 쓰는 기능 중 하나입니다!
한 인터페이스가 다른 인터페이스의 멤버를 상속하여 확장하는 기능이며 인터페이스 확장은 extends 키워드를 사용하여 수행됩니다.

이를 통해 기존 인터페이스에 정의된 프로퍼티와 메소드를 새 인터페이스에 추가하거나, 기존 인터페이스를 기반으로 새로운 인터페이스를 생성할 수 있습니다.

예를 들어, 도형의 기본 속성을 나타내는 Shape 인터페이스와 이를 확장한 CircleRectangle 인터페이스를 작성해보겠습니다.

interface Shape {
  color: string;
  area(): number;
}

interface Circle extends Shape {
  radius: number;
}

interface Rectangle extends Shape {
  width: number;
  height: number;
}

여기서 Shape 인터페이스는 color 프로퍼티와 area 메소드를 정의하고 있습니다. CircleRectangle 인터페이스는 Shape 인터페이스를 확장하여 각각 radius, width, height 프로퍼티를 추가합니다.

const circle: Circle = {
  color: 'blue',
  radius: 10,
  area() {
    return Math.PI * this.radius * this.radius;
  },
};

const rectangle: Rectangle = {
  color: 'red',
  width: 10,
  height: 20,
  area() {
    return this.width * this.height;
  },
};

인터페이스 확장을 사용하면 코드의 재사용성과 계층 구조를 더 명확하게 표현할 수 있습니다.
이를 통해 더욱 간결하고 유지보수가 쉬운 코드를 작성할 수 있습니다.

TypeScript 인터페이스에 대해서는 더 소개해줄 기능들이 많아서 다음에 다른 기능들을 소개하는 포스팅을 작성해보겠습니다!

profile
안녕하세요! 배우는 것을 좋아하는 개발자 JINJIN입니다.

0개의 댓글