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"
역 매핑은 숫자형 열거형에만 존재하는 특징입니다. 열거형의 키(key)로 값(value)을 얻을 수 있고 값(value)으로 키(key)를 얻을 수도 있습니다.
enum Enum {
A
}
let a = Enum.A;
let nameOfA = Enum[a]; // "A"
타입 별칭(Type Aliases)은 타입의 새로운 이름을 만드는 것
예시1
type MyString = string;
let str1: string = 'hello!';
// string 타입처럼 사용할 수 있습니다.
let str2: MyString = 'hello world!';
예시2
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,
},
};
예시1
type Person = {
name: string;
age: number;
}
interface User {
name: string;
age: number;
}
let kimcoding: Person = {
name: '김코딩',
age: 30,
}
let coding: User = {
name: '김코딩',
age: 30,
}
VSCode로 작성 시, kimcoding 객체가 참조하고 있는 Person(type)에 마우스를 올리면 Person 내부에 어떤 프로퍼티들이 정의되어 있는지 보입니다. 그러나 coding 객체가 참조하고 있는 User(interface)에 마우스를 올리면 User 내부에 어떤 프로퍼티들이 정의되어 있는지 보이지 않습니다.
예시2
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;
}
타입 추론(Type Inference)은 변수나 함수의 타입을 선언하지 않아도 TypeScript가 자동으로 유추하는 기능
let isNumber = 123;
//이 경우, 타입스크립트는 isNumber의 타입을 자동으로 숫자(Number)로 추론합니다.
여러 표현식에서 타입 추론이 발생할 때, 해당 표현식의 타입을 사용하여 "최적 공통 타입"을 계산
let x = [0, 1, null];
//여기서 배열의 타입으로 고를 수 있는 두 가지 후보가 있습니다: number와 null입니다.
//최적 공통 타입 알고리즘은 각 후보의 타입을 고려하여,
//모든 후보의 타입을 포함할 수 있는 타입을 선택
function add(a, b) {
return a + b;
}
add 함수는 두 개의 매개변수를 받아 더한 값을 반환합니다. 하지만 매개변수의 타입이 명시되어 있지 않습니다. 이 경우, 타입스크립트는 매개변수 a와 b의 타입을 자동으로 추론했습니다. 만약 매개변수 a와 b가 모두 숫자(Number) 타입이라면, add 함수의 반환 값도 숫자(Number) 타입으로 추론
코드의 가독성 향상: 타입 추론을 사용하면 코드의 가독성이 향상됩니다. 명시적으로 타입을 지정하지 않아도 코드에서 변수의 타입을 알 수 있기 때문입니다.
개발 생산성 향상: 타입 추론을 사용하면 코드 작성 시간을 단축할 수 있습니다. 명시적으로 타입을 지정하지 않아도 TypeScript가 자동으로 타입을 추론하기 때문입니다.
오류 발견 용이성: 타입 추론을 사용하면 코드의 오류를 발견하는 것이 쉬워집니다. TypeScript는 변수나 함수의 타입을 추론하여 타입 검사를 수행하기 때문입니다.
타입 추론이 잘못될 경우 코드 오류 발생: 타입 추론은 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 속성은 문자열과 숫자 타입으로 정의되어 있습니다. 약간의 차이점은 TypeScript에서 클래스를 정의할 때, constructor를 이용하여 초기화하는 멤버들은 전부 상단에서 정의를 해줘야 한다는 것입니다. 또한 contructor 내 인자로 받을 때도 정확히 타입을 명시해 줘야 합니다.
const person = new Person('Alice', 30);
person.greet(); // "안녕하세요, 제 이름은 Alice이고, 30살 입니다."
객체 생성시
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();
extends 키워드를 사용하여 상속
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}살 입니다.`);
}
}
기본적으로 클래스 내에 선언된 멤버는 외부로 공개되는 것이 디폴트 값입니다. 그러나 공개된다고 명시적으로도 표시해 줄 수 있습니다. 이때 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}살 입니다.`);
}
}
외부에 드러내지 않을 멤버가 있다면 private 키워드로 명시
readonly 키워드를 사용하여 프로퍼티를 읽기 전용으로 만들 수 있습니다. 읽기 전용 프로퍼티들은 선언 또는 생성자에서 초기화해야 합니다.
class Mydog {
readonly name: string;
constructor(theName: string) {
this.name = theName;
}
}
let spooky = new Mydog("스푸키");
spooky.name = "멋진 스푸키"; // 에러
위의 코드는 name이 readonly로 명시되어 있기 때문에, 값을 변경할 수 없습니다. 이런 식으로 변경되면 안 될 값을 readonly로 명시하여 보호할 수 있습니다.