TypeScript에서는 인터페이스가 제약 조건으로 사용됩니다. JavaScript로 컴파일하면 JavaScript에는 인터페이스 개념이 없기 때문에 모든 인터페이스가 지워집니다.
간단한 예를 살펴보겠습니다.
function printLabel(labelledObj: { label: string }) { console.log(labelledObj.label); } var myObj = { size: 10, label: "Size 10 Object" }; printLabel(myObj);
그러면 이 메소드에서 labelsObj의 유형은 {label: string}입니다. 이는 다소 복잡해 보일 수 있지만 아래 myObj의 선언을 보면 이것이 크기 속성( 값은 10) 및 레이블 속성(값 "크기 10 개체")이 있는 개체입니다. 따라서 labelObj 메소드 매개변수의 유형은 {label: string}입니다. 이는 매개변수에 문자열 유형의 label 속성이 있음을 의미합니다.
그런데 이렇게 작성하면 이 방법이 아직은 좀 헷갈리는 것 같습니다. 그런 다음 인터페이스를 사용하여 이 메소드의 매개변수 유형을 정의할 수 있습니다.
interface LabelledValue { label: string; } function printLabel(labelledObj: LabelledValue) { console.log(labelledObj.label); } var myObj = { size: 10, label: "Size 10 Object" }; printLabel(myObj);
선택 속성
경우에 따라 속성이 존재할 필요가 없으므로 선택적 속성을 사용하여 정의할 수 있습니다.
interface SquareConfig { color?: string; width?: number; } function createSquare(config: SquareConfig): { color: string; area: number } { var newSquare = { color: "white", area: 100 }; if (config.color) { newSquare.color = config.color; } if (config.width) { newSquare.area = config.width * config.width; } return newSquare; } var mySquare = createSquare({ color: "black" });
그런 다음 SquareConfig 인터페이스를 구현하는 객체를 createSquare 메소드에 전달합니다.
완전히 필요 없는 일인데 왜 정의해야 할까요? 선택적 속성을 정의하면 전혀 정의하지 않는 것보다 두 가지 장점이 있습니다. 1. 속성이 있는 경우 유형이 제한될 수 있으며 이는 매우 중요합니다. 2. 지능형 구문 프롬프트를 얻을 수 있습니다. 실수로 메소드 본문에 색상을 작성하면 컴파일이 통과되지 않습니다.
방법 종류
자바스크립트에서는 메소드 함수가 기본형입니다. 객체 지향 사고에서 인터페이스 구현은 클래스에 의해 수행됩니다. 함수가 인터페이스를 구현할 수 있습니까? 대답은 '예'입니다.
TypeScript에서는 인터페이스를 사용하여 메소드 서명을 제한할 수 있습니다.
interface SearchFunc { (source: string, subString: string): boolean; } var mySearch: SearchFunc; mySearch = function(source: string, subString: string) { var result = source.search(subString); if (result == -1) { return false; } else { return true; } }
위 코드에서는 메소드의 시그니처를 제한하는 인터페이스를 정의합니다. 이 메소드에는 두 개의 문자열 매개변수가 있으며 부울 값을 반환합니다. 두 번째 코드에서는 이 인터페이스의 구현을 선언합니다.
컴파일러는 유형이 올바른지(매개변수 유형, 반환값 유형)만 확인하므로 매개변수 이름을 다른 것으로 변경할 수 있다는 점에 유의해야 합니다.
var mySearch: SearchFunc; mySearch = function(src: string, sub: string) { var result = src.search(sub); if (result == -1) { return false; } else { return true; } }
이것은 컴파일하여 전달할 수도 있습니다.
배열 유형
위에서 인터페이스의 메소드 유형을 정의했는데 배열 유형을 어떻게 정의해야 합니까? 매우 간단합니다.
interface StringArray { [index: number]: string; } var myArray: StringArray; myArray = ["Bob", "Fred"];
그러면 myArray는 배열이고 인덱서는 숫자 유형이며 요소는 문자열입니다.
인터페이스 정의에 있어서 인덱서의 이름은 일반적으로 index로 되어 있습니다(물론 다른 이름으로 변경될 수도 있지만 일반적으로 index로 이름을 유지합니다). 그럼
로 바꿔보세요interface StringArray { [myIndex: number]: string; } var myArray: StringArray; myArray = ["Bob", "Fred"];
역시 좋습니다.
인덱서 유형은 숫자 또는 문자열만 가능하다는 점에 유의하세요.
interface Array{ [index: number]: any; } interface Dictionary{ [index: string]: any; }
위의 두 문단을 컴파일하여 전달할 수 있습니다.
마지막으로 주의할 점은 인터페이스가 이미 배열 유형인 경우 인터페이스에 정의된 다른 속성의 유형은 배열의 요소 유형이어야 한다는 것입니다. 예:
interface Dictionary { [index: string]: string; length: number; // error, the type of 'length' is not a subtype of the indexer }
그러면 컴파일되지 않으며, 길이를 문자열 형식으로 변경해야 합니다.
클래스를 사용하여 인터페이스 구현
일반적인 상황에서 우리는 여전히 위와 같이 인터페이스를 직접 사용하기보다는 클래스를 사용하여 필요한 인터페이스를 구현하는 데 익숙합니다.
interface ClockInterface { currentTime: Date; } class Clock implements ClockInterface { currentTime: Date; constructor(h: number, m: number) { } }
TypeScript에서는 EcmaScript 6과 동일하게 class 키워드를 사용하여 선언합니다.
또한 인터페이스를 사용하여 클래스에 정의된 메서드를 제한할 수 있습니다.
interface ClockInterface { currentTime: Date; setTime(d: Date); } class Clock implements ClockInterface { currentTime: Date; setTime(d: Date) { this.currentTime = d; } constructor(h: number, m: number) { } }
TypeScript에서는 인터페이스 생성자를 정의할 수 있습니다.
interface ClockInterface { new (hour: number, minute: number); }
순진하다면 다음과 같이 쓸 수도 있습니다.
interface ClockInterface { new (hour: number, minute: number); } class Clock implements ClockInterface { currentTime: Date; constructor(h: number, m: number) { } }
이렇게 하면 안 돼요! ! ! 생성자는 정적이므로 클래스는 인터페이스의 인스턴스 부분만 구현할 수 있습니다.
그럼 이 인터페이스에 정의된 생성자는 아무런 효과가 없나요? TypeScript가 이 기능을 제공하므로 확실히 쓸모가 없습니다. 선언된 메소드는 다소 특별합니다:
interface ClockStatic { new (hour: number, minute: number); } class Clock { currentTime: Date; constructor(h: number, m: number) { } } var cs: ClockStatic = Clock; var newClock = new cs(7, 30);
일반적으로 우리는 새로운 Clock을 작성하는데 여기서는 Clock 클래스를 ClockStatic 인터페이스로 지정합니다. newClock 변수의 유형은 any라는 점에 유의해야 합니다.
상속된 인터페이스
클래스와 마찬가지로 인터페이스도 확장 키워드를 사용하여 상속을 구현할 수 있습니다.
interface Shape { color: string; } interface Square extends Shape { sideLength: number; } var square = <Square>{}; square.color = "blue"; square.sideLength = 10;
물론 여러 인터페이스를 상속할 수도 있습니다.
interface Shape { color: string; } interface PenStroke { penWidth: number; } interface Square extends Shape, PenStroke { sideLength: number; } var square = <Square>{}; square.color = "blue"; square.sideLength = 10; square.penWidth = 5.0;
여러 인터페이스 상속을 지원하더라도 상속된 인터페이스에 정의된 동일한 이름의 속성 유형이 다른 경우 컴파일이 통과되지 않는다는 점에 유의해야 합니다.
interface Shape { color: string; test: number; } interface PenStroke { penWidth: number; test: string; } interface Square extends Shape, PenStroke { sideLength: number; }
那么这段代码就无法编译通过了,因为 test 属性的类型无法确定。
同时使用上面所述的类型
如果仅能单一使用某种类型,那么这接口也未免太弱了。但幸运的是,我们的接口很强大。
interface Counter { (start: number): string; interval: number; reset(): void; } var c: Counter; c(10); c.reset(); c.interval = 5.0;
这样就使用到三种类型了,分别是方法(接口自己是个方法)、属性、方法(定义了方法成员)。
以上所述就是本文的全部内容了,希望大家能够喜欢。