[TypeScript] 타입스크립트란?

유동균·2023년 2월 10일
0

TypeScript

목록 보기
1/3
post-thumbnail

TypeScript 공식 문서

1. 자바스크립트와 타입스크립트의 관계

  • 웹 브라우저에서 동작하는 표준 자바스크립트인 ES5
  • 2015년부터 매년 새로운 버전을 발표하는 ESNext
  • ESNext에 타입기능을 추가한 타입스크립트

타입스크립트는 자바스크립트의 모든 문법을 포함한다.
따라서 타입스크립트로 개발했더라도 타입 기능을 사용하지 않는다면 자바스크립트 소스나 마찬가지이다.

  • 구문 (Syntax)

    • 타입스크립트는 자바스크립트의 구문이 허용되는, 자바스크립트의 상위 집합 언어
    • 자바스크립트 코드를 타입스크립트 파일에 넣어도 잘 작동한다.
      // Syntax error TS1005: ')' expected.
      let a = (4
  • 타입 (Types)

    • 타입스크립트는 다른 종류의 값들을 사용할 수 있는 방법이 추가된, 타입이 있는 상위 집합
    • 실제로 어떤 일이 일어나는지 보려는 의도로 숫자를 배열로 나눌 수 있지만, 대부분은 프로그래밍 실수이다.
    • 타입스트립트의 타입 검사자는 일반적인 오류를 최대한 많이 검출하면서 올바른 프로그램을 만들 수 있게 설계되어있다.
          // Types error TS2363: The right - hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type.
          console.log(4 / []);
  • 런타임 특성 (Runtime Behavior)

    • 타입스크립트는 JavaScript의 런타임 특성을 가진 프로그래밍 언어이다.
    • 자바스크립트에서 0으로 나누는 행동은 런타임 예외로 처리하지 않고 Infinity값을 반환한다.
    • 논리적으로, 타입스크립트는 자바스크립트 코드의 런타임 특성을 절대 변화시키지 않는다.
    • 즉, 타입스크립트가 코드에 타입 오류가 있음을 검출해도, 자바스크립트 코드를 타입스크립트로 이동시키는 것은 같은 방식으로 실행시킬 것을 보장한다는 의미이다.
    • 자바스크립트와 동일한 런타임 동작을 유지하는 것은 프로그램 작동을 중단시킬 수 있는 미묘한 차이를 걱정하지 않고 두 언어 간에 쉽게 전환할 수 있도록 하기 위한 타입스크립트의 기본적인 약속이다.
  • 삭제된 타입 (Erased Types)

    • 타입스크립트의 컴파일러가 코드 검사를 마치면 타입을 삭제해서 결과적으로 “컴파일된” 코드를 만든다.
    • 즉, 코드가 한 번 컴파일되면, 결과로 나온 일반 자바스크립트 코드에는 타입 정보가 없다.
    • 타입 정보가 없는 것은 타입스크립트가 추론한 타입에 따라 프로그램의 특성을 변화시키지 않는다는 의미이다.
    • 결론적으로 컴파일 도중에는 타입 오류가 표출될 수 있지만, 타입 시스템 자체는 프로그램이 실행될 때 작동하는 방식과 관련이 없다.

1.1 자바스크립트의 문제점

  • 자바스크립트의 동일 연산자는 == 인수를 강제로 변환하여(coerces), 예기치 않은 동작을 유발한다.
console.log("" == 0);	// true

var foo = 2;
console.log(1< x < 3);	// x가 2가 아닌 어떤 값이더라도 항상 true	
  • 자바스크립트는 존재하지 않는 프로퍼티의 접근을 허용한다.
const obj = { width: 10, height: 15 };

const area = obj.width * obj.heigth; // obj 객체에는 heigth라는 프로퍼티가 없음.
console.log(area);	// NaN
  • 문자 타입과 숫자 타입 암묵적 형변환
function add(num1, num2) {
	return num1 + num2;
}

console.log(add(1,"2"));	// 12

// if문을 추가해서 입력 타입 검사를 해야함

대부분의 프로그래밍 언어들은 위와같은 오류들이 발생하면 오류를 표출하거나,
코드가 실행되기 전인 컴파일 중 오류를 표출한다.

컴파일러(Complier)란?

  • 프로그래밍 언어(고급언어)를 컴퓨터가 이해 할 수 있는 기계어로 변환시키는 과정
    • 소스코드 → 바이너리 코드으로 변환

2. 타입스크립트

  • 타입스크립트는 마이크로소프트가 개발한 오픈소스 프로그래밍 언어이자 자바스크립트 슈퍼셋이다.

    Superset - 기존의 언어에서 가지고 있는 기능을 확장하고 새로운 기능을 추가한 언어를 말한다.

  • 즉, 타입스크립트는 자바스크립트를 기반으로 하는 프로그래밍 언어.
  • 타입스크립트는 브라우저와 같은 자바스크립트 환경에서 실행할 수 없다.(브라우저 & Node.js는 타입스크립트를 실행할 수 없음.)
  • 타입스크립트는 도구이도 하다.
    즉, 코드를 실행하여 타입스크립트 코드를 자바스크립트로 컴파일하는 컴파일러라는 의미.
  • 타입스크립트의 기능을 추가하기 위해서는 기능들을 자바스크립트 해결책으로 컴파일하는 타입스크립트 컴파일러를 사용해야한다.

2.1 타입스크립트의 기능

2.1.1 정적 타입 검사자 (Static Type Checker)

  • 프로그램을 실행시키지 않으면서 코드의 오류를 검출하는 것을 정적 검사라고 한다.
  • 어떠한 것이 오류인지와 어떠한 것이 연산 되는 값에 기인하지 않음을 정하는 것이 정적 타입 검사이다.

정적 타입 검사자인 타입스크립트는 프로그래을 실행시키기 전에 값의 종류를 기반으로 프로그램의 오류를 찾는다.
즉, 코드 작성과 디버깅을 더욱 편리하게 할 수 있다.

// 오류의 이유는 obj의 타입 때문.

// @errors: 2551
const obj = { width: 10, height: 15 };
const area = obj.width * obj.heigth;

자바스크립트는 동적 타입 언어이며, 변수의 타입을 지정하지 않고 사용할 수 있다.
따라서, 실행 시점에 타입 오류를 찾는다.

2.1.2 자동 타입 추론

  • 타입을 명시하지 않아도 타입스크립트가 자동으로 타입을 추론할 수 있다.
let n: number =1
let m = 2	// 타입을 생략해도 대입 연산자(=)의 우항을 분석해 좌항 변수의 타입을 결정함

2.1.3 클래스와 인터페이스

  • 객체지향 프로그래밍을 구현할 수 있다.

  • 클래스(Class)

    • 클래스는 객체지향 프로그래밍(Object Oriented Programming, OOP)의 개념에서 객체를 정의하는 데 사용되는 설계 단위이다.
    • 클래스는 새로운 타입을 정의하고 객체를 만드는데 사용된다.
    • 클래스에서는 프로퍼티(property)와 메소드(method)를 정의할 수 있으며, 객체의 상태와 행위를 정의한다.
  • 인터페이스(Interface)

    • 인터페이스는 타입을 정의하는 것이며, 특정 클래스가 어떤 특정 타입의 구현을 갖추고 있는지를 나타내는 데 사용된다.
    • 인터페이스는 프로퍼티와 메소드의 선언만 가지고 있으며, 구현에 대한 정의는 갖지 않는다.
    • 인터페이스를 사용하면 타입의 재사용성을 높일 수 있으며, 각 클래스에 공통적인 규약을 정의할 수 있다.

2.1.4 튜플

  • 튜플은 고정된 길이의 배열이며, 각 요소의 타입이 미리 정의되어 있다.
  • 튜플은 각 요소의 타입을 확인하는 것과 같이 프로그래밍을 할 때 유용한 기능
  • 물리적으로는 배열과 같지만, 배열에 저장된 데이터 타입이 모두 같으면 배열, 다르면 튜플이라 한다.
let tuple: [number, string, boolean] = [7, "hello", true];

2.1.5 제네릭

  • 타입스크립트에서 함수, 클래스, 인터페이스 등의 재사용 가능한 코드를 만드는데 사용되는 기능
  • 제네릭은 어떤 타입의 데이터를 사용할 것인지를 나중에 지정할 수 있는 타입 매개변수를 사용하여 코드를 정의
  • 정의된 코드는 타입스크립트 컴파일러가 타입 체크를 통해 타입 안정성을 보장할 수 있다.
    • 함수에서 어떤 타입의 데이터를 받을 것인지 지정하지 않았다면 어떤 타입의 데이터도 전달될 수 있지만, 제네릭을 사용하면 특정 타입의 데이터만 받도록 제한할 수 있다.
// T 매개변수는 배열안에 저장될 타입을 의미
function sumArray<T>(arr: T[]) : T {
  let sum = 0;
  for (const item of arr) {
    sum += item;	// 각각의 아이템을 더해서 최종적으로 한 값을 반환
  }
  return sum;
}

const numbers = [1, 2, 3, 4, 5];
const answer = sumArray<number>(numbers);
console.log(answer); // 15
  • 이 함수는 어떤 타입의 배열을 전달하더라도 정상적으로 동작

2.1.6 모듈

  • 모듈을 사용하면 코드를 여러 개 파일로 분할해서 작성 가능.
  • 변수나 함수, 클래스 등에 export 키워드를 사용해 모듈로 만들어서 다른 파일에서 사용.
  • 만들 모듈을 불러 올 때에는 import 키워드 사용
// greet.ts
export function greet(name: string) {
  return `Hello, ${name}!`;
}

// main.ts
import { greet } from './greet';

console.log(greet('TypeScript'));
  • greet.ts 파일에서는 greet 함수를 정의하고 export 키워드를 사용하여 외부 모듈에서 사용할 수 있도록 공개.
  • main.ts 파일에서는 greet 함수를 가져오기 위해 import 키워드를 사용한다. 이 파일에서는 greet 함수를 호출하여 결과를 출력한다.
  • 위의 예제를 컴파일하여 자바스크립트 파일을 생성하면 다음과 같은 자바스크립트 코드가 만들어진다.
// greet.js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
function greet(name) {
    return "Hello, " + name + "!";
}
exports.greet = greet;

// main.js
"use strict";
var greet_1 = require("./greet");
console.log(greet_1.greet('TypeScript'));

2.1.7 네임스페이스

  • 네임스페이스는 개념적으로 같은 이름의 변수, 함수, 인터페이스 등을 그룹으로 묶는 것을 의미.
  • 아래의 코드는 다음과 같은 코드는 네임스페이스 MySpace에 greet 함수를 정의하는 것.
namespace MySpace {
  export function greet(name: string) {
    console.log(`Hello, ${name}!`);
  }
}

MySpace.greet("John");  // Output: Hello, John!
  • 위 예제에서, MySpace 네임스페이스 내부에 있는 함수 greet를 호출할 때는 MySpace를 이용해야 한다.
  • 이렇게 하면 전역 스코프에서 같은 이름의 변수나 함수가 충돌하지 않게 할 수 있다.

2.1.8 강화된 제어문

2.1.8.1 if

let num: number = 10;

if (num > 0) {
  console.log(`${num} is positive.`);
} else {
  console.log(`${num} is non-positive.`);
}

2.1.8.2 switch

let color: string = 'red';

switch (color) {
  case 'red':
    console.log('The color is red.');
  	break;
  case 'blue':
	console.log('The color is blue.');
  	break;
  default:
	console.log(The color is ${color}.);
  	break;
}

2.1.8.3 for

for (let i: number = 0; i < 10; i++) {
console.log(The value of i is ${i}.);
}

2.1.8.4 while

let i: number = 0;

while (i < 10) {
console.log(The value of i is ${i}.);
i++;
}

2.1.8.5 do-while

let i: number = 0;

do {
  console.log(`The value of i is ${i}.`);
  i++;
} while (i < 10);

2.1.8.6 for-in

const person: { name: string, age: number, location: string } = {
name: 'John Doe',
age: 32,
location: 'Seoul'
};

for (const key in person) {
console.log(${key}: ${person[key]});
}

for (const key in person) {
console.log(${key}: ${person[key]});
}

2.1.8.7 for-of

const numbers: number[] = [1, 2, 3, 4, 5];

for (const number of numbers) {
console.log(`The number is ${number}.`);
}

2.1.9 타입 검사

  • 개발자가 변수나 함수의 입력값과 리턴 값의 타입을 지정할 수 있는 기능
function add(a: number, b: number): number {
  return a + b;
}
  • 여기서 a와 b의 타입은 number이며, add 함수의 리턴 타입도 number.
  • add 함수에 다른 타입의 값이 전달된다면, 컴파일 시점에 타입 오류가 발생.
  • 이는 개발자가 코드를 작성하는 동안 미리 오류를 찾을 수 있는 장점을 제공.

2.1.10 자동 완성

  • 자동완성 기능은 개발자가 코드를 작성하는 동안 일어날 수 있는 실수를 줄이는 기능.
  • 예를 들어, 변수의 이름을 입력하는 동안 해당 변수와 관련된 정보 (타입, 속성, 메서드 등)를 자동으로 제안해주는 기능이 있다.
  • 또한, 타입스크립트에서는 함수의 입력값의 타입과 리턴 값의 타입을 미리 지정할 수 있다.
  • 개발자가 해당 함수를 호출하는 동안 필요한 입력값과 예상되는 리턴 값의 타입을 자동으로 제안해주는 기능도 있다.
  • 자동완성 기능은 개발자의 프로그래밍 생산성을 높이고, 오타나 실수를 줄이는 데 도움을 줌.

2.1.11 안정성

  • 타입스크립트 컴파일러가 코드의 타입을 검사하여 컴파일 시점에 타입 오류를 잡아낼 수 있도록 해주는 기능.
  • 이를 통해 개발자는 실행 중에 발생하는 런타임 오류를 최소화하고, 코드의 안정성과 유지보수성을 높일 수 있다.
  • 예를 들어, 타입스크립트에서는 변수의 타입을 명시해야 하는데, 이를 통해 개발자는 해당 변수에 올바른 타입의 값만 대입할 수 있도록 강제할 수 있다.
  • 만약, 타입이 다른 값을 대입하려 할 경우 컴파일 시점에 타입 오류를 잡아낼 수 있다.

아래의 기능들은 이후 포스트에서 추가 설명 예정

2.1.12 데코레이터(Decorators)

  • 타입스크립트에서 클래스, 메소드, 프로퍼티, 파라미터 등을 동적으로 수정할 수 있는 기능
  • 데코레이터는 @ 기호를 사용하여 적용할 수 있다.
function log(target: any, key: string) {
  console.log(`${key} 메소드가 호출되었습니다.`);
}

class MyClass {
  @log
  public myMethod() {
    console.log('myMethod 가 호출되었습니다.');
  }
}

const myClass = new MyClass();
myClass.myMethod();

// Output: myMethod 메소드가 호출되었습니다.
//         myMethod 가 호출되었습니다.
  • 위의 예제에서는 log Decorators를 적용하여 myMethod 메소드가 호출될 때마다 메시지가 출력되는 것을 확인할 수 있다.

2.1.13 생성기(generator)

  • 타입스크립트의 generator는 자바스크립트와 동일하게 function* 키워드를 사용하여 정의할 수 있다.
  • 그리고 yield 키워드를 사용하여 값을 반환한다.
function* generateSequence(): IterableIterator<number> {
  let i = 0;
  while (true) {
    yield i++;
  }
}

const sequence = generateSequence();
console.log(sequence.next().value); // 0
console.log(sequence.next().value); // 1
console.log(sequence.next().value); // 2
  • 위의 코드에서 generateSequence 함수는 무한히 값을 반환하는 generator다.
  • next 메서드를 호출할 때마다 yield문에서 정의한 값이 반환된다.

2.1.14 대수타입

  • ADT란, 추상 데이터 타입(Avstract Data Type)을 의미하기도 하지만, 대수 타입(Algebraic Data Type)이라는 의미로도 사용됨.
  • 대수 타입이란, 다른 자료형의 값을 가지는 자료형을 의미함.
  • 타입 스크립트에서 새로운 타입을 정의하는 방식 중 하나이다.
  • 대수 타입에는 크게 합집합 타입(union or sum type)과 교집합 타입(intersection or product type) 두가지가 있다.
  • 합집합 타입의 기호는 |, 교집합 타입의 기호는 &를 사용한다.
type Shape = Circle | Rectangle;

interface Circle {
  type: 'circle';
  radius: number;
}

interface Rectangle {
  type: 'rectangle';
  width: number;
  height: number;
}

function area(s: Shape): number {
  switch (s.type) {
    case 'circle':
      return Math.PI * s.radius * s.radius;
    case 'rectangle':
      return s.width * s.height;
  }
}

const c: Circle = {
  type: 'circle',
  radius: 4
};

const r: Rectangle = {
  type: 'rectangle',
  width: 10,
  height: 5
};

console.log(area(c)); // 50.26548245743669
console.log(area(r)); // 50
  • 위 예제에서 Shape 타입은 Circle 타입과 Rectangle 타입의 합집합 타입입니다.
  • area 함수는 Shape 타입의 파라미터를 받아서 각 모양의 면적을 계산합니다.
  • 그리고 cr 변수는 각각 Circle 타입과 Rectangle 타입입니다.

2.2 Install

  • 타입스크립트 컴파일러 설치
> npm i typescript

> tsc --version
Version 4.9.5

2.3 타입스크립트의 동작 과정

2.3.1 타입스크립트 컴파일러(tsc)에 의한 수행

  1. 개발자가 '타입스크립트 코드'로 작성을 한다
  2. 작성한 타입스크립트 코드는 '타입스크립트 컴파일러(tsc)'를 통해 파싱하여 '타입스크립트 AST 코드'로 변환된다.
  3. '타입 검사기(Typechecker)'를 통하여 파싱 된 '타입스크립트 AST 코드'의 타입을 체크한다.
  4. 타입스크립트 AST의 코드를 '자바스크립트 코드'로 변환한다.

AST(Abstract Syntax tree) : 추상화 문법트리

  • 프로그래밍 언어(고급언어)를 컴파일러를 통해 파싱하여서 AST의 자료 구조형태의 코드로 만들어진다.

2.3.2 자바스크립트 런타임(js engine, node.js)에 의한 수행

  1. 자바스크립트 코드를 '자바스크립트 AST 코드'로 파싱한다.
  2. 자바스크립트 AST를 '바이트 코드'로 변환된다.
  3. 런타임(runtime)이라는 실행환경에서 바이트 코드를 실행한다.

자바스크립트 코드 -> (타입스크립트 컴파일러로 파싱) -> 타입스크립트 AST 코드 -> (타입 검사기로 체크) -> 자바스크립트 코드 -> (파싱) -> 자바스크립트 AST 코드 -> 바이트 코드 -> (런타임) -> 코드 실행

2.3.2.1 참고 사항

  • 타입스크립트를 브라우져에서 실행 시키려면 '자바스크립트 코드' 로 변환하여 수행되어야 한다
    (타입스크립트만으로는 실행이 불가능하다.)

  • 타입스크립트는 '컴파일' 단계에서 타입을 검사하여 사전에 오류 발견이 가능하다
    (자바스크립트 언어의 경우 인터프리티 언어로 ‘런타임' 단계에서 오류가 발견이 된다)

인터프리터(Interpreter)란?

  • 프로그래밍 언어(고급언어)를 컴파일 변환 없이 바로 사용하는 언어를 말한다.
    • 자바스크립트
  • 타입스크립트 IDE툴(VSCode, IntelliJ, ...)을 설치를 하면 미리 발생 가능한 오류에 대해서 확인이 가능하다.

  • 타입스크립트는 인터프리터 언어가 아닌 컴파일 언어이다.
    (자바스크립트는 언어의 변환없는 인터프리터 언어이고, 타입스크립트는 컴파일러가 필요하며 변환이 필요한 컴파일 언어이다)

트랜스 파일러(Transplier)란?

  • 한 언어로 작성된 소스코드를 비슷한 수준의 추상화를 가진 다른 언어로 변환하는것을 말한다
    • 바벨 (ES6+ 코드를 ES5로 트랜스 파일한다), Typescript(Type+Javascript -> javascript)

2.4 타입스크립트 예제

  • 자바스크립트에서 볼수 없는 Error가 나타남.
  1. 10행의 input1.value, input1.valuevalue 속성이 실제로 있는지 확실하지 않음
  • Object is possibly 'null'.ts(2531)
  • 2행과 3행에서 id 선택자를 이용해 요소를 선택하고 있지만,
    타입스크립트는 코드가 작동할지 알 수 없다.(HTML 코드가 작동하는지 확인하기 위해 분석하지 않음.)
    • const input1 = document.querySelector("#num1")!;
    • 위와 같이 !를 추가함으로써 요소를 얻을 것임을 타입스크립트에게 알림(즉, 이것이 결코 null을 야기하지 않음을 알림)
  1. 1번이 성공한다고 해도 value 속성이 있는지 명확하지 않음
  • Property 'value' does not exist on type 'Element'.ts(2339)
    • const input1 = document.querySelector("#num1")! as HTMLInputElement;
    • 위와 같이 as HTMLInputElement을 추가함으로써 input요소임을 알림
  1. 5행의 function add(num1, num2) {...}에서 타입스크립트는 num1, num2의 안에 무엇이 있는지 알지 못하며 어떤 타입의 값이든 될 수 있음을 알림
  • Parameter 'num1' implicitly has an 'any' type, but a better type may be inferred from usage.ts(7044)
    • function add(num1: number, num2: number) {...} 처럼 명시적으로 추가할 수 있다.
  1. 이후 console.log(add(input1.value, input2.value));input1.value, input2.value에 error가 발생하는데
  • Argument of type 'string' is not assignable to parameter of type 'number'.ts(2345) 이는 input 요소의 value 속성에서 얻는 것이 문자열이 됨을 알려줌
    • 따라서, console.log(add(+input1.value, +input2.value));와 같이 숫자 타입으로 수정해줌.
  1. 컴파일
> tsc using-ts.ts
// 컴파일 된 자바스크립트
var btn = document.querySelector("button");
var input1 = document.querySelector("#num1");
var input2 = document.querySelector("#num2");

function add(num1, num2) {
    return num1 + num2;
}

btn.addEventListener("click", function () {
    console.log(add(+input1.value, +input2.value));
});
// 타입스크립트
const btn = document.querySelector("button")!;
const input1 = document.querySelector("#num1")! as HTMLInputElement;
const input2 = document.querySelector("#num2")! as HTMLInputElement;

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

btn.addEventListener("click", function () {
  console.log(add(+input1.value, +input2.value));
});
  1. 자바스크립트 파일이 생기면서 ts파일에 error가 발생하는데, 이는 js, ts 파일을 동시에 사용하지 않을 것이라는것을 이해하지 못하는 것.

0개의 댓글