TypeScript (2)

TypeScript (2)

TypeScript의 주요 기능

  1. 타입 선언
  2. Class
  3. Interface
  4. Generic

Type Declaration

1
2
let num: number;
let num2 = 2; // 선언과 동시에 할당할 때는 바로 그 type으로 지정됨
1
2
3
function mult(x: number, y: number): number {
return x * y;
}

Parameter의 type을 모두 명시해준 경우 Return type은 추론이 가능하므로 생략이 가능하다. Type은 any가 나오지 않게끔만 지정하면 된다.

void: return을 하지 않는다. 사실은 undefined가 return되지만 void라고 한다.

Types of TypeScript

From JavaScript: boolean, null, undefined, number, string, symbol, object

Added in TypeScript: array, tuple, enum, any, void, never

void와 never 차이

never는 함수가 종료하지 않아 결코 return하지 않을 때 사용된다. 무한루프 혹은 Error 메시지를 throw할 때 return type이 never이다.

void는 return 값이 없을 뿐이지 함수는 종료한다.

array

1
2
let list1: number[] = [1, 2, 3];
let list2: Array<number> = [1, 2, 3]; // Generic Array Type

tuple

1
2
3
let tuple: [string, number];
tuple = ['hello', 10];
tuple.push('good', 30);

배열인데 고정된 element의 수만큼 type을 미리 선언한다.

enum

1
2
enum Season {Spring, Summer, Fall, Winter};
let s1: Season = Season.Spring;

Class

TypeScript가 지원하는 Class는 ES6의 Class와 유사하지만 몇 가지 고유한 확장 기능을 가진다.

1. Class Definition

ES6 Class와 다르게 constructor 외부, 즉 Class body에 Class field를 미리 선언해야 한다. 그렇지 않으면 Error가 발생한다.

1
2
3
4
5
6
7
8
class Circle {
// Class field 미리 선언
radius: number;

constructor(radius: number) {
this.radius = radius;
}
}

constructor의 parameter에 Access Identifier를 사용하면 아래와 같이 선언할 수 있다.

1
2
3
4
5
class Circle {
constructor(public radius) {
// this.radius = radius;도 안 해줘도 됨
}
}

2. Access Identifier

  • public : Class 내부, Child Class 내부, Class Instance에서 접근 가능
  • protected: Class 내부, Child Class 내부에서 접근 가능
  • private: Class 내부에서만 접근 가능

Access identifier를 지정해주지 않으면 암묵적으로 public이 된다. 따라서 public으로 지정하고자 하는 Member variable과 method는 access identifier를 생략한다.

constructor parameter를 선언할 때 public를 붙이면 할당까지 이루어지고 Class 내부의 member variable이 된다. public을 쓰지 않으면 constructor 내부에서만 참조 가능한 지역 변수가 된다.

3. readonly Keyword

readonly가 선언된 클래스 프로퍼티는 선언할 때 또는 생성자 내부에서만 값을 할당할 수 있다. 그 외의 경우에는 값을 할당할 수 없고 오직 읽기만 가능한 상태가 된다. 상수를 선언할 때 사용한다.

4. static Keyword

메소드 뿐만 아니라 프로퍼티도 static으로 지정할 수 있다.

5. Abstract Class

Abstract class는 하나 이상의 abstract method를 포함하며 일반 method도 가질 수 있다. Abstract method란 구현 없이 method 이름과 type만이 선언된 method를 말한다. 선언시 abstract 키워드를 사용한다.

Abstract class는 직접 instance를 생성할 수 없고 상속만을 위해 사용된다. Abstract class를 상속한 class는 반드시 abstract class의 abstract method를 구현해야 한다.

Interface는 모든 method가 abstract이다.

Interface

Interface는 일반적으로 type check를 위해서 사용된다. 변수, 함수, 클래스에 사용할 수 있다.

Interface는 여러가지 type을 갖는 property로 이루어진 새로운 type을 정의하는 것과 같다. Interface에 선언된 property와 method의 구현을 강제해서 일관성을 유지할 수 있게 한다.

1. Variable and Interface

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Definition of interface
interface Todo {
id: number;
content: string;
completed: boolean;
}

// 변수의 type으로 interface Todo를 선언
let todo: Todo;

// 변수 todo는 Todo interface를 따라야한다.
todo = { id: 1, content: 'typescript', completed: false };

// 함수 parameter를 interface Todo로 선언
function addTodo(todo: Todo) {
...
}

필요에 따라서 새로운 타입을 생성하는 것과 같다. 함수의 parameter 선언시에도 interface를 사용하여 전달되는 argument의 type 형식을 제한할 수 있다.

2. Function and Interface

1
2
3
4
5
6
7
8
9
10
11
// 함수 인터페이스의 정의
interface SquareFunc {
(num: number): number;
}

// 함수 인테페이스를 구현하는 함수는 인터페이스를 따라야 한다.
const squareFunc: SquareFunc = function (num: number) {
return num * num;
}

console.log(squareFunc(10)); // 100

잘 안 씀

3. Class and Interface

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 인터페이스의 정의
interface IPerson {
name: string;
sayHello(): void;
}

/*
인터페이스를 구현하는 클래스는 인터페이스에서 정의한 프로퍼티와 추상 메소드를 반드시 구현하여야 한다.
*/
class Person implements IPerson {
// 인터페이스에서 정의한 프로퍼티의 구현
constructor(public name: string) {}

// 인터페이스에서 정의한 추상 메소드의 구현
sayHello() {
console.log(`Hello ${this.name}`);
}
}

function greeter(person: IPerson): void {
person.sayHello();
}

const me = new Person('Lee');
greeter(me); // Hello Lee

4. Duck Typing

Interface를 implements해서 구현하지 않아도, 해당 interface 내부의 property나 method를 모두 구현하면 type check에서 통과된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
interface IDuck { // 1
quack(): void;
}

class MallardDuck implements IDuck { // 3
quack() {
console.log('Quack!');
}
}

class RedheadDuck { // 4
quack() {
console.log('q~uack!');
}
}

function makeNoise(duck: IDuck): void { // 2
duck.quack();
}

makeNoise(new MallardDuck()); // Quack!
makeNoise(new RedheadDuck()); // q~uack! // 5

Interface IDuck을 명시적으로 implements하지 않은 RedheadDuck의 instance도 IDuck 내부를 완벽하게 구현했다면 type이 IDuck으로 인정된다.

즉, implements 여부가 아니라 interface 구현 여부가 check된다.

5. Optional Property in Interface

Interface 내부에서 ?가 붙은 property는 구현을 생략해도 된다.

1
2
3
4
5
6
interface StudentInfo {
name: string;
number: string;
age? : number;
address? : string;
}

Generic

C나 C++ 등 정적 타입 언어에서는 함수 또는 클래스를 정의할 때 parameter나 return 값의 타입을 선언해야 한다. TypeScript도 정적 타입 언어이므로 정의 시점에 타입을 선언해야하는데, 함수 또는 클래스를 정의할 때 parameter나 return type을 선언하기 어려운 경우가 있다.

TypeScript는 선언시 타입을 지정하지 않으면 any타입이 되어 type check를 할 수 없게 된다. Stack이나 Queue를 구현하는 경우 배열에 어떤 type을 담을 것인지 정의할 때 확정짓기 어렵다. 이런 경우에 Generic을 사용한다.

1
2
3
4
5
6
7
8
9
class Stack<T> {
protected data: Array<T> = [];
push(item: T) {
this.data.push(item);
}
pop(): T {
return this.data.pop();
}
}

위의 class Stack을 정의할 때 타입을 따로 지정하지 않고 <T>를 사용했다. <T>는 Type Paremeter이며 Type의 약자이다. 어느 type이던 사용할 수 있음을 의미한다.

Generic은 선언 시점이 아니라 생성 시점에 타이블 명시해서 다양항 타입을 사용할 수 있도록 하는 기법이다.

1
2
3
function sort<T>(items: T[]): T[] {
return items.sort();
}

위는 함수에서 Generic을 사용한 것이다. 어떤 type으로 이루어지는지는 모르지만 배열을 parameter로 받아서 sorting한 배열을 리턴한다.

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×