enum Color {
  Red = 1,  //디폴트 값으론 0, 1, 2, ...으로 지정됨(auto-incrementing)
  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 HttpMethod {
  Get = "GET",  // 숫자형 열거형과 다르게 문자로된 열거형
  Post = "POST",  // 항상 명확한 값
  Put = "PUT",
  Delete = "DELETE",
}
function makeRequest(url: string, method: HttpMethod) {
  // ...
}
makeRequest("/api/data", HttpMethod.Post);
3.역 매핑
열거형에서
key -> value searching
value -> key searching
둘 다 가능(단, 숫자형 열거형에서)
객체의 구조를 정의하기 위해 사용되는 예약어
cf. 예약어란? 프로그래밍 언어에서 이미 문법적인 용도로 사용되고 있어 식별자로 사용할 수 없는 단어 (ex) let, const ...)
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 Greeting {
	(user: User, greeting: string): string;
}
const greet: Greeting = (user, greeting) => {
	return `${greeting}, ${user.name}! Your job : ${user.job}.`;
}
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
 
+ extends 키워드를 사용하여 인터페이스 상속 확장 가능
interface Person {
    name: string;
    age: number;
}
interface Developer extends Person {
    language: string;
}
const person: Developer = {
    language: "TypeScript",
    age: 20,
    name: "Anna",
}
새로운 이름으로 기존의 타입을 참조하는 것
키워드 type
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",  // 프로퍼티는 참조한 type의 프로퍼티를 맞춰야함(다를 시 컴파일 에러)
    },
}
123 -> number로 유추
123, x -> number와 string으로 유추
a+b = ? -> 숫자의 합, number로 유후
장점 : 코드의 가독성 향상, 개발 생산성 향상, 오류 발견 용이성
단점 : 타입 추론이 잘못될 경우 오류 발생, 직접 명시적인 타입 지정이 필요한 경우도 또한 있을 수 있음
JS의 class와 비슷하지만 TS에선 추가된 몇가지 기능이 있음
추가된 기능 일. 클래스의 속성과 메서드에 대한 타입 명시 가능
TypeScript에서 클래스를 정의할 때에는 constructor를 이용하여 초기화하는 멤버들은 전부 상단에서 정의를 해줘야 함
constructor 내 인자로 받을 때도 정확히 타입을 명시해줘야 함
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}살 입니다.`);
  }
}
추가된 기능 이. 인터페이스처럼 기존 존재하는 클래스를 extends 키워드를 사용하여 상속받아 확장 가능
추가된 기능 삼. 클래스 내 멤버는 외부 공개가 디폴트 값! + 공개된다고 명시적으로 표시 가능(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 키워드
프로퍼티를 읽기 전용으로 작성(선언 또는 생성자에서 초기화 해야함)
class Mydog {
    readonly name: string; // 읽기 전용으로 명시
    constructor(theName: string) {
        this.name = theName;
    }
}
let spooky = new Mydog("스푸키");  
spooky.name = "멋진 스푸키"; // 읽기 전용으로 명시되어 있으므로 값 변경 못함 --> 에러