인터페이스 | 타입 별칭

2022. 12. 26. 15:42프로그래밍/TypeScript

인터페이스 (interface)

타입스크립트 여러 객체를 정의하는 일종의 규칙/구조
interface 키워드 사용
? 사용 시 선택적 속성 정의 가능
interface User {
  name: string,
  readonly age: number, // 읽기 전용 속성 (readonly)
  isValid?: boolean // 선택적 속성 (Optional property)
}

 

인터페이스 + 타입 단언

interface A {
  name: string;
}

// 빈 객체로 초기화 하지만
// A의 구조로 변경될 것이라고 단언함
const a = {} as A;

// A의 구조로 변경
a.name = 'abcdefg...';

 

읽기 전용 속성

읽기 전용 속성 정의 가능
readonly 키워드 사용
// 모든 속성이 readonly일 경우
interface User { 
  name: string,
  age: number
}

// 유틸리티 (Utility) 활용
const user: Readonly<User> = {
  name: 'Neo',
  age: 36
};

// 타입 단언 (Type Assertion) 활용
const user = {
  name: 'Neo',
  age: 36
} as const;

 

함수 타입

함수 타입의 인터페이스 정의 시 호출 시그니처 사용
호출 시그니처: 함수의 매개변수, 반환 타입 지정
interface Name {
  // 호출 시그니처
  (매개변수이름: 타입) : 반환타입
}
interface User {
  name: string
}

// 함수 타입 인터페이스
interface GetUser {
  // (매개변수이름: 타입): 반환타입
  (name: string): User
}

const getUser: GetUser = name => {
  ...
  return { name }
}

getUser('Neo');

 

클래스 타입

클래스 타입의 인터페이스 정의 가능
implements 키워드 사용
interface UserClass {
  name: string,
  getName(): string
}

class User implements UserClass {
  constructor(public name: string) {
  
  }
  getName() {
    return this.name;
  }
}

const neo = new User('Neo');
neo.getName(); // Neo

 

정의한 클래스를 인수로 사용하는 경우 문제 발생

interface CatClass {
  name: string;
}

class Cat implements CatClass {
  constructor(public name: string) { }
}

function makeKitten(c: CatClass, n: string) {
  return new c(n); // Error. 'CatClass' 형식에 구문 시그니처가 없음
}

const kitten = makeKitten(Cat, 'Lucy');
console.log(kitten);

 

구성 시그니처를 가진 인터페이스를 정의하여 해결 가능

interface Name {
  // 구성 시그니처
  new (매개변수이름: 타입): 반환타입
}
interface CatClass {
  name: string;
}

// 구성 시그니처
interface CatConstructor {
  // new (매개변수이름: 타입): 반환타입
  new (name: string): CatClass;
}

class Cat implements CatClass {
  constructor(public name: string) { }
}

function makeKitten(c: CatConstructor, n: string) {
  return new c(n);
}

const kitten = makeKitten(Cat, 'Lucy');
console.log(kitten);

 

인덱싱 가능 타입 (Indexable types)

많은 속성을 가지거나
단언 불가능한 임의의 속성이 포함되는 구조에서 사용
인덱스 시그니처 사용
interface Name {
  // 인덱스 시그니처
  [인덱서이름: 타입]: 반환 타입
}
interface Item {
  // 인덱스 시그니처
  [item: number]: string 
}

const item: Item = ['a', 'b', 'c'];
console.log(item[0]);
console.log(item['0']); // Error. 인덱스는 number 타입만 가능
// 반환 타입으로 유니언 활용
interface User {
  [key: string]: string | boolean;
}

const user: User = {
  name: 'Neo',
  email: 'thesecon@gmail.com',
  isValid: true,
  0: false
};

// 인덱스: string
console.log(user['name']); // 'Neo'
console.log(user['email']); // 'thesecon@gmail.com'
console.log(user['isValid']); // true

// 인덱스: number
console.log(user[0]); // false
console.log(user[1]); // undefined

// 인덱스: string (해당하는 인덱스 값이 없음)
console.log(user['0']); // false
// 인덱스 시그니처 + 명시적으로 정의된 속성
interface User {
  [key: string]: string | number
  name: string,
  age: number
}

const user: User = {
  name: 'Neo',
  age: 123,
  
  // 인덱스: string, 값: string
  email: 'thesecon@gmail.com',
  
  // 인덱스: string, 값: boolean
  isAdult: true // Error. string 또는 number 타입만 할당 가능
};

 

keyof

인덱싱 가능 타입에서 keyof 키워드를 사용하면
속성 이름을 타입으로 사용 가능
타입의 속성 이름들이 유니온 타입으로 적용됨
keyof를 통한 인덱싱으로 타입의 값에 접근 가능
interface Countries {
  KR: '대한민국',
  US: '미국',
  CP: '중국'
}

// 속성 이름을 타입으로 사용 가능
let country: keyof Countries; // 'KR' | 'US' | 'CP'
country = 'KR';

// keyof를 통한 인덱싱으로 타입의 값에 접근 가능
let country: Countries[keyof Countries]; // Countries['KR' | 'US' | 'CP']
country = '대한민국';

 

인터페이스 확장

클래스처럼 extends 키워드로 상속 가능
같은 이름의 인터페이스 여러 개 정의 가능
기존 인터페이스와 중복되는 속성은 타입이 같아야 함
interface Animal {
  name: string;
}

interface Cat extends Animal {
  meow(): string;
}

class Cat implements Cat {
  constructor(public name: string) {}
  meow() {
    return 'MEOW~';
  }
}

const cat = new Cat('Luxy');
interface FullName {
  firstName: string,
  lastName: string
}

// 같은 이름의 인터페이스 여러 개 정의 가능
interface FullName {
  middleName: string,
  // 기존 인터페이스와 중복되는 속성은 타입이 같아야 함
  lastName: boolean // Error. string 타입이어야 함
}

const fullName: FullName = {
  firstName: 'Tomas',
  middleName: 'Sean',
  lastName: 'Connery'
};

타입 별칭 (Type Aliases)

type 키워드를 사용해 새로운 타입 조합을 만들 수 있음
하나 이상의 타입을 조합해 이름을 부여함
조합한 각 타입들을 참조하는 별칭을 만드는 것
// MyType 이라는 이름을 가진 string 타입
type MyType = string;

// YourType 라는 이름을 가진 유니언 타입
type YourType = string | number | boolean;

// string 타입의 매개변수를 받음
// YourType 타입의 값을 반환함 (string | number | boolean)
function someFunc(arg: MyType): YourType {
  switch (arg) {
    case 's':
      return arg.toString(); // string
    case 'n':
      return parseInt(arg); // number
    default:
      return true; // boolean
  }
}
// User 라는 이름을 가진 유니언 타입
type User = {
  name: string,
  age: number,
  isValid: boolean
} | [string, number, boolean]; // 튜플 타입

const userA: User = {
  name: 'Neo',
  age: 85,
  isValid: true
};

const userB: User = ['Evan', 36, false];