Interfaces

장유진·2022년 6월 22일
1

TypeScript

목록 보기
4/14

https://www.typescriptlang.org/docs/handbook/interfaces.html

TypeScript는 structural subtyping을 사용한다. 즉, 변수가 가진 모양을 기준으로 타입을 판단한다. interface는 이런 type들의 이름을 지정하는 역할을 한다.

Our First Interface

interface LabeledValue {
  label: string;
}

function printLabel(labeledObj: LabeledValue) {
  console.log(labeledObj.label);
}

let myObj = { size: 10, label: "Size 10 Object" };
printLabel(myObj);

interface는 LabeledValue라는 타입의 구조(shape)을 정의한다.
printLabel은 myObj가 label이라는 이름을 가진 string 타입을 가진 property가 있는지만 확인하고 그 외는 확인하지 않는다.

Optional Properties

property의 이름 뒤에 물음표(?)를 붙여서 존재할 수도 있고 아닐 수도 있는 property임을 명시한다.
이 경우 undefined가 자동으로 포함되기 때문에 undefind를 굳이 별도로 추가하지 않아도 된다.

interface SquareConfig {
  color?: string; // color?: string | undefined와 동일
  width?: number;
}

function createSquare(config: SquareConfig): { color: string; area: number } {
  let newSquare = { color: "white", area: 100 };
  if (config.color) {
    newSquare.color = config.color;
  }
  if (config.width) {
    newSquare.area = config.width * config.width;
  }
  return newSquare;
}

Readonly properties

property 이름 앞에 "readonly"를 적으면 해당 property는 변경할 수 없게 된다.
readonly와 const는 같은 효과를 갖지만 readonly는 property에, const는 변수에 사용한다.

interface Point {
  readonly x: number;
  readonly y: number;
}

Excess Property Checks

TypeScript는 객체(object literal)를 새로 만들어 변수에 할당하거나 인자로 넘겨줄 때 excess property checking을 진행한다. 이 과정에서 만약 객체가 지정된 타입에 해당하지 않는 property를 가지고 있다면 에러가 발생한다.

interface SquareConfig {
  color?: string;
  width?: number;
}

function createSquare(config: SquareConfig): { color: string; area: number } {
  ...
}

let square1 = createSquare({ clor: "red", width: 100 }); // error!
let square2 : SquareConfig = { clor: "red", width: 100 }; // error!

Function Types

interface로 함수의 타입을 지정할 수도 있다. 이 때에는 interface에 call signature라는 것을 준다. call signature는 함수의 매개 변수들과 return 타입을 지정한다. 매개 변수들은 모두 이름과 타입을 지정해주어야 한다.

interface SearchFunc {
  (source: string, subString: string): boolean;
}

let mySearch: SearchFunc;
mySearch = function (src: string, sub: string) {
  let result = source.search(subString);
  return result > -1;
};

Indexable Types

interface로 a[10]이나 a["daniel"]같은 인덱스 타입도 지정할 수 있다. 이 때는 index signature라는 것을 주는데, 이는 index와 return type을 지정한다.

interface StringArray {
  [index: number]: string;
}

let myArray: StringArray;
myArray = ["Bob", "Fred"];

index signature는 string과 number의 두 가지 형태가 가능하다. 둘 다 사용할 수도 있지만 numeric indexer의 return 타입이 string indexer의 return 타입의 subtype이어야 한다. 따라서 아래의 경우는 에러가 발생한다.

interface Animal {
  name: string;
}

interface Dog extends Animal {
  breed: string;
}

// Error: indexing with a numeric string might get you a completely separate type of Animal!
interface NotOkay {
  [x: number]: Animal;
  [x: string]: Dog;
}

Class Types

Implementing an interface

다른 언어에서와 마찬가지로 interface로 class를 구현할 수 있다. interface에 명시된 method도 class에서 구현할 수 있다. 그리고 interface로 구현한 내용은 class에서 public이다.

interface ClockInterface {
  currentTime: Date;
  setTime(d: Date): void;
}

class Clock implements ClockInterface {
  currentTime: Date = new Date();
  setTime(d: Date) {
    this.currentTime = d;
  }
  constructor(h: number, m: number) {}
}

Difference between the static and instance sides of classes

class는 두 가지 타입을 가진다.

  • static side의 타입: 모든 클래스가 공통적으로 가지는 것 ex) static 변수, constructor
  • instance side의 타입: 각각의 클래스가 따로 가지는 것 ex) 일반 함수, 변수

class가 interface를 구현할 때에는 instance side만 가능하다.

Extending Interfaces

interface도 class처럼 서로 상속할 수 있고, 다중상속도 가능하다.

interface Shape {
  color: string;
}

interface PenStroke {
  penWidth: number;
}

interface Square extends Shape, PenStroke {
  sideLength: number;
}

Hybrid Types

하나의 객체가 여러 타입을 가지는 경우도 있다.

interface Counter {
  (start: number): string;
  interval: number;
  reset(): void;
}

function getCounter(): Counter {
  let counter = function (start: number) {} as Counter;
  counter.interval = 123;
  counter.reset = function () {};
  return counter;
}

let c = getCounter();
c(10); // function type
c.reset(); // object type
c.interval = 5.0; // object type

Interfaces Extending Classes

interface가 class를 상속하게 되면 class의 멤버들만 상속받고 구현은 상속받지 않는다. 또한 base class의 private나 protected 멤버들도 상속받을 수 있기 때문에 이렇게 된다면 이 interface는 base class나 bace class의 상위 클래스로만 구현이 가능하다.

profile
프론트엔드 개발자

0개의 댓글