티스토리 뷰

TypeScript 언어 핵심 요약 사항

TypeScript 핵심 요약은 ES6 에 추가된 기능과 중복된 항목이 있다. TypeScript 는 Javascript 의 슈퍼셋(Superset)이라고 하지만, 아직 ES6 를 완벽하게 지원하지 않는다. 그래서 본 글의 핵심 요약은 TypeScript 에서 추가된 기능이자 ES6 와 중복된 내용이 있다.

ES6 의 새로운 기능은 다음의 링크에서 참고하기 바란다.

TypeScript 2.1 최신이고 아직 꾸준히 업데이트 중이며, 1.8 버전을 기준으로 비교된 ES6 와 호환 테이블이다.

TypeScript 의 모든 언어 사양은 아래의 링크를 참고하기 바란다.


1. var vs let 키워드

var 키워드는 Javascript 의 그 var 키워드와 동일한 역할을 한다. var 키워드는 function scope 단위로 할당이 된다. 그래서 아래의 예제와 같이 원하지 않는 결과를 얻을 수도 있다.

일반적으로 사용하는 방법은 Javascript 의 var 와 동일하게 사용하면 되고, TypeScript 에서는 되도록 let 을 쓰도록 권장하고 있다.

var 키워드

for (var i = 0; i < 10 ; i++) {
    setTimeout(function() { console.log(i); }, 100 * i);
}
10
10
10
10
10
10
10
10
10
10

let 키워드

for (let i = 0; i < 10 ; i++) {
    setTimeout(function() { console.log(i); }, 100 * i);
}
0
1
2
3
4
5
6
7
8
9

2. Indexable 타입

C# 의 인덱서와 동일한 역할을 하는 Indexable 타입이 있다. Cars 인터페이스가 배열/컬렉션 객체가 아니지만, 마치 배열/컬렉션 객체의 아이템을 가져오는 것처럼, 인덱서를 사용할 수 있다.

interface Cars {
    [num: number]: string;
}

let cars: Cars;
cars = ["Cadillac", "Benz", "BMW", "Audi"];

console.log(cars[0]);

3. Hybrid 타입

인터페이스에 함수를 인터페이싱 하는 방법 중의 하나다. (start: number): string; 는 익명 함수를 선언하고 있고, reset() 은 명시적으로 함수를 선언하고 있다. <Counter> 는 캐시팅을 명시적으로 지정하였으며 counter 변수는 Counter 객체로 캐스팅 된다.

interface Counter {
    (start: number): string;
    interval: number;
    reset(): void;
}

function getCounter(): Counter {
    let counter = <Counter>function (start: number) { };
    counter.interval = 123;
    counter.reset = function () { };
    return counter;
}

let c = getCounter();
c(10);
c.reset();
c.interval = 5.0;

4. protected 키워드

객체지향언어의 protected 키워드와 동일한 역할을 한다. 클래스 맴버가 상속받은 자식 클래스에만 노출이 된다.

class Person {
    protected name: string;

    constructor(name: string) {
        this.name = name;
    }
}

class Student extends Person {
    constructor(name: string) {
        super(name);
    }

    say(): void {
        console.log(this.name);
    }
}

let student: Student = new Student("POWERUMC");

student.say();
student.name = "POWERUMC"; // Error

5. Optional and Default 파라메터(Parameters)

Optional 파라메터(Parameters)

기본적으로 TypeScript 는 Javascript 함수처럼 가변적인 매개변수를 지정하여 함수를 호출할 수 없다. (아래 6번에서 가능한 방법을 설명한다.) 여타 객체지향언어처럼 매개변수와 타입에 맞게 호출하는 것이 객체지향언어의 규약이다.

마찬가지로 TypeScript 에서도 함수를 호출하려면 타입에 맞아야 한다.

function test(src:string, dest:string): boolean {
    return src === dest;
}

test("P", "P");
test("P");          // Error

이를 Optional 매개변수로 만들기 위해서 dest? 로 지정하면 된다. dest? 매개변수에는 undefined 가 된다.

function test(src:string, dest?:string): boolean {

    console.log(dest);
    return src === dest;
}

test("P", "P");
test("P");          // Ok

Default 파라메터(Parameters)

Default 파라메터로 만들기 위해 dest = "" 와 같이 리터럴 상수값을 선언하면 된다.

function test(src:string, dest = ""): boolean {

    console.log(dest);
    return src === dest;
}

test("P", "P");
test("P");          // Ok

6. 가변적인 매개변수(Rest Parameters)

...restOfName 처럼 매개변수 이름 앞에 ...을 붙이면 가변적인 매개변수가 된다.

function buildName(firstName: string, ...restOfName: string[]) {
    return firstName + " " + restOfName.join(" ");
}

let employeeName = buildName("Joseph", "Samuel", "Lucas", "MacKinzie");
function buildName(firstName: string, ...restOfName: string[]) {
    return firstName + " " + restOfName.join(" ");
}

let buildNameFun: (fname: string, ...rest: string[]) => string = buildName;

7. 오버로드(Overloads)

첫 번쨰 pickCard 함수는 명시적으로 object 리터럴로 감싸고 number 타입을 반환하는 함수이고, 두 번째 pickCard{suit: string; card: number; } 타입을 반환하는 함수이다.

세 번째 pickCard 함수가 메인 함수인데, 타입을 체크하여 각각 처리 후 결과를 반환하는데 반환 타입이 다르다는 것을 알 수 있다.

let suits = ["hearts", "spades", "clubs", "diamonds"];

function pickCard(x: {suit: string; card: number; }[]): number;
function pickCard(x: number): {suit: string; card: number; };
function pickCard(x): any {
    if (typeof x == "object") {
        let pickedCard = Math.floor(Math.random() * x.length);
        return pickedCard;
    }
    else if (typeof x == "number") {
        let pickedSuit = Math.floor(x / 13);
        return { suit: suits[pickedSuit], card: x % 13 };
    }
}

let myDeck = [{ suit: "diamonds", card: 2 }, { suit: "spades", card: 10 }, { suit: "hearts", card: 4 }];
let pickedCard1 = myDeck[pickCard(myDeck)];
alert("card: " + pickedCard1.card + " of " + pickedCard1.suit);

let pickedCard2 = pickCard(15);
alert("card: " + pickedCard2.card + " of " + pickedCard2.suit);

8. 제네릭(Generics)

C# 의 '제네릭(Generics)' 또는 C++ 의 '템플릿(Tempaltes)' 는 코드 재사용성을 높이고, 타입 안정성, 그리고 성능에서 큰 이점을 준다.

TypeScript 또한 이러한 이점을 그대로 얻을 수 있다.

제네릭 함수(Generic Functions)

function identity<T>(arg: T): T {
    return arg;
}
function identity<T>(arg: T): T {
    return arg;
}

let myIdentity: <T>(arg: T) => T = identity;
function identity<T>(arg: T): T {
    return arg;
}

let myIdentity: <U>(arg: U) => U = identity;
function identity<T>(arg: T): T {
    return arg;
}

let myIdentity: {<T>(arg: T): T} = identity;
interface GenericIdentityFn {
    <T>(arg: T): T;
}

function identity<T>(arg: T): T {
    return arg;
}

let myIdentity: GenericIdentityFn = identity;

제네릭 클래스 (Generic Classes)

class GenericNumber<T> {
    zeroValue: T;
    add: (x: T, y: T) => T;
}

let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function(x, y) { return x + y; };
interface Lengthwise {
    length: number;
}

function loggingIdentity<T extends Lengthwise>(arg: T): T {
    console.log(arg.length);  // Now we know it has a .length property, so no more error
    return arg;
}

9. Nullable Types

let s = "foo";
s = null; // error, 'null' is not assignable to 'string'
let sn: string | null = "bar";
sn = null; // ok

sn = undefined; // error, 'undefined' is not assignable to 'string | null'
function f(x: number, y?: number) {
    return x + (y || 0);
}
f(1, 2);
f(1);
f(1, undefined);
f(1, null); // error, 'null' is not assignable to 'number | undefined'
class C {
    a: number;
    b?: number;
}
let c = new C();
c.a = 12;
c.a = undefined; // error, 'undefined' is not assignable to 'number'
c.b = 13;
c.b = undefined; // ok
c.b = null; // error, 'null' is not assignable to 'number | undefined'

10. for..of 과 for..in 구문(statements)

for..in 구문은 배열의 키 값을 반환하는 한편, for..of 구문은 배열의 항목을 반환하는 다른점이 있다.

따라서 for..of 구문을 사용하는 것을 권장한다.

let list = [4, 5, 6];

for (let i in list) {
   console.log(i); // "0", "1", "2",
}

for (let i of list) {
   console.log(i); // "4", "5", "6"
}

11. 데코레이터(Decorators)

데코레이터(Decorators)는 C# 의 특성(Attributes), Java 의 어노테이션(Annotations) 와 같이 클래스나 함수에 선언적으로 정보를 지정할 수 있다.

reflect-metadata 모듈을 이용하면 런타임에 리플랙션을 이용하여 이 데코레이터의 정보를 얻어와서 처리를 하는 방법도 있다.

function f() {
    console.log("f(): evaluated");
    return function (target, propertyKey: string, descriptor: PropertyDescriptor) {
        console.log("f(): called");
    }
}

function g() {
    console.log("g(): evaluated");
    return function (target, propertyKey: string, descriptor: PropertyDescriptor) {
        console.log("g(): called");
    }
}

class C {
    @f()
    @g()
    method() {}
}
f(): evaluated
g(): evaluated
g(): called
f(): called


댓글