TypeScript, 함수 내에서 this 선언하기

아래와 같은 코드가 있습니다.

interface User {
  id: number;
  name: string;
  admin: boolean;
}

interface DB {
  filterUsers(filter: (/*this: User*/) => boolean): User[];
}

class UserDB implements DB {
  private users: User[] = [
    { id: 1, name: "Alice", admin: true },
    { id: 2, name: "Bob", admin: false },
    { id: 3, name: "Charlie", admin: true },
    { id: 4, name: "David", admin: false },
  ];

  filterUsers(filter: (/*this: User*/) => boolean): User[] {
    const result: User[] = [];

    for (const user of this.users) {
      // filter 함수의 this를 현재 user로 지정하여 호출
      if (filter.call(user)) {
        result.push(user);
      }
    }

    return result;
  }
}

function getDB(): DB {
  return new UserDB();
}

// ------------------------
// 사용 예제
// ------------------------

const db = getDB();

const admins = db.filterUsers(function (this: User) {
  return this.admin;
});

console.log(admins);

중요한 것은 43번째 줄의 인자로 받은 함수의 인자가 this: User라는 것입니다. 인자로 받은 이 함수는 filter라는 이름으로 24번째 줄에서 filter.call(user)로 호출되고 있습니다. 43번째의 코드는 Javascript에서는 허락하지 않는 문법입니다. Type를 항상 확인해야만 하는 TypeScript에서는 이 this: User를 통해 인자로 받는 함수 내부에서의 this의 타입도 확인을 해야하므로 개발자가 직접 this의 타입을 User라고 명시 해준 것입니다. this: User가 없을 경우 thisany 타입으로 추론될 것이기 때문입니다. 이렇게 된 이유는 filter.call(user)와 같은 형태로 호출되고 있기 때문인데, 이러한 호출 방식은 오래된 방식입니다. 하지만 지금도 매우 많이 사용되고 있는 방식이기도 합니다. 그럼 지금 방식(정확히는 제가 주장하는 방식)으로 바꾼다면 다음과 같습니다.

interface User {
  id: number;
  name: string;
  admin: boolean;
}

interface DB {
  filterUsers(filter: (user: User) => boolean): User[];
}

class UserDB implements DB {
  private users: User[] = [
    { id: 1, name: "Alice", admin: true },
    { id: 2, name: "Bob", admin: false },
    { id: 3, name: "Charlie", admin: true },
    { id: 4, name: "David", admin: false },
  ];

  // filterUsers(filter: (this: User) => boolean): User[] {
  filterUsers(filter: (user: User) => boolean): User[] {
    const result: User[] = [];

    for (const user of this.users) {
      // filter 함수의 인자에 직접 현재 user를 지정하여 호출
      if (filter(user)) {
        result.push(user);
      }
    }

    return result;
  }
}

function getDB(): DB {
  return new UserDB();
}

// ------------------------
// 사용 예제
// ------------------------

const db = getDB();

const admins = db.filterUsers((user: User) => {
  return user.admin;
});

console.log(admins);

명확합니다. 저는 이 방식을 선호하지만.. 현재 제공되는 매우 유명한 라이브러리들이 이 방식으로 제공되지 않으므로 전자의 방식도 알아두고 있어야 합니다.

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다