TypeScript - Interfaces를 공부한 내용입니다.
Our First Interface
interface 작동 방식을 보자. 일단 아래의 예제는 printLabel 함수가 하나의 argument를 받는데, 그 인자 타입은 객체이며, label라는 프로퍼티는 string 형이여야 한다.
function printLabel(labeledObj: { label: string }) {
console.log(labeledObj.label);
}
let myObj = {size: 10, label: "Size 10 Object"};
printLabel(myObj);
아래도 같은 코드인데 이번엔 interface로 type을 checking하는 방식이다. 위도 아래도 labeledObj에 프로퍼티가 더 있지만, type 선언한 것만 체크하고 만다. 아무래도 아래 코드가 더 깔끔하고 interface를 재사용할 수도 있으니 interface를 사용하는 것이 좋겠다.
interface LabeledValue {
label: string;
}
function printLabel(labeledObj: LabeledValue) {
console.log(labeledObj.label);
}
let myObj = {size: 10, label: "Size 10 Object"};
printLabel(myObj);
Optional Properties
type checking을 하고 싶긴 한데, 프로퍼티가 있을 수도 있고, 없을 수도 있는 optional한 경우에는 ? 를 붙여주면 된다. 아래의 경우 인자 config에는, color, width라는 프로퍼티가 있을 수도, 없을 수도 있다.
interface SquareConfig {
color?: string;
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;
}
let mySquare = createSquare({color: "black"});
Readonly properties
최초에 객체 literal로 값을 할당하고, 프로퍼티를 수정하고 싶지 않다면 readonly 를 붙여주자. react props에 써도 될까? 아직 모르겠다. 일단 유지보수 하고 있는 소스코드에서는 readonly 사용한 것을 본적이 없다. 조만간 알게 되겠지 ㅎㅎ
interface Point {
readonly x: number;
readonly y: number;
}
let p1: Point = { x: 10, y: 20 };
p1.x = 5; // error!
배열을 수정하고 싶지 않을 때는 ReadonlyArray를 사용하면 된다.
let a: number[] = [1, 2, 3, 4];
let ro: ReadonlyArray<number> = a;
ro[0] = 12; // error!
ro.push(5); // error!
ro.length = 100; // error!
a = ro; // error!
ReadonlyArray 로 생성한 배열을 다시 배열에 할당하는 것도 안되는데, type assertion 으로 아래와 같이 할당하면 된다.
a = ro as number[];
어제 공부한 type assertion인데, 어색해서 그런지 뭐더라? 했다. 다시 내용을 가져왔다.
type assertion이란, any type으로 선언된 변수이긴 한데, 사용할 시점에 확실히 타입을 알았을 때 사용하는 것이다. 아래는 as 방식을 사용했다.
let someValue: any = "this is a string";
let strLength: number = (someValue as string).length;
readonly vs const
const도 변하면 안 되는 값을 선언할 때 사용하는데 언제 뭐를 써야 할까? 간단하다. 변수는 const를 사용하면 되고, property는 readonly를 사용하면 된다.
Excess Property Checks
말그대로 초과 프로퍼티 체크이다. 넣으면 안 될 프로퍼티를 넣었을 때 에러가 난다. 그런데 아래 코드에서 에러가 나는 것을 보고 1분 당황했다. 분명히 interface 첫 예제에서는 type을 선언한 프로퍼티만 검사했기 때문에, 다른 프로퍼티가 있어도 에러가 없었다.
interface SquareConfig {
color?: string;
width?: number;
}
function createSquare(config: SquareConfig): { color: string; area: number } {
// ...
}
let mySquare = createSquare({ colour: "red", width: 100 });
알고보니 객체 리터럴을 직접 전달해줄때만 Excess Property Checks 체크를 한다. 이해할 수 없는 동작원리지만, 컴파일할 때 체크하므로 그러려니 해본다.
Function Types
이해필요, wip..
Indexable Types
공부 더 필요…
Class Types
interface는 C#이나 Java에서 class를 정의할 때 자주 쓰는데, TypeScript에서도 비슷하게 가능하다.
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) { }
}
이 아래부터 다시 공부 필요 wip
한번에 이해가 안되네..
Extending Interfaces
class 상속하듯이 interface도 상속할 수 있다.
interface Shape {
color: string;
}
interface Square extends Shape {
sideLength: number;
}
let square = <Square>{};
square.color = "blue";
square.sideLength = 10;
여러개 상속도 가능하다.
interface Shape {
color: string;
}
interface PenStroke {
penWidth: number;
}
interface Square extends Shape, PenStroke {
sideLength: number;
}
let square = <Square>{};
square.color = "blue";
square.sideLength = 10;
square.penWidth = 5.0;
Hybrid Types
여기도 다시다시..