리터럴 타입
특정 값을 나타내는 타입으로, 해당 값이 정확하게 일치해야 한다.
리터럴 타입은 코드의 가독성을 높이고, 잘못된 값이 들어노는 것을 막을 수 있게 해 준다.
문자형, 숫자형, 불리언형, 객체형이 있다.
문자열 리터럴 타입
result에는 'success'라는 문자열과 'error'라는 문자열만 들어갈 수 있다. line 3처럼 다른 값을 넣으면 아래 사진과 같은 에러가 발생한다. 숫자형과 불리언형도 동일하게 사용하면 된다.
let result: 'success' | 'error';
result = 'success'; // 허용
result = 'pending'; // 에러
객체 리터럴 타입
객체 리터럴은 객체의 속성명뿐만 아니라 그 값 또한 일치해야 한다. line 3처럼 'Lee'와 30이 아닌 다른 값을 넣으면 에러가 발생한다.
let person: {name: 'Lee', age: 30};
person = {name: 'Lee', age: 30}; // 허용
person = {name: 'Choi', age: 40}; // 에러
타입 별칭(Type Alias)
반복되는 코드를 재사용하기 위해 타입을 재정의 하는 것을 말한다.
동서남북 중 하나의 값을 가지는 두 변수 direction1, direction2가 있다고 가정해 보자. 그러면 아래와 같이 리터럴 타입 부분이 중복된다.
let direction1: 'North' | 'East' | 'South' | 'West';
direction1 = 'North';
let direction2: 'North' | 'East' | 'South' | 'West';
direction2 = 'East';
타입 별칭을 이용해 중복되는 코드를 없애보자.
다음 코드와 같이 CardinalDirection이라는 타입을 정의해서 사용한다. 이 CardinalDirection이 타입 별칭이다.
type CardinalDirection = 'North' | 'East' | 'South' | 'West';
let direction1: CardinalDirection = 'North';
let direction2: CardinalDirection = 'East';
유니온 타입
제한된 타입을 동시에 지정하고 싶을 때 사용한다.
다음 코드에서 anyValue 변수에는 문자형과 숫자형의 값을 담을 수 있다.
let anyValue: number | string;
anyValue = 100;
anyValue = 'abc';
함수의 파라미터에도 유니온 타입을 사용할 수 있다.
let numStr: number | string = 100;
function convertToString(value: number | string) :string {
return String(value);
}
function convertToNumber(value: number | string): number {
return Number(value);
}
하지만 동일한 유니온 타입 코드가 반복되고 있다. 따라서 다음과 같이 타입 별칭을 사용할 수 있다.
type strOrNum = number | string;
let numStr: strOrNum = 100;
function convertToString(value: strOrNum) :string {
return String(value);
}
function convertToNumber(value: strOrNum): number {
return Number(value);
}
타입 가드
유니온 타입의 경우 대입하는 과정에서 오류가 발생할 수 있기 때문에 typeof 연산자를 사용하여 타입 검증을 수행하는 것을 말한다.
아래와 같은 타입과 변수들이 있다.
type strOrNum = number | string;
let numStr2: strOrNum = 100;
let item: number;
여기서 item 변수에 numStr의 값을 담는다고 해보자.
지금은 numStr이 숫자형이라서 문제가 발생하지 않지만 numStr은 문자형일 수도 있고, 그럴 경우 오류가 발생한다..
item = numStr // ?
따라서 다음과 같이 typeof 연산자를 사용하여 타입 검증을 수행하여 값을 담는다. 이것을 타입 가드라고 한다.
if(typeof numStr2 === 'number') {
item = numStr2;
}
Array와 Tuple
Array
배열은 길이가 가변적이고, 동일한 타입의 요소로 구성된다.
배열의 타입은 다음과 같이 지정할 수 있다.
let numbers: number[] = [1, 2, 3, 4, 5];
let fruits: string[] = ['apple', 'banana', 'orange'];
유니온 타입으로도 다음과 같이 지정할 수 있다.
let mixedArray: (number | string)[] = [1, 'two', 3, 'four'];
별도의 타입을 지정하지 않아도 타입 추론으로 자료형이 결정되기는 한다. 아래 사진에서 number형 배열로 지정된 것을 확인할 수 있다.
let infer = [1, 2, 3];
읽기만 가능한 배열은 다음과 같이 선언할 수 있다.
let readOnlyArray: ReadonlyArray<number> = [1, 2, 3];
Tuple
튜플은 길이가 고정적이고, 각 요소의 타입이 정해져 있다.
다음과 같이 [] 안에 각 요소의 타입을 순서대로 작성하면 된다.
let greeting: [number, string, boolean] = [1, 'hello', true];
클래스
클래스는 객체의 설계도, 생산 틀 같은 개념이고, 객체는 클래스의 실체이다. 예로 표현하자면 클래스는 쿠키 틀, 객체는 그 틀로 찍어내서 만든 쿠키 같은 것이다.
클래스는 다음과 같이 선언한다. 멤버 변수를 속성, 프로퍼티라고도 하며, 멤버 함수는 메서드라고 부른다.
class 클래스이름 {
// 멤버 변수
// ...
// 멤버 함수
// ...
}
접근 지정자
접근 지정자에는 세 종류가 있다.
접근 지정자 | 설명 |
public | 외부에서도 직접 접근할 수 있다. |
private | 그 클래스의 내부에서만 접근할 수 있다. |
protected | 상속 관계일 때만 접근할 수 있다. |
멤버 변수는 보통 public으로 선언하지 않는다. private인 멤버 변수 앞에는 언더바(_)를 붙이는 규칙이 있다. 참고로 아무 접근 지정자도 적지 않으면 기본 값이 public이기 때문에 public으로 설정된다.
class Employee {
private _empName: string;
private _age: number;
private _empJob: string;
}
생성자
다른 언어에서는 보통 생성자는 클래스의 이름과 동일하지만 타입스크립트에서는 constructor()가 생성자다.
class Employee {
private _empName: string;
private _age: number;
private _empJob: string;
// 생성자
constructor(empName: string, age: number, empJob: string) {
this._empName = empName; // this는 자기 자신을 나타냄
this._age = age;
this._empJob = empJob
}
}
객체는 다음과 같이 생성한다. 객체의 생성과 동시에 생성자가 호출된다. 위 코드의 생성자 동작에서 볼 수 있듯이 파라미터의 값들이 멤버 변수에 저장된다.
const emp1 = new Employee('lee', 20, 'developer');
생성자를 저렇게 작성해도 오류가 발생하지는 않지만 멤버 변수를 선언하는 부분과 중복되는 코드가 많다. 그래서 다음 코드와 같이 수정하면 멤버 변수의 선언과 초기화를 동시에 수행할 수 있다.
class Employee {
constructor(
private _empName: string,
private _age: number,
private _empJob: string
) {}
}
getter
멤버 변수가 private로 지정되어 있기 때문에 지금 상태에서는 멤버 변수의 값을 가져올 수 없다. 외부에서 멤버 변수에 직접 접근하는 건 캡슐화에 어긋나기 때문에 getter라는 메서드를 이용해 외부에서 멤버 변수의 값을 받을 수 있도록 해야 한다.
타입스크립트에서는 getter를 get 키워드를 이용하여 다음과 같이 사용한다. this는 지금 이 객체를 가리키는 키워드이다.
class Employee {
constructor(
private _empName: string,
private _age: number,
private _empJob: string
) {}
get empName() {
return this._empName;
}
}
const emp = new Employee('lee', 20, 'engineer');
console.log(emp.empName); // output: lee
setter
외부에서 멤버 변수의 값을 수정하려면 setter을 사용해야 한다.
타입스크립트에서는 setter을 다음과 같이 set 키워드를 사용하여 구현한다.
class Employee {
constructor(
private _empName: string,
private _age: number,
private _empJob: string
) {}
get empName() {
return this._empName;
}
set empName(value: string) {
this._empName = value;
}
}
const emp2 = new Employee('lee', 20, 'engineer');
emp2.empName = 'choi';
console.log(emp2.empName); // output: choi
배운 점
- 리터럴 타입을 사용하면 코드의 반복을 줄여 가독성이 높아지고, 잘못된 값이 들어오는 것을 방지할 수 있다.
- 타입 별칭은 사용자가 타입을 정의하여 반복되는 코드를 재사용할 수 있게 해 준다.
- 유니온 타입을 사용하면 제한된 타입을 동시에 지정할 수 있다.
- 유니온 타입을 사용하는 경우 다른 변수에 대입하는 과정에서 오류가 발생할 수 있으므로 typeof 연산자를 사용하여 타입 검증을 수행해야 한다.(타입 가드)
- 타입스크립트의 getter와 setter은 각각 get 키워드와 set 키워드로 구현한다.
'데브코스' 카테고리의 다른 글
[11주차 - DAY4] 리액트(1) (0) | 2024.05.09 |
---|---|
[11주차 주간 발표] const assertion과 RORO 패턴 (0) | 2024.05.09 |
[10주차 - DAY5] 클래스 (0) | 2024.05.03 |
[10주차 - DAY4] 사용자 정의 자료형, 동적 할당, 객체 지향 (0) | 2024.05.02 |
[10주차 - DAY2] 포인터 (1) | 2024.04.30 |