TypeScript
Part.2
chapter.8 클래스
8.1 클래스 메서드
- 매개변수 타입에 타입이나 기본값을 지정하지 않으면 any타입을 기본으로 갖는다.
메서드를 호출하려면 허용 가능한 수의 인수가 필요하고, 재귀 함수가 아니라면 대부분 반환 타입을 유추할 수 있다.
1 2 3 4 5 6 7 8 9 10
class Greeter { greet(name: string) { console.log(`${name}, do your stuff`); } } new Greeter().greet("Miss Frizzle"); // OK new Greeter().greet(); // Error: Expected 1 argument, but got 0
- string 타입의 단일 필수 매개변수를 갖는 greet클래스 메서드를 가진 Greeter 클래스를 정의한 코드이다.
- 클래스 생성자는 매개변수와 관련하여 전형적인 클래스 메서드처럼 취급되며, 타입스크립트는 메서드 호출 시 올바른 타입의 인수가 올바른 수로 제공되는지 확인하기 위해 타입 검사를 수행한다.
1 2 3 4 5 6 7 8 9 10
class Greeted { constructor(message: string) { console.log(`As I always say: ${message}`); } } new Greeted("take chances, make mistakes, get messy"); new Greeted(); // Error: Expected 1 arguments, but got 0.
- Greeted 생성자는 message: string으로 매개변수가 제공되어야 한다.
8.2 클래스 속성
- 클래스의 속성을 읽거나 쓰려면 클래스에 명시적으로 선언해야 한다.
- 클래스 속성은 인터페이스와 동일한 구문을 사용해 선언하며, 속성 이름 뒤에는 선택적으로 타입 애너테이션이 붙는다.
타입스크립트는 생성자 내의 할당에 대해 그 멤버가 클래스에 존재하는 멤버인지 추론하려고 하지 않는다.
1 2 3 4 5 6 7 8 9 10 11
class FieldTrip { destination: string; constructor(destination: string) { this.destination = destination; //OK console.log(`We're going to ${destination}`); this.nonexistent = destination; // Error: Property 'nonexistent' does not exist on type 'FieldTrip'. } }
- destination은 string으로 명시적으로 선언되어 있어 FieldTrip 클래스인 인스턴승 할당되고 접근할 수 있다.
- 클래스가 nonexistent 속성을 선언하지 않았기 때문에 생성자에서 this.nonexistent 할당은 허용되지 않는다.
1 2 3 4 5
const trip = new FieldTrip("planetarium"); trip.destination; // OK trip.nonexistent; // Error: Property 'nonexistent' does not exist on type 'FieldTrip'.
- 클래스 속성을 명시적으로 선언하면 클래스 인스턴스에서 무엇이 허용되고 허용되지 않는지 이해할 수 있다.
- 클래스 인스턴스가 사용될 때, 코드가 trip.nonexistent와 같은 클래스 인스턴스에 존재하지 않는 멤버에 접근하려고 하면 타입 오류를 발생시킨다.
8.2.1 함수 속성
- 자바스크립트에는 클래스의 멤버를 호출 가능한 함수로 선언하는 두 가지 구문이 있는데, 멤버 이름 뒤에 괄호를 붙이는 메서드 접근 방식이 있다.
또한 값이 함수인 속성을 선언하는 방식도 있다.
1 2 3 4 5
class WithMethod { myMethod() {} } new WithMethod().myMethod === new WithMethod().myMethod; // true
- myFunction(){}과 같이 멤버 이름 뒤에 괄호를 붙여 메서드에 접근할 수 있다.
- 메서드 접근 방식은 함수를 클래스 프로토타입에 할당하므로 모든 클래스 인스턴스는 동일한 함수 정의를 사용한다.
1 2 3 4 5
class WithProperty { myProperty: () => {}; } new WithProperty().myProperty === new WithProperty().myProperty; // false
- 값이 함수인 속성을 선언하는 방식을 사용하면, 클래스 인스턴스를 가리켜야 하는 화살표 함수에서 this 스코프를 사용하여 클래스 인스턴스당 새로운 함수를 실행하는 시간과 메모리 비용 측면에서 유용하다.
- 위의 함수 표현식은 단일 속성을 갖고 있는 () => void 타입이다.
1 2 3 4 5 6 7 8 9 10
class WithPropertyParameters { takesParameters = (input: boolean) => (input ? "Yes" : "No"); } const instance = new WithPropertyParameters(); instance.takesParameters(true); // OK instance.takesParameters(123); // Error: Argument of type 'number' is not assignable to parameter of type 'boolean'.
8.2.2 초기화 검사
- 엄격한 컴파일러 설정이 활성화된 상태에서 타입스크립트는 undefined 타입으로 선언된 각 속성이 생성자에서 할당되었는지 확인한다.
엄격한 초기화 검사는 클래스 속성에 값을 할당하지 않는 실수를 예방할 수 있어 유용하다.
1 2 3 4 5 6 7 8 9 10 11 12
class WithValue { immediate = 0; later: number; // OK(Constructor에서 할당) myBeUndefined: number | undefined; // OK(undefined가 되는 것이 허용됨) unused: number; // Error: Property 'unused` has no initializer // and is not definitely assigned in the constructor. constructor() { this.later = 1; } }
- 엄격한 초기화 검사가 없다면, 타입 시스템이 undefined 값에 접근할 수 없다고 할지라도 클래스 인스턴스는 undefined 값에 접근할 수 있다.
엄격한 초기화 검사가 수행되지 않으면 올바르게 컴파일되지만, 결과 자바스크립트는 런타임 시 문제가 발생한다.
1 2 3 4 5 6
class MissingInitializer { property: string; } new MissingInitializer().property.length; // TypeError: Cannot read property 'length' of undefined
- 클래스 생성자 다음에 클래스 속성을 의도적으로 할당하지 않는 경우가 있을 수도 있다.
- 엄격한 초기화 검사를 적용하면 안 되는 속성인 경우에는 이름 뒤에 !를 추가해 검사를 비활성화하도록 설정한다.
이렇게 하면 타입스크립트에 속성이 처음 사용되기 전 undefined 값이 할당된다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
class ActivitiesQueue { pending: string[]; // Ok initialize(pending: string[]) { this.pending = pending; } next() { return this.pending.pop(); } } const activities = new ActivityQueue(); activities.initialize(["eat", "sleep", "learn"]); activities.next();