티스토리 뷰

TypeScript

특징

  • 오픈소스 프로그래밍 언어(from Microsoft)
  • Typed superset of JavaScript그러니까 자바스크립트의 모든 feature를 포함 + 더 확장된 feature를 포함하는 것이 타입스크립트라는 것
  • superset: A programming language that contains all the features of a given language and has been expanded or enhanced to include other features as well.
  • 타입스크립트로 작성 > 플레인 자바스크립트로 컴파일
  • 커피스크립트와 달리 extended JavaScript
  • 커피스크립트는 자바스크립트가 아닌 새로운 다른 언어지만, 타입스크립트는 .ts확장자를 .js로 바꿔도 사용할 수 있다.
  • 자바스크립트와 달리 타입 서포트를 해주기 때문에 컴파일 시 에러를 미리 잡을 수 있음
  • 타입 지정은 optional해서, 타입 지정을 하지 않더라도 타입스크립트가 타입을 추론해서 에러를 알려준다
  • 향상된 IDE 서포트
  • Intellisense가 잘 돼있다(한국말로 하면 지능형 코드 완성...?)

 

TypeScript 파일 만들기

  1. 일단 타입스크립트 설치잘 설치되었는지 확인하려면 터미널에 tsc -v
  2. npm install -g typescript
  3. 에디터에서 확장자가 ts인 파일을 만든다. (eg. main.ts) TS 코드를 작성한다.
  1. 터미널에서 tsc main.ts 실행하면 컴파일된 main.js파일이 생성된다. (확장자인 ts는 안 써도 된다)
  2. 코드를 실행시키려면 터미널에 node main.js 실행(역시 확장자 생략 가능)
  • Tip: 매번 tsc main 처럼 컴파일 명령 치고 node main 치는 게 귀찮으므로 tsc main --watch 하면 알아서 변화를 감지하고 컴파일한다. 그러니 새로운 터미널을 켜서 node main만 실행시키면 된다.

 

TypeScript의 데이터 타입들

number, string, boolean

별달리 특별한 점은 없다. 변수를 선언하고 뒤에 : 를 쓴 뒤 타입을 명시한다. 사용예는 아래와 같은데, string타입을 사용할 때 템플릿 스트링과 multi 라인을 쓸 수 있다.

let sentence: string = `My name is ${name}
I am a beginner in Typescript`
console.log(sentence);

 

null, undefined

null, undefined 타입도 있는데 서브타입이라 큰 의미는 없는 듯. boolean, number, string 타입에도 null과 undefined를 집어넣을 수 있다.

let sentence1: null = null; 
let sentence2: string = null;

 

Array

배열을 만드는 사용예는 이렇다. 배열 원소의 타입을 지정해줘야 한다. 두 사용예 모두 똑같이 작용한다.

let list1:number[] = [1,2,3]
let list2:Array<number>=[1,2,3]

 

Tuple

타입스크립트의 배열은 정해준 하나의 데이터타입만 원소로 받아야 하지만, 다른 타입을 섞을 수 있는 것도 있다. 그것이 새로운 데이터 타입인 튜플이다.

let person1: [string, number] = ['Chris', 22];

// throw err
let person2: [string, number] = ['Chris', 22, 35];
let person3: [string, number] = [22, 'Chris'];

다만 이렇게 사용하는 경우, 초기화할 때 순서와 원소 개수가 일치해야한다. 즉 스트링, 넘버 순서로 정했으면 그 순서를 지켜야하고, 넘버라고 타입에 한번만 적어줬으면 넘버 원소 한개만 넣어야 된다.

단, push메서드를 사용해서 원소를 추가하려고 할 때 에러가 나지는 않는다. (단 선언된 타입 중 하나라면) 예를 들어 위 person 튜플 예시에서 다른 스트링이나 넘버를 푸시하면 에러 나지 않지만 true를 푸시하려고 하면 에러가 난다.

그리고 타입이 튜플인 array도 만들 수 있다.

let employee: [number, string][] = [[1, 'A'], [2, 'B']]

 

Enum

Enum(enumeration)도 타입스크립트에서 새롭게 서포트하는 데이터 타입이다. enum은 named constant의 집합을 선언할 수 있게 해준다. numeric, string, 복합 enum이 있는데 아래의 예시는 numeric enum이다.

enum Color {Red, Green, Blue};

let c: Color = Color.Green;
console.log(c); // 1

뉴머릭 enum은 각자 숫자값을 갖는데, 아무런 디폴트 값을 설정하지 않으면 마치 인덱스처럼 0부터 하나씩 증가하는 값을 갖는다. 즉 Red는 0, Green은 1, Blue는 2이다.

enum Color {Red = 5, Green, Blue};

let c: Color = Color.Green;
console.log(c); // 6

첫번째 enum을 5로 정해주고 나머지는 정하지 않으면 5부터 하나씩 증가하는 값을 갖는다. 다만 반드시 연속적인 값을 정할 필요는 없다. 그리고 연산식을 넣을 수도 있다.

// 원하는 대로 숫자값을 넣을 수 있다
enum Color {Red = 5, Green = 10, Blue = 5};

enum Color {Red = 5, Green = Red * 2, Blue = 5};

 

Union

유니언은 두가지 이상의 데이터타입을 받아들일 수 있도록 만들어진 데이터타입이다. 밑에서 나오는 any보다는 제한적으로 여러개의 타입을 받아들인다. any보다 나은 점은 어쨌든 타입을 제한할 수 있고, intellisense가 서포트된다는 것이다.

let code: string | number;
code = 123; // OK
code = '123'; // OK
code = false; // ERR!

 

Any

any는 단어에서 알 수 있듯이 모든 데이터 타입을 받을 수 있다는 뜻이다. 플레인 자바스크립트처럼.

// works fine
let randomValue:any = 10;
randomValue = true;
randomValue = 'dy';

 

그래서 아래처럼 써도 에러가 안난다. myVariable에 10을 할당했는데, 함수처럼 실행하려고하거나 스트링에서만 쓸 수 있는 메서드를 써도 컴파일 에러가 안난다. 대신 플레인 자바스크립트를 실행할 때 런타임 에러가 나지만. (그러니까 any타입의 변수는 플레인 자바스크립트처럼 행동한단 소리이고, 타입스크립트를 사용하는 취지로서는 바람직하지는 않다)

// No error when compiling 
let myVariable: any = 10;
console.log(myVariable.name);
myVariable();
myVariable.toUpperCase();

그래서 이것과 비슷한 unknown을 사용할 수 있다.

 

unknown

unknown 또한 any처럼 어떤 데이터타입을 값으로 초기화해도 된다. 다만 any 예시에서 본 것처럼 똑같이 쓰면 컴파일 에러가 난다.

// Throw errors
let myVariable: unknown = 10;
console.log(myVariable.name);
myVariable();
myVariable.toUpperCase();
Property 'name' does not exist on type 'unknown'
This expression is not callable. Type '{}' has no call signatures.
Property 'toUpperCase' does not exist on type 'unknown'

 

다만 이런 식으로 타입캐스팅(?)을 하면 컴파일 에러는 안나지만 런타임에러가 난다.

// similar to typecasting
(myVariable as string).toUpperCase();

 

function

함수도 패러미터 타입과 리턴 타입을 정할 수 있다.

function hasName(obj: any): obj is {name: string} {
    return !!obj && typeof obj == 'object' && "name" in obj
}

let myVariable: unknown = 10;
if(hasName(myVariable)) console.log(myVariable.name);

 

패러미터는 옵셔널하게 정할 수 있다. 패러미터 뒤에 ? 를 붙이면 옵셔널이란 뜻이다. 옵셔널 패러미터는 순서상 required 패러미터 뒤에 위치해야 한다.

// 리턴타입 지정 가능
function add(num1: number, num2: number):number {
    return num1+num2;
}
// 패러미터 옵셔널
function add(num1: number, num2?: number):number {
    return num1+num2;
}
add(5) // It works without err but throws NaN. num2 is undefined.

// prevent undefined
function add(num1: number, num2?: number):number {
    if(num2) return num1 + num2;
    return num1;
}

function add(num1: number, num2: number = 10):number {
    if(num2) return num1 + num2;
    return num1;
}

 

Interface

function fullName(person: {firstName: string, lastName: string}) {
    console.log(`${person.firstName} ${person.lastName}`)
}

let p = {
    firstName: 'k',
    lastName: 'dy'
}

fullName(p); // log k dy

지금 오브젝트 프로퍼티가 2개밖에 없지만 만약에 5개로 늘어난다고 가정하면 함수에 parameter를 쓸 때 매우 길어진다.

게다가 비슷한 함수가 계속 늘어나게 되면 유지보수가 힘들어 질 것이다.

그래서 인터페이스가 필요하다.

interface Person {
    firstName: string,
    lastName: string
}

function fullName(person: Person) {
    console.log(`${person.firstName} ${person.lastName}`)
}

let p = {
    firstName: 'k',
    lastName: 'dy'
}

fullName(p)

함수처럼 인터페이스도 옵셔널 프로퍼티를 갖게할 수 있고 똑같이 ?를 붙이면 된다.

// 옵셔널 프로퍼티를 갖도록 할 수도 있다
interface Person {
    firstName: string,
    lastName?: string
}

function fullName(person: Person) {
    console.log(`${person.firstName} ${person.lastName}`)
}

let p = {
    firstName: 'k'
}

fullName(p)

유저 인풋을 받을 때에(eg. 회원가입폼) 어떤 항목은 필수고 어떤 항목은 필수가 아닐 수 있는데, 이런 경우 인터페이스에서 옵셔널 프로퍼티로 정하면 된다.

 

Class

이 클래스 문법은 자바랑 같다.

class Employee {
    employeeName: string;

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

    greet() {
        console.log(`Welcome! ${this.employeeName}`)
    }
}

let employee1 = new Employee('kdy')
employee1.greet(); // Welcome! kdy

 

Inheritance

class Manager extends Employee{
    constructor(managerName: string) {
        super(managerName);
    }
    delegateWork() {
        console.log(`Manager delegating tasks`)
    }
}

let m1 = new Manager('kang')
m1.delegateWork(); // Manager delegating tasks
m1.greet(); // Welcome! kang
console.log(m1.employeeName); // kang

임플로이를 상속받는 매니저클래스도 임플로이 컨스트럭터를 초기화하기 위해 super 메서드를 사용한다.

매니저 인스턴스를 생성하면 매니저 컨스트럭터는 임플로이 이름 프로퍼티(employeeName)를 초기화하기 위해서 임플로이 컨스트럭터를 호출한다.

 

Access Modifier

private으로 선언하면 클래스 외에서는 접근이 불가능하고 상속받는 클래스 내부에서도 부를 수 없다

상속받은 클래스에서 접근 가능하게 하고 싶으면 protected 로 선언해야 한다.

즉 employeeName을 매니저 클래스 내에서 쓰려면 Employee 클래스 내에서 employeeName이 protected로 선언되어 있어야 하고 private이면 에러가 난다.

// It works when employeeName has protected modifier not private
class Manager extends Employee{
    constructor(managerName: string) {
        super(managerName);
    }
    delegateWork() {
        console.log(`${this.employeeName} Manager delegating tasks`)
    }
}

 

 

'공부일지(TIL) > JavaScript' 카테고리의 다른 글

자바스크립트 스코프(Scope)  (0) 2019.10.10
[TypeScript] 타입스크립트의 장점  (0) 2019.09.16
ES6 모듈 시스템  (0) 2019.08.09
프로미스의 활용  (0) 2019.08.07
useEffect 이해하기  (2) 2019.08.05
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/04   »
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 26 27
28 29 30
글 보관함