1. 다음 코드에서 unknown으로 정의된 User 타입을 적절히 수정하여 완성하세요.
export type User = unknown;

export const users: unknown[] = [
  {
    name: "Max Mustermann",
    age: 25,
    occupation: "Chimney sweep",
  },
  {
    name: "Kate Müller",
    age: 23,
    occupation: "Astronaut",
  },
];

export function logPerson(user: unknown) {
  console.log(` - ${user.name}, ${user.age}`);
}

console.log("Users:");
users.forEach(logPerson);
  1. unknown으로 정의된 타입 Person을 적절히 수정하여 코드를 완성하세요.

    interface User {
      name: string;
      age: number;
      occupation: string;
    }
    
    interface Admin {
      name: string;
      age: number;
      role: string;
    }
    
    export type Person = unknown;
    
    export const persons: User[] /* <- Person[] */ = [
      {
        name: "Max Mustermann",
        age: 25,
        occupation: "Chimney sweep",
      },
      {
        name: "Jane Doe",
        age: 32,
        role: "Administrator",
      },
      {
        name: "Kate Müller",
        age: 23,
        occupation: "Astronaut",
      },
      {
        name: "Bruce Willis",
        age: 64,
        role: "World saver",
      },
    ];
    
    export function logPerson(user: User) {
      console.log(` - ${user.name}, ${user.age}`);
    }
    
    persons.forEach(logPerson);
    
  2. 타입 가드를 적용하여 logPerson()을 적절히 수정하세요.

    interface User {
      name: string;
      age: number;
      occupation: string;
    }
    
    interface Admin {
      name: string;
      age: number;
      role: string;
    }
    
    export type Person = User | Admin;
    
    export const persons: Person[] = [
      {
        name: "Max Mustermann",
        age: 25,
        occupation: "Chimney sweep",
      },
      {
        name: "Jane Doe",
        age: 32,
        role: "Administrator",
      },
      {
        name: "Kate Müller",
        age: 23,
        occupation: "Astronaut",
      },
      {
        name: "Bruce Willis",
        age: 64,
        role: "World saver",
      },
    ];
    
    export function logPerson(person: Person) {
      let additionalInformation: string;
      if (person.role) {
        additionalInformation = person.role;
      } else {
        additionalInformation = person.occupation;
      }
      console.log(` - ${person.name}, ${person.age}, ${additionalInformation}`);
    }
    
    persons.forEach(logPerson);
    
  3. 사용자 타입 가드가 제대로 동작하도록 isAdminisUser를 적절히 수정하세요.

    interface User {
      type: "user";
      name: string;
      age: number;
      occupation: string;
    }
    
    interface Admin {
      type: "admin";
      name: string;
      age: number;
      role: string;
    }
    
    export type Person = User | Admin;
    
    export const persons: Person[] = [
      {
        type: "user",
        name: "Max Mustermann",
        age: 25,
        occupation: "Chimney sweep",
      },
      { type: "admin", name: "Jane Doe", age: 32, role: "Administrator" },
      { type: "user", name: "Kate Müller", age: 23, occupation: "Astronaut" },
      { type: "admin", name: "Bruce Willis", age: 64, role: "World saver" },
    ];
    
    export function isAdmin(person: Person) {
      return person.type === "admin";
    }
    
    export function isUser(person: Person) {
      return person.type === "user";
    }
    
    export function logPerson(person: Person) {
      let additionalInformation: string = "";
      if (isAdmin(person)) {
        additionalInformation = person.role;
      }
      if (isUser(person)) {
        additionalInformation = person.occupation;
      }
      console.log(` - ${person.name}, ${person.age}, ${additionalInformation}`);
    }
    
    console.log("Admins:");
    persons.filter(isAdmin).forEach(logPerson);
    
    console.log();
    
    console.log("Users:");
    persons.filter(isUser).forEach(logPerson);
    
  4. filterUsers()criteria 파라미터는 온전한 User 객체를 요구하고 있습니다. 필요한 요소만 선택적으로 전달받을 수 있도록 함수를 적절히 수정하세요. 단, type은 제외되어야 합니다.

    interface User {
      type: "user";
      name: string;
      age: number;
      occupation: string;
    }
    
    interface Admin {
      type: "admin";
      name: string;
      age: number;
      role: string;
    }
    
    export type Person = User | Admin;
    
    export const persons: Person[] = [
      {
        type: "user",
        name: "Max Mustermann",
        age: 25,
        occupation: "Chimney sweep",
      },
      {
        type: "admin",
        name: "Jane Doe",
        age: 32,
        role: "Administrator",
      },
      {
        type: "user",
        name: "Kate Müller",
        age: 23,
        occupation: "Astronaut",
      },
      {
        type: "admin",
        name: "Bruce Willis",
        age: 64,
        role: "World saver",
      },
      {
        type: "user",
        name: "Wilson",
        age: 23,
        occupation: "Ball",
      },
      {
        type: "admin",
        name: "Agent Smith",
        age: 23,
        role: "Administrator",
      },
    ];
    
    export const isAdmin = (person: Person): person is Admin =>
      person.type === "admin";
    export const isUser = (person: Person): person is User =>
      person.type === "user";
    
    export function logPerson(person: Person) {
      let additionalInformation = "";
      if (isAdmin(person)) {
        additionalInformation = person.role;
      }
      if (isUser(person)) {
        additionalInformation = person.occupation;
      }
      console.log(` - ${person.name}, ${person.age}, ${additionalInformation}`);
    }
    
    export function filterUsers(persons: Person[], criteria: User): User[] {
      return persons.filter(isUser).filter((user) => {
        const criteriaKeys = Object.keys(criteria) as (keyof User)[];
        return criteriaKeys.every((fieldName) => {
          return user[fieldName] === criteria[fieldName];
        });
      });
    }
    
    console.log("Users of age 23:");
    
    filterUsers(persons, {
      age: 23,
    }).forEach(logPerson);
    
  5. 함수 오버로딩을 적용해 filterPerson()의 타입 안전성을 개선하세요.

    interface User {
      type: "user";
      name: string;
      age: number;
      occupation: string;
    }
    
    interface Admin {
      type: "admin";
      name: string;
      age: number;
      role: string;
    }
    
    export type Person = User | Admin;
    
    export const persons: Person[] = [
      {
        type: "user",
        name: "Max Mustermann",
        age: 25,
        occupation: "Chimney sweep",
      },
      { type: "admin", name: "Jane Doe", age: 32, role: "Administrator" },
      { type: "user", name: "Kate Müller", age: 23, occupation: "Astronaut" },
      { type: "admin", name: "Bruce Willis", age: 64, role: "World saver" },
      { type: "user", name: "Wilson", age: 23, occupation: "Ball" },
      { type: "admin", name: "Agent Smith", age: 23, role: "Anti-virus engineer" },
    ];
    
    export function logPerson(person: Person) {
      console.log(
        ` - ${person.name}, ${person.age}, ${
          person.type === "admin" ? person.role : person.occupation
        }`
      );
    }
    
    export function filterPersons(
      persons: Person[],
      personType: string,
      criteria: unknown
    ): unknown[] {
      return persons
        .filter((person) => person.type === personType)
        .filter((person) => {
          let criteriaKeys = Object.keys(criteria) as (keyof Person)[];
          return criteriaKeys.every((fieldName) => {
            return person[fieldName] === criteria[fieldName];
          });
        });
    }
    
    export const usersOfAge23 = filterPersons(persons, "user", { age: 23 });
    export const adminsOfAge23 = filterPersons(persons, "admin", { age: 23 });
    
    console.log("Users of age 23:");
    usersOfAge23.forEach(logPerson);
    
    console.log();
    
    console.log("Admins of age 23:");
    adminsOfAge23.forEach(logPerson);