일반적으로 객체 타입에 사용함.
(확장이 더 쉬움.)
interface Person {
name: string;
age: number;
}
// ✅
const person: Person = {
name: "Mark",
age: 39,
};
// ❌: 프로퍼티가 없음
const person2: Person = {
name: "Anna",
};
// ❌: 불필요한 프로퍼티
const person3: Person = {
name: "Anna",
age: 39,
language: "ko",
};
interface Account {
bank: string;
name: string;
age: number;
memo?: string;
}
// ✅: memo는 없어도 됨
const account: Account = {
bank: "kakao",
name: "Mark",
age: 39,
};
// ✅: memo가 있어도 됨
const account2: Account = {
bank: "kakao",
name: "Mark",
age: 39,
memo: "test",
};
interface Point {
readonly x: number;
readonly y: number;
}
let p1: Point = { x: 10, y: 20 };
p1.x = 5; // 오류!
let a: number[] = [1, 2, 3, 4];
let ro: ReadonlyArray<number> = a;
ro[0] = 12; // 오류!
ro.push(5); // 오류!
ro.length = 100; // 오류!
a = ro; // 오류!
// 단, 타입 단언으로 오버라이딩 가능
a = ro as number[];
readonly는 프로퍼티
const는 변수
기본적으로 명시되지 않은(초과된) 프로퍼티 사용 시 오류가 발생함.
이 검사를 피할 수 있는 방법이 있지만 오류를 우회하는 것보다 타입 정의를 수정하는 게 좋음.
interface SearchFunc {
(source: string, subString: string): boolean;
}
let mySearch: SearchFunc;
mySearch = function (source: string, subString: string) {
return source.search(subString) > -1;
};
함수 타입에서 매개변수 이름은 상관 없음. 위치를 기준으로 타입을 체크함.
객체가 인덱스를 통해 접근될 때 어떤 타입 값을 반환할지 지정
interface StringArray {
[index: number]: string; // 인덱스(숫자)로 접근했을 때 문자열을 반환한다.
}
let myArray: StringArray;
myArray = ["Bob", "Fred"];
let myStr: string = myArray[0];
읽기 전용 인덱스 시그니처
interface ReadonlyStringArray {
readonly [index: number]: string;
}
let myArray: ReadonlyStringArray = ["Alice", "Bob"];
myArray[2] = "Mallory"; // 오류: 인덱스 시그니처가 읽기 전용입니다.
배열은 const로 선언해도 내부의 값은 바꿀 수 있지만 읽기 전용 인덱스 시그니처를 통해 읽기 전용으로 바꿀 수 있음.
인터페이스로 클래스의 내용을 강제할 수 있음.
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) { }
}
인터페이스는 시그니처(계약)만 정의한다. 구현 내용이 표함되지 않는다.
추상 클래스는 실제 구현 코드 포함할 수 있다.
인터페이스는 다중 상속 허용하여(implements),
추상 클래스는 단일 상속만 가능하다.(extends)
인터페이스는 타입 체킹, 계약 정의가 초점이며,
추상 클래스는 코드 재사용과 공통 기능 구현에 사용된다.
클래스는 두 가지 타입을 가진다.
클래스가 인터페이스를 implements 하면 클래스의 인스턴스만 검사한다.
constructor 생성자는 스태틱이므로 검사에 포함되지 않는다.
그래서 이런 오류가 발생함.
interface ClockConstructor {
new (hour: number, minute: number);
}
class Clock implements ClockConstructor { // 오류: 클래스 'Clock'가 인터페이스 'ClockConstructor'를 올바르게 구현하지 못함.
currentTime: Date;
constructor(h: number, m: number) { }
}
그래서 생성자 함수를 수동(?)으로 구현하는 식으로 처리
interface ClockConstructor {
new (hour: number, minute: number);
}
class Clock implements ClockConstructor { // constructor() 때문에 에러 발생함.
currentTime: Date;
constructor(h: number, m: number) {}
}
function createClock(
ctor: ClockConstructor,
hour: number,
minute: number
): Clock {
return new ctor(hour, minute);
}
이런걸 팩토리 함수라고 한다?!

interface Shape {
color: string;
}
interface PenStroke {
penWidth: number;
}
interface Square extends Shape, PenStroke {
sideLength: number;
}
let square = {} as Square;
square.color = "blue";
square.sideLength = 10;
square.penWidth = 5.0;
하나의 변수가 함수처럼 호출될 수도 있고, 객체(프로퍼티 + 메서드) 처럼 동작 가능
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 () {
this.interval = 0;
};
return counter;
}
let c = getCounter();
c(10);
c.reset();
c.interval = 5.0;
인터페이스가 클래스의 "계획도"를 빌려가는 것과 비슷
계획도에는 클래스의 필드, 메서드 등 세부정보가 있지만, 어떻게 구현해야 하는지는 포함되지 않음.
상속: 클래스가 클래스를 상속받을 때는 모든 속성과 메서드(구현을 포함하여) 상속
확장: 인터페이스가 클래스를 확장할 때는, 클래스의 멤버들의 '리스트'만 상속받고, 그 구현을 상속받지 않음.
// 'Control' 클래스 정의: 모든 컨트롤의 기본이 되는 클래스.
// 이 클래스에는 외부에서 접근할 수 없는 'state'라는 private 멤버 변수가 있습니다.
class Control {
private state: any;
}
// 'SelectableControl' 인터페이스 정의: 'Control' 클래스를 확장하고,
// 'select' 메서드를 추가하는 인터페이스.
// 이 인터페이스는 'Control'의 모든 멤버를 상속받지만 구현은 상속받지 않습니다.
// 'select' 메서드는 구현되어야 합니다.
interface SelectableControl extends Control {
select(): void;
}
// 'Button' 클래스 정의: 'Control' 클래스를 상속받고,
// 'SelectableControl' 인터페이스를 구현합니다.
// 'select' 메서드를 구현하여 'SelectableControl' 인터페이스의 요구 사항을 충족시킵니다.
class Button extends Control implements SelectableControl {
select() {}
}
// 'TextBox' 클래스 정의: 'Control' 클래스를 상속받습니다.
// 이 클래스는 'select' 메서드를 가지고 있지만, 'SelectableControl' 인터페이스를 명시적으로 구현하진 않습니다.
// 그러나 'select' 메서드의 존재로 인해 'SelectableControl'의 형태를 갖추고 있습니다.
class TextBox extends Control {
select() {}
}
인터페이스는 심지어 기초 클래스의 private과 protected 멤버도 상속받습니다.
