
enum Color {
Red,
Green,
Blue,
}Color라는 열거형을 정의하고 있다.Red, Green, Blue 세 개이다.열거형은 숫자형과 문자열형, 혹은 이 둘의 조합으로 정의될 수 있다.
디폴트 값으로 숫자형을 사용하며, 각 값은 자동으로 0부터 시작하여 1씩 증가한다.
그러나 다음과 같이 수동으로 값을 지정할 수도 있다.
enum Color {
Red = 1,
Green = 2,
Blue = 4,
}
Red가 1, Green이 2, Blue가 4로 정의되었다.열거형의 값에 대해 산술 연산을 수행할 수도 있다.
enum Color {
Red = 1,
Green = 2,
Blue = 4,
}
let c: Color = Color.Green;
let greenValue: number = Color.Green;
let blueValue: number = Color.Blue;
console.log(c); // 출력: 2
console.log(greenValue); // 출력: 2
console.log(blueValue); // 출력: 4
문자형 열거형은 앞에서 살펴본 숫자형 열거형과 개념적으로는 거의 비슷하다.
문자형 열거형은 열거형의 값을 전부 다 특정 문자 또는 다른 열거형 값으로 초기화해야 한다.
enum Direction {
Up = "UP",
Down = "DOWN",
Left = "LEFT",
Right = "RIGHT",
}
let myDirection: Direction = Direction.Up;
console.log(myDirection); // 출력: "UP"
Direction이라는 문자열 기반의 열거형(Enum)을 정의Up, Down, Left, Right 각각에는 문자열 값이 할당myDirection 변수를 Direction.Up으로 초기화"UP"auto-incrementing이 없어 디버깅을 할 때 숫자형 열거형의 값은 가끔 불명확하게 나올 때가 있지만 문자형 열거형은 항상 명확한 값이 나와 읽기 편하다.문자열 기반의 열거형은 주로 외부에서 가져온 값을 TypeScript에서 다루기 위해서 사용된다.
예를 들어, HTTP 요청 방식을 나타내는 열거형을 정의할 수 있다.
enum HttpMethod {
Get = "GET",
Post = "POST",
Put = "PUT",
Delete = "DELETE",
}
function makeRequest(url: string, method: HttpMethod) {
// ...
}
makeRequest("/api/data", HttpMethod.Post);
HttpMethod 열거형을 정의makeRequest 함수는 URL과 HTTP 요청 방식을 인자로 받음.HttpMethod.Post와 같이 열거형 값을 사용enum Enum {
A
}
let a = Enum.A;
let nameOfA = Enum[a]; // "A"TypeScript에서 변수를 선언할 때 인터페이스를 아래와 같이 사용할 수 있다.
TypeScript에서 인터페이스는 객체(Object)의 구조를 정의하기 위해 주로 사용되는 예약어이다.
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 인터페이스를 만들었다.
인터페이스를 만들 때 예약어를 작성하고, 인터페이스의 이름을 대문자로 작성한다.
이렇게 인터페이스의 이름을 대문자로 시작하는 것은 네이밍 컨벤션이다.
네이밍 컨벤션(Naming Convention) :
- 이름을 짓는 일종의 관례. TypeScript로 개발할 때 대부분의 개발자는 인터페이스의 이름을 대문자로 시작하도록 작성한다. 인터페이스는 객체의 타입을 정의하고, 객체가 대문자로 시작하는 것과 유사하기 때문에 일관성 있는 코드 작성을 위해 이러한 관례를 따른다.
인터페이스 내에는 name과 age가 정의되어 있기 때문에, User 인터페이스를 사용하여 변수를 선언할 때는 반드시 정의된 프로퍼티를 전부 작성해야 한다.
또한 interface로 정의된 속성만 지정할 수 있으며, 그 외 프로퍼티를 추가로 작성하고자 해도 인터페이스 내에 정의되어 있지 않기 때문에 추가로 프로퍼티를 더 작성하여 선언할 수 없다.
그러나 인터페이스 안의 모든 프로퍼티가 필요한 것은 아니며, 어떤 조건에서만 존재하거나 아예 없을 수도 있기 때문에 ? 연산자를 사용하여 선택적 프로퍼티를 작성할 수도 있다.
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);
위의 코드는 User 인터페이스 외에도 Greeting 인터페이스를 추가로 작성하여 함수 타입을 정의했다.
Greeting 인터페이스는 User 타입과 문자열 타입을 매개변수로 받아 문자열 타입을 반환한다.
greet 함수는 Greeting을 사용하여 구현되었으며, user 객체와 문자열 "Hi"를 전달인자로 전달받아 문자열을 반환한다.
Greeting 인터페이스에서 이미 greet의 매개 변수인 user와 greeting의 타입과 반환 타입이 작성되어 있기 때문에, greet 함수는 string 타입을 반환한다고 명시하지 않아도 되며, 매개 변수의 타입 또한 작성하지 않아도 된다.
클래스에서도 인터페이스를 사용할 수 있다. 클래스에서는 인터페이스를 아래와 같이 사용한다.
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와 substract 메서드를 정의하고 있고, SimpleCaculator 클래스는 Calculator 인터페이스를 사용하여 작성되었다.
Caculator 인터페이스를 사용하고 있기 때문에 SimpleCaculator 클래스 내에는 Calculator 인터페이스 내에 정의된 두 메서드를 반드시 작성해야 한다.
또 클래스를 구현할 때 인터페이스에서 정의된 함수나 메서드의 매개변수 타입과 반환 값과 일치하도록 구현해야 하므로, 클래스 내부에서 해당 메서드의 매개변수 타입을 다시 한번 더 명시해 주지 않으면 컴파일 에러가 발생하게 된다.
타입 별칭을 이용하여 타입의 새로운 이름을 만들 때 키워드 type을 사용하여 작성한다.
type MyString = string;
let str1: string = 'hello!';
// string 타입처럼 사용할 수 있다.
let str2: MyString = 'hello world!';
이런 방식으로 타입 별칭을 사용하면 코드를 더 간결하고 가독성 좋게 만들 수 있다.
또한 복잡한 타입을 간략하게 표현하고, 타입 정의를 재사용하는 등 가독성을 높일 수 있다.
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 Person = {
name: string;
age: number;
}
interface User {
name: string;
age: number;
}
let kimcoding: Person = {
name: '김코딩',
age: 30,
}
let coding: User = {
name: '김코딩',
age: 30,
}
kimcoding 객체가 참조하고 있는 Person에 마우스를 올리면 Person 내부에 어떤 프로퍼티들이 정의되어 있는지 보인다.
coding 객체가 참조하고 있는 User는 내부에 어떤 프로퍼티들이 정의되어 있는지 보이지 않는다.
또 다음과 같은 type과 interface 차이점이 있다.
type Person = {
name: string;
age: number;
}
interface User {
name: string;
age: number;
}
// 에러가 발생한다.
type Students extends Person {
className: string;
}
// 정상적으로 동작한다.
interface Students extends User {
className: string;
}
// 정상적으로 동작한다.
interface Students extends Person {
className: string;
}
let isNumber = 123;isNumber를 선언하고, 숫자 123을 할당했다.isNumber의 타입을 자동으로 숫자(Number)로 추론한다.
let x = [0, 1, null];x 타입을 추론하려면 각 배열 요소의 타입을 고려해야 힌다.
function add(a: number, b: number) {
return a + b;
}add 함수는 두 개의 매개변수를 받아 더한 값을 반환한다.a와 b가 모두 숫자(Number) 타입이라면, add 함수의 반환 값도 숫자(Number) 타입으로 추론된다.
JavaScript에서 클래스는 ES6(ECMAScript 2015)에서 처음 도입되었다.
클래스를 사용하면 객체를 생성하고 객체의 속성과 메서드를 정의할 수 있다.
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
greet() {
console.log(`안녕하세요, 제 이름은 ${this.name}이고, ${this.age}살 입니다.`);
}
}
Person 클래스는 name과 age 속성을 가지고 greet() 메서드를 정의한다.const person = new Person('Alice', 30);
person.greet(); // "안녕하세요, 제 이름은 Alice이고, 30살 입니다."예를 들어, TypeScript에서는 클래스의 속성과 메서드에 대한 타입을 명시할 수 있다.
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}살 입니다.`);
}
}
name 속성과 age 속성은 문자열과 숫자 타입으로 정의되어 있다.constructor를 이용하여 초기화하는 멤버들은 전부 상단에서 정의를 해줘야 한다.contructor 내 인자로 받을 때도 정확히 타입을 명시해 줘야 한다.const person = new Person('Alice', 30);
person.greet(); // "안녕하세요, 제 이름은 Alice이고, 30살 입니다."TypeScript의 클래스(class)는 인터페이스(interface)와 마찬가지로 기존에 존재하던 클래스를 상속받아 확장하여 새로운 클래스를 만들 수 있다.
이때도 extends 키워드를 사용하여 상속할 수 있다.
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();
Animal이라는 클래스를 Dog라는 클래스가 상속받고 있다.Dog 클래스는 Animal 클래스로부터 프로퍼티와 메서드를 상속받으며,Dog 클래스는 파생 클래스라고도 불리며, 하위클래스(subclasses)라고도 불린다.Animal 클래스는 기초 클래스, 상위클래스(superclasses)라고 불린다.기본적으로 클래스 내에 선언된 멤버는 외부로 공개되는 것이 디폴트 값이다.
그러나 공개된다고 명시적으로도 표시해 줄 수 있는데, 바로 public 키워드를 사용하면 된다.
class Person {
public name: string;
public age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
greet(): void {
console.log(`안녕하세요, 제 이름은 ${this.name}이고, ${this.age}살 입니다.`);
}
}
혹은 외부에 드러내지 않을 멤버가 있다면 private 키워드로 명시해 주면 된다.
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 키워드를 사용하여 프로퍼티를 읽기 전용으로 만들 수 있다.class Mydog {
readonly name: string;
constructor(theName: string) {
this.name = theName;
}
}
let spooky = new Mydog("스푸키");
spooky.name = "멋진 스푸키"; // 에러name이 readonly로 명시되어 있기 때문에, 값을 변경할 수 없다.
그 어렵다는 타스 정리 폼 미쳐따 ㄷ ㄷ 멋쪄요 !!!