TypeScript - 클래스
- 클래스 메서드
- 독립 함수와 동일한 방식의 메서드
- 매개변수 타입이나 기본 값을 지정하지 않으면 any 타입을 기본 값으로 가진다.
- 메서드를 호출하려면 허용 가능한 수의 인수가 필요하다. 재귀 함수가 아니라면 대부분 반환 타입 유추 가능
- 메서드 호출 시 올바른 타입의 인수가 올바른 수로 제공되는지 확인하기 위해 타입 검사 실시
- 클래스 속성(attribute)
- 클래스의 속성을 읽거나 쓰려면 명시적으로 선언해야 한다.
- 클래스 속성 - method
- 모든 prop은 초기화 또는 정의해야 한다. (! 또는 ?는 제외)
- 클래스 속성 - 초기화 검사
- StrictNullCheck On에서 TS는 undefined 타입으로 선언된 각 속성이 생성자에서 할당되었는지 확인
- 초기화하지 않았다는 것은 undefined이므로 생성자에서라도 초기화 해야 한다.
- StrictNullCheck가 없다면 타입 시스템이 undefined 값에 접근할 수 없다고 말할지라도 클래스 인스턴스는 undefined 값에 접근할 수 있다.
- 클래스 속성 - 확실하게 할당된 속성
- 엄격한 초기화 검사를 적용하면 안되는 속성인 경우 변수 이름 뒤에 ‘!’를 추가해 검사를 비활성화하도록 하기
- TS 속성이 처음 사용되기 전에 undefined 값이 할당됨
- 또는 생성자에서 초기화
- constructor(변수: string[]) { this.변수 = 변수; }
- 클래스 속성 - 선택적 속성
- 선언된 속성 이름 뒤에 ?를 추가해 속성을 옵션으로 선언
- class 클래스 { 변수?: string; }
- ‘ | undefined’ 를 포함하는 유니언 타입과 동일하게 작동
- 선언된 속성 이름 뒤에 ?를 추가해 속성을 옵션으로 선언
- 클래스 속성 - 읽기 전용 속성 (readonly)
- 선언된 속성 이름 앞에 readonly 키워드를 추가해 속성을 읽기 전용으로 선언
- class 클래스 { readonly 변수: string; constructor(변수: string) { this.변수 = 초기화값; }
- readonly로 선언된 속성은 선언된 위치 또는 생성자에서 초기값만 할당할 수 있다. (다른 모든 위치는 읽을 수 만 있고 쓸 수 없음)
- readonly는 타입 시스템에만 존재하고 JS로 컴파일할 때는 삭제된다.
- 클래스 속성 - readonly literal
- 값의 타입이 가능한 좁혀진 리터럴 타입으로 유추
- ex)
class 클래스 { readonly 변수1: string = 초기화값; readonly 변수2 = "Hello"; // Literal Type } // 변수1의 타입은 string // 변수2의 타입은 "Hello"
- 값의 타입이 가능한 좁혀진 리터럴 타입으로 유추
- 타입으로서의 클래스
- TS는 클래스의 동일한 멤버를 모두 포함하는 모든 객체 타입을 클래스에 할 수 있는 것으로 간주
- TS의 구조적 타이핑이 선언되는 방식이 아니라 객체의 형태만 고려하기 때문
- 클래스와 인터페이스 (implements)
- 클래스 이름 뒤에 implements 키워드와 인터페이스 이름을 추가하면 클래스의 인스턴스가 해당 인터페이스를 준수한다고 선언할 수 있다.
- class 클래스 implements 인터페이스 { … }
- 부모 클래스는 선언만 하며, 자식 클래스는 부모의 기능을 다시 정의해서 사용해야 한다. (오버라이딩)
- 클래스 이름 뒤에 implements 키워드와 인터페이스 이름을 추가하면 클래스의 인스턴스가 해당 인터페이스를 준수한다고 선언할 수 있다.
- 클래스와 인터페이스 - 다중 인터페이스 구현
- 클래스에 구현된 인터페이스 목록은 개수 제한없이 인터페이스를 사용할 수 있다. (다 상속 가능)
- class 클래스 implements 인터페이스1, 인터페이스2 { … }
- 하지만 두 개의 충돌하는 인터페이스를 구현하는 클래스를 선언하려고 하면 클래스에 하나 이상의 타입 오류 발생
- 클래스에 구현된 인터페이스 목록은 개수 제한없이 인터페이스를 사용할 수 있다. (다 상속 가능)
- 클래스 확장 (extends)
- 다른 클래스를 확장하거나 하위 클래스를 만드는 자바스크립트 개념에 타입 검사 추가
- class 하위클래스 extends 기본클래스 { … }
- 기본 클래스에 선언된 모든 메서드나 속성은 하위 클래스(파생 클래스) 에서 사용 가능
- 부모 클래스에서 선언과 정의를 모두하고, 자식 클래스는 오버라이딩 할 필요없이 부모 클래스의 기능을 사용할 수 있다.
- extends는 클래스 한 개만 상속받을 수 있다.
- 다른 클래스를 확장하거나 하위 클래스를 만드는 자바스크립트 개념에 타입 검사 추가
- 클래스 확장 - 재정의(override)된 생성자
- 하위 클래스가 자체 생성자를 선언하면 super 키워드를 통해 기본 클래스 생성자를 호출해야 함
- class 하위클래스 extends 기본클래스 { constructor() { super(값); } }
- 하위 클래스 생성자는 모든 매개변수 선언 가능
- 클래스 확장 - 재정의(override)된 메서드
- 하위 클래스는 기본 클래스와 동일한 이름으로 새 메서드를 다시 선언할 수 있다.
- 클래스 확장 - 재정의된 속성
- 하위 클래스는 동일한 이름으로 기본 클래스의 속성 (변수)을 명시적으로 다시 선언할 수 있다. (하위는 기본과 구조적으로 일치해야함)
- 추상 클래스 (Abstract Class)
- 일부 메서드를 구현하지 않고 하위 클래스가 해당 메서드를 제공할 것을 예상하고 기본 클래스를 만드는 방법
- abstract class 추상클래스 { readonly name: string; constructor(name: string) { this.name = name; } // 아래 코드 처럼 본체는 없음 abstract 추상메서드(): string[]; } class 하위클래스 extends 추상클래스 { 추상메서드() { // 구현코드 } }
- 추상 클래스를 상속 받는 하위 클래스는 꼭 추상 메서드를 재정의 해야 한다. (override 안하면 error 발생)
- 추상 클래스는 객체 생성이 불가능하고, 자식 클래스를 대상으로 객체 생성 한다.
- 추상 클래스는 추상 메서드를 가진 클래스를 말하며 일반 멤버(변수, 메서드)도 가질 수 있다. 하지만 한 개 이상의 추상 메서드는 반드시 존재해야함!
- 멤버 접근성
- TS의 멤버 접근성은 클래스 멤버의 선언 이름 앞에 아래 키워드 중 하나를 추가한다.
- public (기본값)
- 모든 곳(외부, 하위) 에서 접근 가능
- protected
- 해당 클래스 내부 또는 하위 클래스에서만 접근 가능
- private
- 해당 클래스 내부에서만 접근 가능
- 멤버 접근성 - 정적 필드 제한자 (static)
- 클래스를 통해 인스턴스를 생성할 필요 없이 클래스의 속성이나 메서드를 사용하고자 할 때 static 키워드를 사용하여 속성이나 메서드 정의
- ex) protected static readonly 변수: ‘aaa’;
- static 키워드를 사용하여 선언된 변수, 함수는 정적 변수, 정적 함수라고 말한다. 이는 클래스에 속하는 변수와 함수로 호출하기 위한 객체가 필요하지 않고 클래스에서 바로 호출 가능하다. (클래스에서 점 표기법으로 직접 호출가능)
- 객체에서(인스턴스 생성) 정적 변수, 정적 함수 호출은 불가능
- var 클래스2 = new 클래스();
- 클래스2.정적함수(); → 에러 발생!
- 클래스를 통해 인스턴스를 생성할 필요 없이 클래스의 속성이나 메서드를 사용하고자 할 때 static 키워드를 사용하여 속성이나 메서드 정의
TypeScript - 타입 제한자
- top 타입 (any, unknown)
- top 타입은 모든 타입이 할당 가능한 타입
- any
- TS가 해당 값에 할당 가능성 또는 멤버에 대해 타입 검사를 수행하지 않도록 명시적으로 지시 (타입 아직 미정의)
- const anyParam = (value: any) ⇒ { … }
- 위 함수는 오류는 발생하지 않지만 런타임 에러 발생
- unknown
- unknown 타입 값의 속성에 직접 접근할 수 없고 top 타입이 아닌 타입에는 할당할 수 없다.
- const anyParam = (value: unknown) ⇒ { … }
- instanceof나 typeof를 사용하여 타입을 narrowing 하거나 타입 어서션을 통해 값의 타입이 제한된 경우에 해당 타입이 갖는 속성에 접근할 수 있다.
- const anyParam = (value: unknown) => { if (**typeof** value === 'string') { ... } }
- 타입 서술어
- isString() 함수처럼 인자가 특정 타입인지 여부를 나타내기 위해 boolean 값을 반환하는 함수를 위한 구문
- const isString = (value: unknown): **value is string** => typeof value === 'string';
- 타입 연산자 - typeof
- 제공되는 값의 타입 반환
- const customer1 = { name: 'Im', mobile: '8282', }; // {name: string, mobile: string} 반환 let customer: typeof customer1;
- 타입 연산자 - keyof
- 존재하는 타입의 키를 바탕으로 유니언 타입 생성
- const f3 = (customer: 객체, key: **keyof** 객체) => { … }
- 제공되는 값에 존재하는 키만 매개변수의 타입으로 허용하고 싶을 때 typeof 함께 사용
- const 변수 = (key: **keyof typeof 객체**)=> 객체[key];
- 타입 어서션 (as)
- 값의 타입을 재정의 (확신할 수 있는 경우에만)
- const 변수 = JSON.parse(someData) **as 객체**;
- non-null 어서션
- null 또는 undefined를 포함할 수 있는 변수에서 null과 undefined를 제거한다. (느낌표)
- const jang = 배열.find((a) => a.name === 'jang');
- let 변수: number = jang**!**.age;
- null 또는 undefined를 포함할 수 있는 변수에서 null과 undefined를 제거한다. (느낌표)
TypeScript - 제네릭
- 제네릭 함수
- 호출하는 방식에 따라 다양한 타입으로 작동하도록 의도한다.
- 함수의 기능이 똑같은데 매개변수의 타입과 반환하는 타입이 다를 때 제네릭 기법을 사용하여 한 개의 함수로 구현 가능
- 제네릭 함수 구현
- function 제네릭함수<T>(arg: T): T { return arg; }
- 함수명 뒤에 <T>를 추가하고, T를 매개변수의 타입 또는 반환 타입으로 설정 가능
- 꼭 <T>로 작성할 필요는 없고 다른 문자열도 사용 가능 (대부분 Type의 T로 작성)
- function 제네릭함수<T>(arg: T): T { return arg; }
- 제네릭 함수 호출
- <>안에 인수의 타입을 작성한다.
- ex) let 변수1 = 제네릭함수<number>(123);
- ex) let 변수2 = 제네릭함수<string>(’ABC’);
- <>안에 인수의 타입을 작성한다.
- 다중 함수 타입 매개변수
- 구현
- function 다중제네릭함수<First, Second> (first: First, second: Second_ { return [first, second] as const; }
- 호출
- ex) const [name, age] = 다중제네릭함수(’Im’, 25);
- ex) const [level, agree] = 다중제네릭함수<number, boolean>(10, true);
- 구현
- 제네릭 인터페이스
- 인터페이스에서도 제네릭을 사용해 항목의 타입 정의 가능
- // 구현 interface 제네릭인터페이스<T> { id: number, name: string, additional?: T; } // 호출 type Color = 'red' | 'blue' | 'green'; const info1: 제네릭인터페이스<Color> = { id: 1, name: 'lim', additional: 'red' }; type Address = { sigungu: string, zipcode: string }; const info2: Info<Address> = { id: 2, name: 'hong', additional: { sigungu: 'Seoul', zipcode: '04112'} }
- 제네릭 인터페이스 구현
- class 클래스<T> implements 제네릭인터페이스<T> { … }
- 제네릭 클래스
- 클래스도 제네릭 함수를 호출하는 것과 동일한 타입 인수 유추 규칙을 따른다.
- // 구현 class Factory<T> { protected products: T[]; constructor(product: T) { this.products = [product]; } create(product: T) { this.products.push(product); } getProducts() { return [...this.products]; } }; // 호출 const factory = new Factory({ name: 'KIA', description: 'car factory' }); // 확장 class CoffeeFactory<T> extends Factory<T> {} const coffeeFactory = new CoffeeFactory<{ menu: string, price: number }>({ menu: 'americano', price: 2000 });
- 정적 클래스 제네릭
- ex)
- class BothLogger<OnInstance> { instanceLog(value: OnInstance) { console.log('instanceLog.value > ', value); return value; } static A: OnInstance; static staticLog<OnStatic>(value: OnStatic) { let instanceLogValue: OnInstance; console.log('staticLog.value > ', value); return value; } }
- OnInstance 타입은 인스턴스 생성시 정해진다.
- 인스턴스를 생성하지 않아도 접근 가능한 정적(static) 클래스 메서드에서는 클래스에 선언된 어떤 타입 매개변수에도 접근할 수 없다.
- 메서드 제네릭
- 인스턴스와 무관하게 메서드에서 자체 제네릭 타입 사용 가능
- 제네릭 제한자
- 제네릭 기본값
- 함수 매개변수에 기본값을 제공하듯 제네릭 타입 매개변수에 기본 타입 지정 가능
- 제한된 제네릭 타입 (extends)
- extends 키워드를 사용해 T의 타입 제한
- keyof는 전체 키 대상, extends keyof는 해당 프로퍼티의 특정키를 직접 검사
- 제네릭 기본값
- Promise
- 최종적으로 resolve된 값을 나타내는 단일 타입 매개변수를 갖는다.
- async 함수
- async 함수의 반환 타입은 항상 Promise 타입이다.
- 제네릭 명명규칙
- 첫 번쨰 타입 인수로 T를 사용
- 후속 타입 매개변수가 존재하면 U, V 등을 사용
- 타입 인수가 어떻게 사용되어야 하는지 맥락과 관련된 정보가 알려진 경우 해당 용어의 첫 글자를 사용 (상태 관리 라이브러리-S, 키-K, 값-V)
- 여러 개의 타입 매개변수를 갖거나 목적이 명확하지 않은 경우 완전한 이름을 사용
'교육 (Today I Learned) > Hanaro' 카테고리의 다른 글
[Hanaro] 23일차 / React 시작하기 (0) | 2024.02.18 |
---|---|
[Hanaro] 22일차 / TypeScript (선언 파일과 구성 및 옵션, 타입 운영, 유틸리티 타입) (0) | 2024.02.15 |
[Hanaro] 19일차 / TypeScript (function, Array, tuple, interface) (0) | 2024.02.13 |
[Hanaro] 18일차 / TypeScript (Type System, Union&Literal, Object, function) (0) | 2024.02.08 |
[Hanaro] 17일차 / JavaScript (DOM) (0) | 2024.02.07 |