수색…


소개

인터페이스는 인터페이스를 구현하는 모든 클래스에서 예상 될 수있는 필드 및 함수의 목록을 지정합니다. 반대로 클래스는 인터페이스에 지정된 모든 필드와 함수가 없으면 인터페이스를 구현할 수 없습니다.

인터페이스를 사용하는 주된 이점은 다형성 방식으로 다른 유형의 객체를 사용할 수 있다는 것입니다. 이것은 인터페이스를 구현하는 모든 클래스가 적어도 해당 필드와 함수를 가지고 있기 때문입니다.

통사론

  • interface InterfaceName {
  • parameterName : parameterType;
  • optionalParameterName? : parameterType;
  • }

비고

인터페이스 대 Type Aliases

인터페이스는 객체의 모양을 지정하는 데 좋습니다 (예 : 지정할 수있는 person 객체).

interface person {
    id?: number;
    name: string;
    age: number;
}

그러나 SQL 데이터베이스에 사람이 저장되는 방식을 표현하고 싶다면 어떻게해야할까요? 각 DB 항목이 shape [string, string, number] (문자열 또는 숫자의 배열)으로 이루어져 있기 때문에 행에 속성 이 없으므로이를 객체 모양으로 표시 할 수있는 방법이 없습니다. 따라서, 그것은 단지 배열입니다.

이것은 유형이 유용하게 들어온 경우입니다. 행 매개 변수 function processRow(row: [string, string, number]) 를 허용하는 모든 함수를 지정하는 대신 function processRow(row: [string, string, number]) 대해 별도의 유형 별칭을 만든 다음 모든 함수에서이를 사용할 수 있습니다.

type Row = [string, string, number];
function processRow(row: Row)

공식 인터페이스 문서

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

기존 인터페이스에 기능 또는 속성 추가

우리가 JQuery 타입 정의에 대한 참조를 가지고 있다고 가정 해보자. 여기에 우리가 포함하고 공식 타입 정의가없는 플러그인으로부터 추가 기능을 갖기 위해 확장하려고한다. 우리는 플러그인으로 추가 된 함수를 같은 JQuery 이름으로 별도의 인터페이스 선언에 선언함으로써 쉽게 확장 할 수 있습니다.

interface JQuery {
  pluginFunctionThatDoesNothing(): void;

  // create chainable function
  manipulateDOM(HTMLElement): JQuery;
}

컴파일러는 동일한 이름을 가진 모든 선언을 하나로 병합 합니다. 자세한 내용은 병합 선언 을 참조하십시오.

클래스 인터페이스

public 변수와 메소드를 인터페이스에 선언하여 다른 타이프 코드 코드와 상호 작용할 수있는 방법을 정의하십시오.

interface ISampleClassInterface {
  sampleVariable: string;

  sampleMethod(): void;
  
  optionalVariable?: string;
}

여기에서는 인터페이스를 구현하는 클래스를 생성합니다.

class SampleClass implements ISampleClassInterface {
  public sampleVariable: string;
  private answerToLifeTheUniverseAndEverything: number;

  constructor() {
    this.sampleVariable = 'string value';
    this.answerToLifeTheUniverseAndEverything = 42;
  }

  public sampleMethod(): void {
    // do nothing
  }
  private answer(q: any): number {
    return this.answerToLifeTheUniverseAndEverything;
  }
}

이 예제는 인터페이스를 implements 하는 ISampleClassInterface 인터페이스와 SampleClass 클래스를 생성하는 방법을 보여줍니다.

확장 인터페이스

인터페이스가 있다고 가정 해보십시오.

interface IPerson {
    name: string;
    age: number;

    breath(): void;
}

그리고 우리는 사람의 동일한 속성을 가진 좀 더 구체적인 인터페이스를 만들고 싶습니다. extends 키워드를 사용하여 할 수 있습니다.

interface IManager extends IPerson {
    managerId: number;

    managePeople(people: IPerson[]): void;
}

또한 다중 인터페이스를 확장 할 수 있습니다.

인터페이스를 사용하여 유형 강제

Typescript의 핵심 장점 중 하나는 실수를 방지하기 위해 코드를 전달하는 데이터 형식의 값을 적용한다는 것입니다.

애완 동물 데이트 응용 프로그램을 만들고 있다고 가정 해 봅시다.

두 마리의 애완 동물이 서로 호환되는지 확인하는 간단한 기능이 있습니다 ...

checkCompatible(petOne, petTwo) {
  if (petOne.species === petTwo.species &&
      Math.abs(petOne.age - petTwo.age) <= 5) {
    return true;
  }
}

이것은 완전히 기능적인 코드이지만, 누군가, 특히이 기능을 작성하지 않은이 응용 프로그램에서 작업하는 다른 사람들이 '종'과 '나이'객체를 전달해야한다는 것을 모르고 있다는 것은 너무 쉬울 것입니다. 속성. 그들은 실수로 checkCompatible(petOne.species, petTwo.species) 시도한 다음 함수가 petOne.species.species 또는 petOne.species.age에 액세스하려고 할 때 발생하는 오류를 알아낼 수 있습니다!

이것을 방지 할 수있는 한 가지 방법은 애완 동물 매개 변수에 대해 원하는 속성을 지정하는 것입니다.

checkCompatible(petOne: {species: string, age: number}, petTwo: {species: string, age: number}) {
    //...
} 

이 경우 Typescript는 함수에 전달 된 모든 것이 'species'및 'age'속성을 가졌는지 확인합니다 (추가 속성이 있으면 괜찮습니다).하지만이 속성은 두 개만 지정되어 있어도 다루기 힘든 솔루션입니다. 인터페이스를 사용하면 더 좋은 방법이 있습니다!

먼저 인터페이스를 정의합니다.

interface Pet {
  species: string;
  age: number;
  //We can add more properties if we choose.
}

이제 우리는 새로운 인터페이스로 매개 변수의 유형을 지정해야합니다.

checkCompatible(petOne: Pet, petTwo: Pet) {
  //...
}

... Typescript는 함수에 전달 된 매개 변수가 Pet 인터페이스에 지정된 속성을 포함하는지 확인합니다!

일반 인터페이스

클래스와 마찬가지로 인터페이스도 다형성 매개 변수 (generics라고도 함)를 수신 할 수 있습니다.

인터페이스에서 일반 매개 변수 선언

interface IStatus<U> {
    code: U;
}

interface IEvents<T> {
    list: T[];
    emit(event: T): void;
    getAll(): T[];
}

여기서 우리는 두 개의 인터페이스가 TU라는 일반적인 매개 변수를 사용한다는 것을 알 수 있습니다.

일반 인터페이스 구현

우리는 인터페이스 IEvents 를 구현하기 위해 간단한 클래스를 생성 할 것입니다.

class State<T> implements IEvents<T> {
    
    list: T[];
    
    constructor() {
        this.list = [];
    }
    
    emit(event: T): void {
        this.list.push(event);
    }
    
    getAll(): T[] {
        return this.list;
    }
    
}

State 클래스의 인스턴스를 만들어 보겠습니다.

예제에서 State 클래스는 IStatus<T> 사용하여 일반 상태를 처리합니다. 이러한 방법으로, 인터페이스 IEvent<T> 도 처리 할 IStatus<T> .

const s = new State<IStatus<number>>();

// The 'code' property is expected to be a number, so:
s.emit({ code: 200 }); // works
s.emit({ code: '500' }); // type error 

s.getAll().forEach(event => console.log(event.code));

여기서 State 클래스는 ISatus<number> 로 입력됩니다.


const s2 = new State<IStatus<Code>>();

//We are able to emit code as the type Code
s2.emit({ code: { message: 'OK', status: 200 } });

s2.getAll().map(event => event.code).forEach(event => {
    console.log(event.message);
    console.log(event.status);
});

우리의 State 클래스는 IStatus<Code> 로 입력됩니다. 이 방법으로 우리는 emit 메소드에보다 복잡한 유형을 전달할 수 있습니다.

보시다시피, 제네릭 인터페이스는 정적 형식의 코드에 매우 유용한 도구가 될 수 있습니다.

다형성을위한 인터페이스 사용

인터페이스를 사용하여 다형성을 구현하고 나중에 개발자가 인터페이스의 메소드를 구현하여 고유 한 방식으로 구현할 수있게합니다.

인터페이스와 세 개의 클래스가 있다고 가정 해보십시오.

interface Connector{
    doConnect(): boolean;
}

이것은 커넥터 인터페이스입니다. 이제 우리는 Wifi 통신을 구현할 것입니다.

export class WifiConnector implements Connector{

    public doConnect(): boolean{
        console.log("Connecting via wifi");
        console.log("Get password");
        console.log("Lease an IP for 24 hours");
        console.log("Connected");
        return true
    }

}

여기에서는 자체 구현이있는 WifiConnector 라는 구체적인 클래스를 개발했습니다. 이것은 이제 유형 Connector 입니다.

이제 컴포넌트 Connector 가있는 System 을 만들고 있습니다. 이를 종속성 주입이라고합니다.

export class System {
    constructor(private connector: Connector){ #inject Connector type
        connector.doConnect()
    }
}

constructor(private connector: Connector) 이 줄은 여기에서 매우 중요합니다. Connector 는 인터페이스이며 doConnect() 가 있어야합니다. Connector 는 인터페이스이므로이 클래스 System 은 유연성이 훨씬 뛰어납니다. Connector 인터페이스를 구현 한 모든 유형을 전달할 수 있습니다. 미래의 개발자는 더 많은 유연성을 얻습니다. 예를 들어, 이제 개발자는 Bluetooth 연결 모듈을 추가하려고합니다.

export class BluetoothConnector implements Connector{

    public doConnect(): boolean{
        console.log("Connecting via Bluetooth");
        console.log("Pair with PIN");
        console.log("Connected");
        return true
    }

}

Wi-Fi와 블루투스가 자체 구현되어 있음을 확인하십시오. 연결할 다른 방법이 있습니다. 그러나 두 가지 유형 Connector 가 구현되었으므로 이제 유형 Connector 입니다. 그래서 우리는 그 중 하나를 생성자 매개 변수로 System 클래스에 전달할 수 있습니다. 이것을 다형성이라고합니다. 클래스 System 은 이제 Connector 인터페이스 만 구현하여 Inferade, Bluetooth5와 같은 다른 통신 모듈을 추가 할 수 있다고하더라도 Bluetooth / Wi-Fi인지 여부를 알지 못합니다.

이를 오리 (Duck) 타이핑 이라고합니다. doConnect() 는 단지 자리 표시 자이므로 개발자 유형을 구현합니다. 이제 Connector 유형이 동적입니다.

constructor(private connector: WifiConnector) 에서 WifiConnector 가 구체적인 클래스 인 경우 어떻게됩니까? 그렇다면 System 클래스는 WifiConnector와 단단히 결합 할 것입니다. 여기서 인터페이스는 다형성으로 우리의 문제를 해결했습니다.

암시 적 구현 및 객체 모양

TypeScript는 인터페이스를 지원하지만 컴파일러는 JavaScript를 출력하지 않습니다. 따라서 인터페이스는 컴파일 단계에서 효과적으로 손실됩니다. 이 때문에 인터페이스의 유형 검사는 객체가 인터페이스의 실제 구현 여부에 관계없이 인터페이스의 필드와 함수를 지원하는지 여부에 따라 객체의 모양 에 의존합니다.

interface IKickable {
  kick(distance: number): void;
}
class Ball {
  kick(distance: number): void {
    console.log("Kicked", distance, "meters!");
  }
}
let kickable: IKickable = new Ball();
kickable.kick(40);

그래서 경우에도 Ball 명시 적으로 구현하지 않습니다 IKickable 하는 Ball 인스턴스를 할당 할 수있다 (와 같은 조작)을 IKickable 유형이 지정된 경우에도.



Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow