TypeScript의 "클래스"데이터 유형 및 객체 지향 프로그래밍 패러다임 소개

이 강의에서는 TypeScript의 클래스, 인터페이스 및 기본 개념 객체 지향 프로그래밍 패러다임에 대해 알아 봅니다.

(출처 : unsplash.com)

JavaScript는 프로토 타입 상속을 사용하여 객체 지향 패러다임을 지원합니다 . Java와 같은 프로그래밍 언어에서는 한 클래스가 다른 클래스의 속성과 메서드를 상속하는 고전적인 상속에 익숙합니다. 슬프게도 JavaScript가 작동하는 방식이 아닙니다.

ES5까지는 생성자 함수에서 생성 된 객체가 이러한 메서드를 상속 할 수 있도록 User.prototype.<method>표현식 을 사용 method하여 User생성자 함수의 프로토 타입 에을 추가해야했습니다 .

💡 프로토 타입 상속에 대한 이야기는 꽤 크고 그것에 대해 배우고 싶다면 이 주제에 대해이 기사를 썼습니다 .

ES6 사양은 class클래스를 정의하는 extends키워드 와 다른 클래스에서 메서드를 상속 하는 키워드를 제시했습니다. JavaScript는 거의 프로토 타입 상속을 기반으로하지만 개발자가 생산성에 집중할 수있는 시간을 더 많이 제공하며,이를 통해 JavaScript의 OOP는 고전적인 상속 패러다임을 작업하는 사람들에게 낯설지 않습니다.

TypeScript는 ES6 사양에 설명 된 것과 똑같은 클래식 상속 구문을 따르며, 클래스에서 생성 된 인스턴스 ( objects ) 의 동작을 제어하는 ​​구문에 더 많은 기능을 추가합니다 .

(class.ts)

위의 예에서, 우리는 만든 Person이 클래스 firstNamelastName타입의 필드 stringage유형의 필드 number. 이러한 선언은 TypeScript 컴파일러가 Person클래스 에서 생성 될 인스턴스의 모양을 이해하는 데 필요합니다 .

💡 필드특성 단어는 개체 (예)에서 클래스의 필드 또는 속성 이름을 표시하는 의미로 사용 할 수 있습니다. 그러나 본 문서에서는, 필드는 같은 클래스의 엔티티 firstName속성 또는 getFullName잠시 방법 재산권 엄격하다 key내측 object인 (또는 인스턴스) firstName에서 ross객체 (예). 클래스 속성 이라고 하면 .NET과 같은 인스턴스의 속성 인 클래스 필드를 의미합니다 firstName.

constructor메서드는 클래스의 인스턴스를 만드는 데 필요합니다. new키워드가 사용 되면 주로 객체의 속성 값을 초기화하는 데 사용되는이 생성자가 호출됩니다. 인스턴스의 속성을 초기화하지 않으려면 클래스에 생성자가 없을 수 있습니다.

getFullName방법은 프로토 타입에 살고 있지만, 따라서 우리는 다음과 같이 호출 할 수 있습니다, 인스턴스 객체에서 액세스 할 수 있습니다 ross.getFullName(). this받는 클래스 포인트의 방법 내부 객체 인스턴스 가에 호출 된 객체입니다. 따라서 this내부 getFullName()ross.

기본 속성 값

TypeScript 클래스의 클래스 속성은 기본값을 가질 수 있습니다 . 속성 선언 구문에서 생성자 함수가 호출되기 전에 원하는 속성에 초기 값을 할당 할 수 있습니다. 따라서 생성자 함수 내부에서 속성에 기본값을 할당하는 논리가 필요하지 않습니다.

(기본 속성 값 .ts)

위의 프로그램에서 agetype속성에는 기본값이 있습니다. 따라서 TypeScriirpt가 기본 ( 초기 ) 값 에서 추론 할 것이기 때문에 속성에 대해했던 것처럼 유형 주석 을 제공 할 필요가 없습니다 .type

또한 age생성자 함수 의 인수를 옵션으로 만들었습니다. age속성이 제공되지 않은 경우 속성에 대한 기본값이 있기 때문입니다.

💡 클래스에 속성이 없거나 모든 속성에 기본값이있는 경우 클래스에서 생성자 함수 를 완전히 제거 할 수 있습니다 .

계승

고전적인 상속 구문은 상속을 훨씬 간단하게 만듭니다. ES5에서 우리는 아래와 같이 슈퍼 클래스 의 프로토 타입을 가리키는 서브 클래스에 대한 프로토 타입 객체를 만드는 데 사용해야 했습니다 .Object.create()

function B(){ ... } // superclass
function A(){ ... } // subclass
A.prototype = Object.create( B.prototype);

💡 JavaScript에서는 한 번에 두 개 이상의 클래스를 상속 할 수 없습니다.

인스턴스를 만드는 동안 모든 클래스 super()의 생성자를 호출 A해야하므로의 생성자에 제공해야하는 모든 인수와 함께 의 생성자 내부에서 호출을 사용 합니다 B. 이 호출은 B일부 추가 속성에 대한 값을 초기화 할 수 있는 생성자를 호출합니다 .

(inheritance.ts)

위의 예에서 Student클래스는 클래스를 확장 Person하므로의 인스턴스 StudentgetNameParts메서드에 액세스 할 수 있습니다. 이후 name속성은 생성자에 의해 추가됩니다 Person생성되는 인스턴스에, 우리는 호출 할 필요가 super()필요한 모든 인수.

super()수퍼 클래스에 뭔가를 덤프하는 생성자를 가지고 있지 않는 전화 절대적으로 필요하지 않습니다 this. super()호출은 서브 클래스의 생성자의 첫 번째 행하여야한다.

💡 하위 클래스에 생성자가 필요하지 않은 경우을 호출하기 위해 생성 할 필요가 없습니다 super(). 하위 클래스에 생성자가 없으면 JavaScript는 호출에 super()전달 된 모든 인수를 사용하여 암시 적으로 new Student()호출합니다.

메서드 재정의

위에서 본 상속 패턴에서 하위 클래스가 수퍼 클래스의 메서드를 상속하면 하위 클래스가 부모 클래스와 동일한 메서드를 가질 때 어떤 일이 발생 합니까 ( 이름이 동일 함을 의미 )?

이 경우 인스턴스에 더 가깝기 때문에 하위 클래스 메서드가 호출됩니다 . 이를 메서드 재정의 라고 합니다. 그러나 부모 클래스의 메서드는 파괴되지 않습니다. 여전히 프로토 타입 체인 에 있으며 하위 클래스의 모든 메서드는 super키워드를 사용하여 액세스 할 수 있습니다 .

(inheritance-method-overriding.ts)

위의 예에서 getNameParts메서드는 두 클래스에 모두 존재합니다. 그러나 ross.getNameParts()전화는 방법을 실행 Student하기 때문에 클래스 ross의 인스턴스이며 Student,이 방법은에 가까운 Student의 방법보다 더 클래스 Person클래스입니다.

그러나 super키워드는 슈퍼 클래스를 가리키고 슈퍼 클래스의 메서드 참조를 포함 합니다 (constructor 제외 ). 위의 예에서는 super.getNameParts()getNameParts메서드 에서 호출을 수행 Student하고 변환 된 응답을 반환했습니다.

💡 재정의 메서드는 정확히 동일한 형식 서명을 가져야합니다. 그렇지 않으면 TypeScript 컴파일러가 메서드 재정의를 허용하지 않습니다. OOP 의 메서드 오버로딩 개념에 익숙 할 수 있지만 JavaScript 또는 TypeScript에는 존재하지 않습니다. 그러나 TypeScript 에는 함수 오버로딩 개념이 있습니다 .

액세스 수정 자

JavaScript는 범용 프로그래밍 언어로 사용하도록 설계되지 않았습니다. 주요 업무는 AJAX 및 DOM 조작과 같은 웹 애플리케이션에 동적 동작을 제공하는 것이 었습니다. 따라서 객체 지향적이지 않으며 데이터 캡슐화를 거의 또는 전혀 제공하지 않습니다.

예를 들어, 사용할 수있는 public, privateprotected액세스 한정자는 같은 언어의 클래스의 필드의 액세스 제어하기 위해 자바C ++를 하지만, 확실히 자바 스크립트에 존재하지 않습니다. 개체의 모든 속성은 기본적으로 공개되며 누구나 액세스, 수정 또는 삭제할 수 있습니다.

💡 새로 도입 된 비공개 필드 구문을 제외하고 (아래에서 설명).

그러나 TypeScript는 이러한 액세스 수정자를 지원합니다. 이는 JavaScript의 작동 방식을 변경하지 않지만 컴파일 중에 속성 및 메서드에 대한 액세스 제한을 추가합니다. 따라서 클래스의 필드에 대한 액세스에 문제가있는 경우 코드를 컴파일 할 수 없습니다.

공공 분야

지금까지 public, private또는 레이블이 지정되지 않은 필드가있는 클래스를 만들었습니다 protected. 이 경우 TypeScript 컴파일러는 클래스의 모든 필드와 메서드가 public암시 적으로 있다고 가정합니다 .

private액세스 한정자는 해당 클래스의 필드 나 메소드 개인을합니다. 따라서 private속성은 생성자를 포함하여 해당 클래스의 메서드에서만 액세스 할 수 있습니다. 마찬가지로 private 메서드는 생성자를 포함하여 해당 클래스의 다른 메서드에서만 실행할 수 있습니다.

(액세스 수정 자 -private.ts)

위의 예제 에서 클래스의 메서드와 name속성 getAgeprivate이므로 클래스 외부에서 액세스 할 수 없지만 클래스 내에서 액세스 할 수 있습니다. getNameParts방법은 액세스 할 수있는 name이 클래스의 일부이며 그것은 또한 액세스 할 수 있기 때문에 속성을 getAge.

보호 필드

protected수정은에 비해 적은 수의 제한이 적용 private수정합니다. protected필드 나 메소드는 클래스 외부에서 액세스 할 수 없습니다하지만 클래스 내부에 그 상속이 액세스 할 수 있습니다.

(access-modifier-protected.ts)

위의 예에서 dobfield is privategetAgefield is protected따라서 클래스 외부에서 액세스 할 수 없습니다 Person. 그러나 이후 Student클래스가 확장 Person, getAge방법은 내부에 액세스 할 수 있습니다.

매개 변수 속성

지금까지 만든 클래스의 생성자 함수 구문을주의 깊게 살펴보면 속성을 초기화하는 상용구가 불필요 해 보입니다. 먼저 유형을 사용하여 클래스의 필드를 정의해야합니다. 그런 다음 생성자 함수의 매개 변수를 유형과 함께 언급 한 다음 해당 값을 초기화 할 수 있습니다. 별로 생산적이지 않습니다.

다행히도 우리의 구성 함수 매개 변수와 속성 이름은 동일했습니다. 이러한 경우 TypeScript는 생성자 함수 매개 변수를 정의하고 필드 값을 한 번에 할당 할 수있는 간단한 구문을 제공합니다.

(parameter-properties.ts)

위의 예에서 Person클래스 생성자는 액세스 수정자가있는 매개 변수를 포함합니다. TypeScript 컴파일러는이 서명을 인식 하고 지정된 액세스 수정자를 사용하여 암시 적으로 정의 nameage수정자를 정의 하고 생성자 호출에서 제공된 값을 할당합니다.

이 동작은 protectedreadonly수정자를 포함하는 액세스 수정 자 선언이있는 매개 변수에만 유효합니다 . 생성자 함수 본문에서 우리가 할에 액세스 할 수 있습니다 this.namethis.age하지만 생성자 본체 (바로 실행되기 전에 그 값이 이미 설정됩니다 기본값 속성을 가지고있는 것처럼 ).

💡readonly속성은 데이터 불변성 강의 (곧 제공 예정) 에서 논의됩니다 .

age속성이 비공개이기 때문에 출력에 왜 속성이 표시 되는지 궁금하다면 몇 초 전에 논의한 내용을 다시 한 번 상기시켜 드리겠습니다. TypeScript는 JavaScript의 작동 방식을 변경하지 않으며 코드 컴파일 중에 만 규칙을 적용 할 수 있으므로 ross.ageTypeScript 프로그램에서는 액세스 할 수 없지만 런타임에는 항상 액세스 할 수 있습니다.

💡 선택적 매개 변수 속성을 가질 수도 있습니다. 매개 변수 속성이 선택 사항이고 해당 속성의 값이 생성자 호출에 제공되지 않은 경우 해당 속성은 개체에 대해 정의되지만 값은입니다 undefined. 생성자 호출에서 속성 값이 제공되지 않은 경우 기본 매개 변수 값 구문을 사용하여 기본값을 지정할 수 있습니다.

게터와 세터

때때로 개체에는 값이 특정 형식을 가져야하는 속성이 있습니다. 예를 들어 dob( 생년월일 ) 속성 값을 표준 JavaScript Date형식으로 저장하고 싶지만 사용자가 액세스 할 때 형식을 가져와야 mm-dd-yyy합니다.

마찬가지로 사용자가 mm-dd-yyyy값 을 설정할 수 있어야 하지만 내부적으로는이 값이 Date객체 로 변환되어야 합니다. 이것은 까다로워 보이지만 JavaScript는 및 접근 자 설정을 사용하여 이러한 속성의 동작을 사용자 정의하는 방법을 제공합니다 .Object.definePropertygetset

클래스에는이 기능이 내장되어 있습니다. get클래스 메서드 앞에 키워드를 넣으면 해당 메서드는 클래스 속성처럼 동작합니다. 속성처럼 접근 할 때마다 실행되고 값을 반환합니다. 일반적 private으로이 함수에 액세스하면 속성 값 을 반환합니다 .

마찬가지로 set키워드를 사용하면 클래스 속성으로 작동하는 메서드를 정의 할 수 있지만 값을 설정하려고 할 때 인수로만 실행됩니다. 우리가 할당하는 값이 인수 값이됩니다. 일반적 private으로이 함수가 실행될 때 일부 속성 값 을 업데이트 합니다.

이러한 메서드를 통칭하여 접근 자라고 합니다. 이러한 접근자는 비밀로 저장할 수있는 값을 검색하고 업데이트하기 위해 조화롭게 작동합니다.

(property-accessors.ts)

위의 예 _dob에서 Person클래스 필드는 개인이므로 개인의 생년월일을 저장하는 안전한 저장소 역할을합니다. 유형은 DateTyepScript 설치의 표준 라이브러리에있는 유형 정의 파일에서 제공하는 인터페이스 유형입니다 ( 컴파일 강의에서 논의 됨-곧 제공 될 예정 임).

Person클래스 생성자 는 두 개의 인수를받습니다. name번째 인수 값이 저장된 상태 인자는 공용 필드 _dob유효로 변환 한 후에 속성 Date오브젝트.

dobmm-dd-yyyy형식 을 반환 하는 속성 getter 메서드가 _dob있습니다. dob속성 의 동등한 setter 메서드 는 들어오는 mm-dd-yyyy값을 속성의 Date개체 로 저장하고 _dob아무것도 반환하지 않으므로 반환 유형 주석이 없습니다.

expression dobross사용 ross.dob하는 속성에 접근 하면 dobgetter 메서드가 실행되고 메서드 실행의 반환 값이 반환됩니다. 마찬가지로 표현식을 dob사용하여 필드에 값을 설정 ross.dob = value하면 dobsetter 메서드가 호출되어 _dob.

해당하는 setter 메서드가 없어도 속성에 대한 getter 메서드를 사용할 수 있습니다. TypeScript 컴파일러는 이러한 속성을 고려 readonly하며 setter가 없기 때문에 값을 쓸 수 없습니다.

인스턴스 방법

thisJavaScript 의 개체는 컨텍스트를 인식합니다. 즉, 코드가 어떻게 보이는지 중요하지 않으며 this함수 또는 메서드의 객체는 함수를 호출하는 방법에 따라 다릅니다. 예를 살펴 보겠습니다.

(instance-method.ts)

위의 예제에서 우리는 public 속성 과이 값을 반환 하는 메서드를 가진 간단한 간단한 Person클래스를 가지고 있습니다. 메서드 내부 의 개체 는 호출 된 인스턴스를 가리 키므로 호출 은 개체 의 속성 값을 반환 합니다. 평상시처럼 JavaScript, 여기에는 특별한 것이 없습니다.namegetNamethisgetNameross.getName()nameross

나중에 코드에서 ross.getName함수를 getNameFn변수에 저장 합니다. 이후 ross.getName값의 타입 function이 기능만을 참조에 저장된 getNameFn복사되지. 따라서 우리가 실행할 때 우리 getNameFn()는 기술적으로 실행 ross.getName()합니다.

그러나를 호출 getNameFn()하면 undefined. 이제 육안으로 볼 때 메서드 내부의 값 은 객체 여야 하고 명확하게는 아니기 때문에 this.name반환 undefined은 의미 가 없습니다 . 그래서 무슨 일이 일어나고 있습니까?thisgetNamerossross.nameundefined

this함수 내부 의 값은 코드에서의 위치에 의존하지 않습니다. 함수가 어떻게 호출되는지에 따라 다릅니다. where is an owner 와 같은 소유자 에서 함수가 호출 되면 함수 본문 내의 값은 입니다. 이 기사 에서 자세히 알아볼 수 있습니다 .obj.method()objthisobjthis

💡 화살표 함수의 경우 this값은 함수 의 상위 범위에서 차용됩니다. 따라서 함수가 어떻게 호출되는지는 중요하지 않습니다 this. 함수의 this값은 둘러싸는 어휘 범위 의 값 이므로 함수의 위치에 따라 다릅니다 .

소유자없이 함수를 호출하면 this값이 전역 개체가됩니다. 브라우저에서 전역 개체는 window입니다. 이 상황에서 Node에서 프로그램을 실행하고 있으므로의 this값은 getNameFn()입니다 global. 객체 nameglobalor name속성에 변수 가 없기 때문에 .globalundefined

💡 에서 엄격 모드 함수 호출은 소유자가없는 경우, 기본 this값이 될 것입니다 undefined. 따라서 undefined.name표현식이 undefined객체가 아닌 것처럼 작동하지 않기 때문에 위 프로그램은 엄격 모드에서 작동 하지 않습니다.

이 문제를 해결하기 위해 우리가 할 수있는 것은 getName메서드 this가 호출되는 방식에도 불구하고 고정 된 값 을 갖도록 하는 것입니다. 이것은 bind함수에서 제공하는 방법을 사용하여 수행 할 수 있습니다 . 이 메서드는 this컨텍스트를 받아들이고 일관된 메서드의 복사본을 반환합니다 this.

(instance-method-bind.ts)

React 개발자라면이 구문을 잘 이해하고 있습니다. 위의 프로그램에서 생성자 함수 내 getName에서 인스턴스 자체에 속성을 생성 합니다. 이제,의 인스턴스는 Person해야합니다 getName속성을.

이 속성의 값은 인스턴스 자체에 바인딩 된 getName프로토 타입 의 메서드 복사 본인 함수입니다 this. 이것은 소화하기 어려울 수 있지만 점들을 연결하기 만하면됩니다.

이제 ross.getName()메서드 를 호출 할 때 getName프로토 타입 에서 메서드를 호출하는 대신 ross.getName속성에 저장된 함수를 실행합니다 . 이것은 ross.getName속성 함수에 this컨텍스트가 바인딩되어 있기 때문에 작동 ross합니다.

(instance-method-arrow.ts)

위의 예에서는 기본 속성 표현식을 사용하여 getName속성 을 만들고 를 반환하는 함수를 할당했습니다 this.name. 여기에서 우리는 필요한 화살표 기능을 사용했습니다.

이 서명은 TypeScript 컴파일러에 의해 인식되며 getName의 인스턴스에 속성 을 추가하는 JavaScript 코드를 출력합니다 Person. 여기서 화살표 함수는 서명에만 사용되지만 실제 출력에서는 화살표 함수가 삭제되고 this함수 내부에서 일관된 객체가 참조됩니다.

정적 속성 및 방법

지금까지 해당 클래스의 인스턴스에서 액세스 할 수있는 클래스 속성 및 메서드를 만드는 방법을 살펴 보았습니다. 인스턴스에서 메서드를 호출하면 this해당 메서드 내의 개체가 인스턴스 자체를 가리 킵니다. 따라서 이러한 메서드 내에서 인스턴스의 속성 ( 및 기타 메서드 )에 쉽게 액세스 할 수 있습니다 .

때로는 클래스 수준 속성 및 메서드가 필요합니다. 이러한 속성과 메서드는 인스턴스가 아닌 클래스 자체에서 액세스 할 수 있습니다.

💡 원시 데이터를 제외한 모든 유형의 그러한로서 자바 스크립트 객체이다 function하거나 array또는 class. 따라서 이러한 유형에도 속성과 메서드를 추가 할 수 있습니다.

(static-properties.ts)

위의 예에서, 우리는 staticstatic 클래스의 속성과 인스턴스를 표시하기 위해 키워드를 사용했습니다 . 이것은 이제 그것들이 클래스에 속함을 의미합니다. 정적 속성은 Person.type위의 예 와 같은 클래스 또는 static메서드 내 에서만 액세스 할 수 있습니다 .

마찬가지로 정적 메서드는 함수 호출을 static사용하여 클래스 또는 다른 메서드 내부에서만 액세스 할 수 있습니다 this.describe(). this정적 메서드가와 같은 클래스 변수에서 호출되므로 정적 메서드 내부 의 개체는 클래스를 가리 킵니다 Person.describe(). 따라서이 Person함수 호출에서 메서드의 소유자입니다.

인터페이스 구현

인터페이스는 개체의 모양을 설명합니다. 우리는 인터페이스 강의 에서 인터페이스에 대해 많은 것을 배웠습니다 . 클래스의 인스턴스도 객체입니다. 따라서 클래스는 일관된 인스턴스 모양을 생성하기 위해 인터페이스에 의해 정의 된 계약을 구현해야 할 수 있습니다.

implements인터페이스를 구현하기 위해 클래스와 함께 키워드를 사용 합니다. 인터페이스는 인스턴스에 있어야하는 공용 속성 및 메서드를 정의합니다. 따라서 인터페이스를 구현하는 클래스에는 인터페이스에서 정의한 모양을 생성하는 논리가 있어야합니다.

(interface.ts 구현)

위의 예 에서는 , 및 속성 PersonInterface을 정의하는 a 를 정의했습니다 . 이다 특성 값을 의미 만 읽고 쓸 수는 없습니다. 인터페이스에 정의 된 방법은 리턴 값.firstNamelastNamedobnamenamereadonlygetBirthYearnumber

클래스가 인터페이스를 구현할 때 TypeScript 해당 클래스가 인터페이스에 정의 된 모든 속성과 모든 메서드를 구현하도록합니다. 그렇게하지 않으면 프로그램이 컴파일되지 않습니다.

인터페이스의 역할은 대중이 볼 수있는 객체의 모양을 제공하는 것입니다. 인스턴스에 나타나지 않기 때문에 클래스를 구현 private하거나 protected필드 또는 이벤트 필드 를 적용 할 수 없습니다 static.

추상 클래스

때로는 다른 클래스의 기능을 확장하는 일반 클래스가 있습니다. 예를 들어, Person클래스는 같은 클래스에 몇 가지 일반적인 필드와 방법을 제공 할 수 있습니다 Student, Player그리고 Racer하지만 당신은 누군가의 인스턴스를 생성하고 싶지 않아요 Person사용하여 new Person().

바로이 Person클래스를 추상 클래스 라고합니다 . extends키워드를 사용하여 추상 클래스를 상속 할 수 있지만 키워드를 사용하여 인스턴스를 만들 수는 없습니다 new. 추상 클래스는 상속 될뿐입니다.

(abstract-class.ts)

위의 예 에서는이 클래스를 추상으로 만드는 키워드 로 클래스 Person를 만들었습니다 abstract. 이 클래스의 인스턴스를 만들려고하면 TypeScript 컴파일러에서 오류가 발생합니다.

그러나 클래스는 일반적인 방식으로 Student클래스를 확장합니다 Person. 따라서 Person클래스의 속성과 메서드는 monica평소와 같이 개체에서 액세스 할 수 있습니다 .

클래스의 정적 대 인스턴스 측

지금까지 클래스의 인스턴스가 해당 클래스의 유형을 가지고 있음을 확인했습니다. 예를 들어, 위의 예에서 since monica는 using 키워드 Student에서 생성 된 since 의 인스턴스입니다 .Studentnew

그러나 클래스에서 정의한 공용 속성 및 메서드monica 만 가질 수 있습니다 . 어디 않았다 기능은 이동? 정적 속성과 메서드는 어떻습니까?Studentconstructor

TypeScript는 클래스를 값과 유형으로 취급합니다. TypeScript에 의해 선언 된이 암시 적 유형은 클래스가 생성하는 인스턴스의 모양을 설명합니다. 따라서 let value :Class주석 을 사용하는 것과 같이 클래스가 유형으로 사용되는 경우 TypeScript value는에 모든 공용 속성이 있는지 확인 합니다 Class.

💡 이 때문에 클래스에 의해 구현 된 인터페이스는 클래스의 공용 속성 만 확인할 수 있으며 생성자 함수 또는 해당 클래스의 정적 멤버에 규칙을 적용 할 수 없습니다.

간단히 말해서, 클래스 유형은 클래스의 공용 속성 선언을 포함하는 인터페이스에 불과합니다. 클래스의 인스턴스를 만들거나 클래스 유형으로 값에 주석을 달 때이 유형은 해당 인스턴스가 가질 수있는 정보 만 포함하므로 클래스의 인스턴스 측 유형 이라고 합니다 .

그러나 인터페이스 강의 에서 인터페이스가 생성자 함수를 설명 할 수도 있다는 것을 배웠습니다 . 생성자 함수를 설명하는 인터페이스 는 클래스 의 정적 측 유형을 설명합니다 . 이 인터페이스는 생성자 함수 유형 및 정적 멤버 유형을 선언 할 수 있습니다.

슬프게도 정적 측면을 구현하기 위해 클래스를 강제 할 수는 없습니다. 그러나 이것은 클래스를 인수로 받아들이고 해당 클래스의 인스턴스를 반환하는 팩토리 함수 를 만드는 데 매우 유용합니다 . 이 인수는 생성자 ( 및 / 또는 정적 멤버 )를 사용하여 인스턴스를 생성 하므로 클래스의 정적 측면 유형을 가져야 합니다.

(공장 기능 .ts)

위의 예에서는 PersonInterface두 개의 string인수 를 받아야하는 생성자 함수를 정의합니다 . 또한 delimeter이 생성자 함수 ( class ) 및 splitName메서드 에 있어야하는 속성을 설명 합니다 .

이 인터페이스는 기술적으로 사용하여 호출 될 수있는 값에 대해 설명 new하고는 보유 delimeter하고 splitName속성. Person이것에 대한 클래스 자격을 우리는 그것을 사용하여 호출 할 수 있기 때문에 new동일한 인수 유형과 키워드 우리는 접근도 할 수 Person.delimeterPerson.splitName어떤 인터페이스에 의해 정확히 같은 서명 정의가 있습니다. 그래서 간단히 말해서, PersonInterfaceA는 정적 측면 유형Animal클래스.

createPerson함수는의 ctor인수를 허용 PersonInterface하므로 Person클래스에 인수를 전달할 수 있습니다 . 기억의 Person클래스 유형이없는 Person, 그 인스턴스가 있습니다. 실제 Person클래스 유형 ( value )은 클래스의 정적 멤버 PersonInterface가있는에 의해 설명되는 클래스의 정적 측면을 설명합니다 constructor.

당신의 기능 구현에서 볼 수 있듯이 createPersonctor값을 사용하여 호출 할 수 있습니다 new그리고 우리는 정적 멤버에 접근 아무런 문제가 없다. 이 함수의 반환 유형은 클래스 Person의 인스턴스가 호출을 Person사용하여 생성 된이 유형을 new Person갖기 때문입니다.

💡 클래스에 정적 멤버가 없거나 팩토리 함수 내에서 신경 쓰지 않는 new (firstName: string, lastName: string) => Person경우 ctor인수에 대한 유형으로 간단히 사용할 수 있습니다 . 자세한 내용 은 인터페이스 강의 에서 인터페이스를 사용하는 함수 유형 섹션을 읽어 보세요.

간단한 질문 typeof (new Person)이 있습니다 Person. 그렇다면 무엇 typeof Person입니까? 앞에서 설명한 것처럼 클래스 유형은 클래스의 정적 인 측면입니다. 따라서 클래스 여야하는 값의 유형에 주석을 달기 위해 멋진 인터페이스를 설명 할 필요가 없습니다. typeof <Class>대신 사용할 수 있습니다 .

(공장 기능 유형의 클래스 .ts)

간단히 말해서 다음과 같이 말할 수 있습니다.

  • :typeof Person→ 반환 정적 측면 의 유형 Person클래스를 그리고 그것은 포함 constructor클래스와 모든 정적 멤버를 .
  • :typeof (new Person) 또는 그냥 → 클래스 의 인스턴스 측 유형을 반환하고 인스턴스에 공개적으로 표시되는 모든 멤버를 포함합니다. 런타임에 인스턴스에있을지라도 또는 멤버를 포함하지 않습니다 .:PersonPersonprivateprotected

인터페이스로서의 클래스

지금까지 클래스를 생성하는 방법과 extends키워드를 사용하여 다른 클래스에서 상속하는 방법을 살펴 보았습니다 . 클래스에 특정 스키마가 있어야하는 경우 interface키워드를 사용 하여 인터페이스를 구현합니다.

TypeScript의 클래스는 설명 된대로 암시 적 인터페이스 도 정의합니다 . 즉, TypeScript는 클래스 의 공용 멤버 ( 속성 및 메서드 ) 에서 인터페이스를 만듭니다 . 따라서 implements클래스에 키워드를 사용 하여 다른 클래스의 공개 스키마를 구현할 수 있습니다 .

💡 클래스에 의해 정의 된 암시 적 인터페이스는 클래스의 인스턴스 측 입니다.

(class-interface.ts)

위의 예에서는 Person일반 클래스이며 클래스를 Student구현합니다 Person. 따라서 Student속성을 정의해야 firstName하고 lastName뿐만 아니라 getFullName에 의해 지정된 메소드 Person클래스를.

현재 TypeScript는 private또는 protected필드를 사용 하여 클래스를 구현하도록 허용하지 않으며 그럴만 한 이유가 있습니다. 이 StackOverflow 답변을 따라이 문제를 이해할 수 있습니다 .

💡abstract 클래스를 구현할 수도 있으며 동일한 규칙이 적용됩니다.

위의 예에서 Student클래스는 Person클래스 에서 아무것도 상속하지 않습니다 . 그러나 클래스의 일부 기능을 상속해야하지만 클래스를 인터페이스로 사용해야하는 경우 구조를위한 추상 메서드 가 있습니다 .

추상 클래스는 abstract주석 이있는 메서드를 가질 수 있습니다 . 이러한 메서드를 추상 메서드라고하며 본문이 없습니다. 이는 인터페이스의 메서드 서명과 유사한 메서드 서명일뿐입니다. 추상 클래스를 상속하는 클래스는 이러한 메서드를 구현해야합니다.

(class-interface-with-abstract-methods.ts)

위의 예제는 우리가 이전에 추상 클래스 sectopm에서 사용했던 것과 같은 프로그램입니다. 클래스 의 getFullName메서드 Person는 추상 메서드이므로 본문이 없습니다.

이후 Student클래스가 확장 Person클래스를, 그것은 상속 firstNamelastName특성. 그러나 getFullName메서드는 추상적이므로 Student자체적으로 구현해야합니다.

💡 추상 클래스에서 추상 속성 을 가질 수도 있으며 하위 클래스도이를 구현해야합니다.

에서 인터페이스 레슨 , 우리는 인터페이스를 사용하여 다른 인터페이스에서 속성을 상속 할 수 있음을 알게 extends키워드. 이제 클래스가 암시 적 인터페이스를 정의한다는 것을 알았으므로 클래스를 사용하여 인터페이스를 확장 할 수 있습니다.

(interface-extends-class.ts)

위의 예에서, 클래스는 Person보유 firstNamelastName공개 특성 및 getFullName공개 방법. 이들은 함께 Student인터페이스가 상속 하는 암시 적 인터페이스를 형성합니다 . Student인터페이스는 또한 자체 marks유형 number의 속성을 선언합니다 .

따라서 유형의 모든 개체에는 Student이 4 개의 필드가 모두 있어야합니다. 이후 ross의 일종 Student이지만이 포함되지 않은 getFullName속성을 타이프 스크립트 컴파일러는 프로그램을 컴파일하지 않습니다.

💡 클래스는 Student인터페이스를 구현 하거나 다른 인터페이스도 Student인터페이스 에서 상속 할 수 있습니다 .

EcmaScript 비공개 필드

이제 JavaScript는 기본적으로 private 필드를 지원합니다 . 이 기능은 공식적으로 출시되지 않았지만 Google Chrome 및 Node는이를 지원합니다. TypeScript 클래스에서 속성에 주석을 추가하는 방법과 유사하게 JavaScript에서 비공개로 간주되는 속성에 접두사를 private사용할 수 있습니다 #.

(ecmascript-private-properties.ts)

EcmaScript 속성은 JavaScript 개체에 새 동작을 추가하며 기존 JavaScript에서는 동일한 동작을 수행 할 방법이 없습니다. 따라서 이에 대한 정확한 polyfill을 찾을 수 없습니다. 이러한 이유로 TypeScript 컴파일러는 ES2015 이상을 대상으로하는 한이 기능이 구현 된 프로그램 만 컴파일합니다 .

(thatisuday.com / GitHub / Twitter / StackOverflow / Instagram)

Suggested posts

React 자습서가 가르치지 않는 5 가지 주요 교훈

React 자습서가 가르치지 않는 5 가지 주요 교훈

React 개발자가 알아야 할 필수 개념과 교훈이 많이 있지만 대부분의 튜토리얼에서는 다루지 않습니다. 나는 당신이 알아야 할 가장 중요한 주제 중 일부를 직접 골랐지만, 자세히 다루기 위해 시간을 할애 한 기사는 거의 없습니다.

Express.js 시작하기

Express.js 시작하기

Express는 웹 및 모바일 앱을 만드는 경험을 즐겁게 만드는 기능 세트가 포함 된 Node.js 프레임 워크입니다.