TypeScript
의 타입 별칭(Type Aliases)
타입 별칭(Type Aliases)은 타입의 새로운 이름을 만드는 것
새로운 이름으로 기존의 타입을 참조하는 것을 의미
타입 별칭을 이용하여 타입의 새로운 이름을 만들 때 키워드 type
을 사용하여 작성
type MyString = string;
let str1: string = 'hello!';
// string 타입처럼 사용할 수 있습니다.
let str2: MyString = 'hello world!';
원래 string이라는 타입이 존재하고 있어, myString
이라는 새로운 이름을 부여.
myString
과 string
은 동일한 의미를 갖게 됨.이런 방식으로 타입 별칭을 사용하면 코드를 더 간결하고 가독성 좋게 만들 수 있다.
또한 복잡한 타입을 간략하게 표현하고, 타입 정의를 재사용하는 등 가독성을 높일 수 있다.
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
타입과, coding
이 참조하고 있는 User
인터페이스에 각기 마우스를 올려놓아 보았다.
kimcoding
객체가 참조하고 있는 Person
내부에 어떤 프로퍼티들이 정의되어 있는지 보이지만, coding
객체가 참조하고 있는 User
에 내부에 어떤 프로퍼티들이 정의되어 있는지 보이지 않는다.따라서 타입 별칭으로 정의한 타입으로 작성할 시에는 조금 더 편하게 코드를 작성할 수 있게 된다.
// 이러한 차이점이 있다.
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;
}
TypeScript
의 타입 추론(Type Inference)
TypeScript는 정적타입을 지원하는 프로그래밍 언어
(Type Inference)
의 기본타입 추론(Type Inference)
은 변수나 함수의 타입을 선언하지 않아도 TypeScript가 자동으로 유추하는 기능.let isNumber = 123;
isNumber
를 선언123
을 할당isNumber
의 타입을 자동으로 숫자(Number)
로 추론(Best common type)
"최적 공통 타입"
을 계산.let x = [0, 1, null];
x
타입을 추론하려면 각 배열 요소의 타입을 고려해야 한다. number
와 null
있다.(Contextual Typing)
function add(a, b) {
return a + b;
}
add
함수는 두 개의 매개변수를 받아 더한 값을 반환.a
와 b
의 타입을 자동으로 추론했다.a
와 b
가 모두 숫자(Number) 타입이라면, add
함수의 반환 값도 숫자(Number) 타입으로 추론된다.TypeScript
의 클래스(Class)
JavaScript와 TypeScript 모두 객체 지향 프로그래밍을 지원하며 클래스(class)
를 사용하여 객체를 생성할 수 있다.
그러나 두 언어의 클래스는 몇 가지 차이점이 있다.
JavaScript
에서의 클래스(Class)
JavaScript에서 클래스를 사용하면 객체를 생성하고 객체의 속성과 메서드를 정의할 수 있다.
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)
TypeScript의 클래스는 JavaScript의 클래스와 비슷하지만 몇 가지 추가된 기능이 있다.
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살 입니다."
(Inheritance)
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, private
키워드기본적으로 클래스 내에 선언된 멤버는 외부로 공개되는 것이 디폴트 값.
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
키워드readonly
키워드를 사용하여 프로퍼티를 읽기 전용으로 만들 수 있다.
읽기 전용 프로퍼티들은 선언 또는 생성자에서 초기화해야 한다.
class Mydog {
readonly name: string;
constructor(theName: string) {
this.name = theName;
}
}
let spooky = new Mydog("스푸키");
spooky.name = "멋진 스푸키"; // 에러
name
이 readonly
로 명시되어 있기 때문에, 값을 변경할 수 없다.
이런 식으로 변경되면 안 될 값을 readonly
로 명시하여 보호할 수 있다.