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
로 명시되어 있기 때문에, 값을 변경할 수 없다.
그 어렵다는 타스 정리 폼 미쳐따 ㄷ ㄷ 멋쪄요 !!!