열거형(Enum)
: 특정 값들의 집합
✔️ 숫자형 이넘
디폴드 값으로 숫자형을 사용하며 아래와 같이 선언한다.
enum Computer {
Monitor = 3,
Mouse = 7,
Keyboard = 1,
Speaker = 5,
}
초기 값을 주면 차례로 1씩 증가한다.
Monitor - 1
Mouse - 2
Keyboard - 3
Speaker - 4
초기 값을 주지 않으면 0부터 차례로 1씩 증가한다.
Monitor - 0
Mouse - 1
Keyboard - 2
Speaker - 3
이넘 값에 대해 산술 연산을 수행할 수도 있다.
enum Computer {
Monitor = 3,
Mouse = 7,
Keyboard = 1,
Speaker = 5,
}
let a: Computer = Computer.Keyboard;
let b: number = Computer.Mouse;
console.log(a); // 1
console.log(b); // 7
✔️ 문자형 이넘
enum Computer {
Monitor = "MONITER",
Mouse = "MOUSE",
Keyboard = "KEYBOARD",
Speaker = "SPEAKER"
}
문자형 이넘은 이넘값을 전부 다 특정 문자 또는 다른 열거형 값으로 초기화해야 한다.
숫자형 이넘과 달리 초기값을 설정하지 않았을 때 동작하는 auto-incrementing이 없지만 디버깅을 할 때 항상 명확한 값이 나와 읽기 편하다.
✔️ 역 매핑
숫자형 이넘에만 존재하는 특징이며 이넘의 키로 값을 얻을 수 있고 값으로 키를 얻을 수 있다.
enum Enum {
A
}
let a = Enum.A;
let nameOfA = Enum[a]; // "A"
인터페이스(Interface)
: 타입 체크를 위해 사용하며 인터페이스에 선언된 프로퍼티 또는 메서드 구현을 강제하여 일관성을 유지하도록 한다.
✔️ 변수
- 인터페이스는 객체의 구조를 정의하기 위해 주로 사용되는 예약어
- 인터페이스의 이름을 대문자로 시작하는 것은 네이밍 컨벤션
- 정의된 프로퍼티보다 더 많거나 적게 작성하여 선언할 수 없다.
interface User {
name: string;
age: number;
}
// 정상적으로 선언됩니다.
const user: User = {
name: "anna",
age: 20
}
// 프로퍼티의 순서를 지키지 않아도 정상적으로 선언됩니다.
const user: User = {
age: 20,
name: "anna"
}
// 정의된 프로퍼티보다 적게 작성했기 때문에 에러가 납니다.
const user: User = {
name: "anna"
}
// 정의된 프로퍼티보다 많이 작성했기 때문에 에러가 납니다.
const user: User = {
name: "anna",
age: 20,
job: "developer"
}
모든 프로퍼티가 필요하지 않을 경우가 있기에 ? 연산자로 선택적 프로퍼티를 작성할 수 있다.
interface User {
name: string;
age?: number;
}
// 정상적으로 선언됩니다.
const user: User = {
name: "anna"
}
✔️ 함수
: 인터페이스를 사용하여 함수의 매개변수와 반환 타입도 정의 할 수 있다.
interface User {
name: string;
age: number;
job: string;
}
interface Greeting {
(user: User, greeting: string): string;
}
const greet: Greeting = (user, greeting) => {
return `${greeting}, ${user.name}! Your job : ${user.job}.`;
}
const user: User = {
name: "anna",
age: 30,
job: "developer"
};
const message = greet(user, "Hi");
console.log(message); // "Hi, anna! Your job : developer."
greet 함수는 Greeting 인터페이스로부터 매개변수의 타입과 반환 타입을 받으므로 명시해줄 필요가 없다.
✔️ 클래스
interface Calculator {
add(x: number, y: number): number;
substract(x: number, y: number): number;
}
class SimpleCalculator implements Calculator {
add(x: number, y:number) {
return x + y;
}
substract(x: number, y: number) {
return x - y;
}
}
const caculator = new SimpleCalculator();
console.log(caculator.add(4, 9)); //13
console.log(caculator.substract(10, 5)); //5
Calculator 인터페이스는 add와 substarct 메서드를 정의
SimpleCalculator 클래스는 Calculator 인터페이스를 사용했기 때문에
Calculator 인터페이스에 정의된 add와 substarct 메서드를 반드시 작성해야한다.
클래스를 구현할 때 인터페이스에서 정의된 함수나 메서드의 매개변수 타입과 반환 값이 일치하도록 구현해야 한다.
클래스 내부에서 해당 메서드의 매개변수 타입을 한번 더 명시 해주지 않으면 컴파일 에러가 발생한다.
✔️ 인터페이스와 상속
: extends 키워드 사용해 기존에 존재하던 클래스를 상속해 새로운 클래스를 정의할 수 있다.
인터페이스도 extends 키워드를 사용해서 기존에 존재하던 인터페이스를 상속해 확장이 가능하다.
interface Person {
name: string;
age: number;
}
interface Developer extends Person {
language: string;
}
const person: Developer = {
language: "TypeScript",
age: 20,
name: "Anna",
}
타입 별칭(Type Aliases)
: 타입의 새로운 이름을 만드는 것, type 키워드 사용
type CustomType = number;
let num: CustomType = 123;
type Person = {
id: number;
name: string;
email: string;
}
//Commentary 인터페이스에서 Person 타입을 참조하고 있습니다.
interface Commentary {
id: number;
content: string;
user: Person;
}
//객체에서 Commentary 인터페이스를 참조하고 있습니다.
let comment1: Commentary = {
id: 1,
content: "뭐예요?",
user: {
id: 1,
name: "김코딩",
email: "kimcoding@codestates.com",
},
}
//Commentary 인터페이스 내부에 content 프로퍼티가 존재하기 때문에
//content 프로퍼티를 작성하지 않으면 컴파일 에러가 납니다.
let kimcoding: Commentary = {
id: 1,
user: {
id: 1,
name: "김코딩",
email: "kimcoding@codestates.com",
},
};
//Person 타입 내부에 isDeveloper 프로퍼티가 존재하지 않기 때문에
//isDeveloper 프로퍼티를 작성할 시 컴파일 에러가 납니다.
let kimcoding: Commentary = {
id: 1,
content: "뭐예요?",
user: {
id: 1,
name: "김코딩",
email: "kimcoding@codestates.com",
isDeveloper: true,
},
};
인터페이스와 비슷하지만
참조를 할 때 마우스 올리면 type은 프로퍼티 타입을 보여주고 인터페이스는 안보여준다.
그러나 타입별칭은 extends 키워드를 사용한 확장이 안된다. 유연한 코드 작성을 하려면 인터페이스를 쓰는게 좋다.
타입 추론(Type Inference)
: 변수나 함수의 타입을 선언하지 않아도 TypeScript가 자동으로 유추하는 기능
let isString = "KimgCoding"
TypeScript는 isString의 타입을 자동으로 문자로 추론한다.
최적 공통 타입(Best Common Type)
TypeScript는 여러 표현식에서 타입 추론이 발생할 때 최적 공통 타입을 계산한다.
let arr = [0, 1, null];
number, null 타입 중에 TypeScript는 최적 공통 타입 알고리즘으로 다른 타입과 가장 잘 호환되는 타입을 선택한다.
문맥상의 타이핑
코드의 위치를 기준으로 일어난다.
function add(a, b) {
return a + b;
}
만약 매개변수 a,b가 둘 다 숫자 타입이면 add 함수의 반환 값도 숫자 타입으로 추론된다.
타입추론 장단점
장점: 가독성, 생산성, 오류발견 용이성 향상
단점: 잘못된 추론으로 오류 발생가능, 명시적인 타입 지정이 필요한 경우가 있음
클래스
: 클래스에서 속성과 메서드에 대한 타입을 명시할 수 있다.
class Person {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
greet(): void {
console.log(`안녕하세요, 제 이름은 ${this.name}이고, ${this.age}살 입니다.`);
}
}
constructor 를 이용하여 초기화 하는 멤버들은 상단에서 정의를 해주고
constructor 에서 인자를 받을 때도 타입을 명시해줘야 한다.
상속
class Animal {
move(distanceInMeters: number): void {
console.log(`${distanceInMeters}m 이동했습니다.`);
}
}
class Dog extends Animal {
speak(): void {
console.log("멍멍!");
}
}
const dog = new Dog();
dog.move(10);
dog.speak();
public,private
클래스 내에 선언된 멤버는 공개가 기본값이지만 public 키워드를 사용해서 명시적으로 표시할 수 있다.
class Person {
public name: string;
private age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
greet(): void {
console.log(`안녕하세요, 제 이름은 ${this.name}이고, ${this.age}살 입니다.`);
}
}
readonly
readonly 키워드를 사용해서 변경되면 안될 값을 명시하여 보호할 수 있다.
class Mydog {
readonly name: string;
constructor(theName: string) {
this.name = theName;
}
}
let spooky = new Mydog("스푸키");
spooky.name = "멋진 스푸키"; // 에러
Reference
코드스테이츠 유어클래스
'TypeScript' 카테고리의 다른 글
[typescript] 나는 제네릭을 아는가? (2) | 2023.09.28 |
---|---|
type alias, interface (0) | 2023.09.03 |
[TypeScript] 프로젝트 환경설정과 문법 (0) | 2023.05.30 |