현재 오즈코딩스쿨 강의를 통해 프론트엔드를 학습하고 있습니다.
본 포스트는 해당 강의에 대한 내용 정리를 목적으로 합니다.
TypeScript 는 JavaScript 의 상위 집합(super set)으로, 자바스크립트의 모든 기능을 포함하면서 추가적인 기능을 제공합니다.
정적 타입 검사
컴파일러(Compiler)
슈퍼셋(Superset)
TypeScript는 Microsoft에서 개발한 오픈 소스 프로그래밍 언어입니다. 대규모 프로젝트에서 코드의 유지보수성과 가독성을 높이는 것을 목표로 합니다. TypeScript 는 개발자들에게 강력한 도구를 제공하여 코드 작성 시 타입을 명시하고, 컴파일 단계에서 타입 오류를 확인할 수 있게 합니다. 이를 통해 런타임 오류를 줄이고, 더 안전하고 신뢰성 있는 코드를 작성할 수 있습니다.



TypeScript는 2023년 Github 기준 가장 많이 사용되고(3위) 사용량이 가장 많은 언어(3위) 중 하나입니다.

현대 프로그래밍 언어에서 TypeScript와 JavaScript의 관계는 꽤 독특합니다. TypeScript는 JavaScript 위에 추가된 레이어로, JavaScript의 기능을 제공하면서 추가적인 타입 시스템을 갖추고 있습니다.
JavaScript는 string, number, object, undefined 같은 기본 타입을 가지고 있지만, 코드 전체에서 일관되게 타입이 사용되었는지 미리 확인해 주지 않습니다. TypeScript는 이런 점을 해결하기 위해 존재합니다.
따라서 기존의 JavaScript 코드는 그대로 사용 가능하지만, TypeScript의 타입 검사기를 사용하면 코드에서 의도와 실제 동작 사이의 차이를 미리 발견할 수 있습니다.

function greet(name) {
if (typeof name !== 'string') {
throw new Error('Name must be a string');
}
return `Hello, ${name}!`;
}
try {
console.log(greet('Alice')); // Hello, Alice!
console.log(greet(42)); // Error: Name must be a string
} catch (error) {
console.error(error.message);
}
greet 함수는 name 인수가 문자열인지 확인하고, 문자열이 아니면 런타임에 오류를 던집니다.greet(42) 호출 시, 런타임에 오류가 발생합니다.function greet(name: string): string {
return `Hello, ${name}!`;
}
console.log(greet('Alice')); // Hello, Alice!
console.log(greet(42)); // Compile-time error: Argument of type 'number' is not assignable to parameter of type 'string'.
greet 함수는 name 인수가 문자열임을 타입으로 명시합니다.greet(42) 호출 시, 컴파일러가 타입 오류를 감지하여 컴파일 시점에 오류를 발생시킵니다.위와 같이 TypeScript를 사용하면 타입 시스템을 통해 컴파일 시점에 더 많은 오류를 잡아낼 수 있습니다. 이는 코드의 안전성을 높이고, 유지보수를 용이하게 합니다. JavaScript는 동적 언어로 유연하지만, 타입 관련 오류를 런타임에 처리해야 하므로, TypeScript의 정적 타입 시스템을 사용하면 더 많은 오류를 예방할 수 있습니다.
node -v 입력 후 node의 버전이 출력되면 설치가 된 것입니다.TypeScript 설치 링크 에서 설치를 진행합니다.

프로젝트마다 TypeScript를 설치하고 싶다면 npm install typescript --save-dev를 입력합니다

전역으로 TypeScript를 설치하고싶다면 npm install -g typescript 를 입력합니다. 설치가 잘 되었는지 확인하고 싶다면 터미널에서 tsc -v 를 입력해봅니다. 버전이 출력되면 설치가 잘 된것입니다.
컴파일이 잘 동작하는지 간단한 코드를 작성해서 확인해보겠습니다. test 폴더 생성 → index.ts 파일 생성 후 아래 코드를 작성해줍니다.
function hello(name: string) {
console.log(`Hello ${name}`);
}
hello("TypeScript");
터미널에 tsc index.ts를 입력하면 자동으로 index.js 파일이 test 폴더에서 생성됩니다. 이제 node index.js 를 터미널에 입력하면 ‘Hello TypeScript’가 출력됩니다.


타입스크립트 동작 방식을 정확히 이해 하려면 대다수의 프로그래밍 언어들이 어떻게 동작 하는지 그 원리를 살펴볼 필요가 있습니다.
먼저 대부분의 프로그래밍 언어는 사실 컴퓨터보단 인간에게 더 친화적입니다. 컴퓨터는 인간과는 달리 바이트코드나 기계어, 이진수 같은 아주 단순한 형태의 언어를 기반으로 동작해요 따라서 영어의 문법과 비슷한 프로그래밍 언어를 컴퓨터가 바로 이해하고 실행할수는 없습니다.
그래서 컴퓨터는 우리가 작성한 코드를 실행하기 위해서 이 코드를 자기가 해석하기 쉬운 형태로 변환 하는 데요 이 과정을 우리는 변환한다 라고 해서 컴파일이라고 부릅니다.
그래서 우리가 프로그래밍 언어로 작성한 코드를 컴파일 하면 코드가 컴퓨터가 이해할 수 있는 기계어 같은 형태로 변환됩니다. 그럼 이제 컴퓨터가 이걸 읽어서 실행하고 결과적으로 코드가 실행되는거죠

그리고 이렇게 코드를 컴파일하는 녀석을 특별히 컴파일러 라고 부릅니다. 컴파일 하는 친구 라는 뜻이죠?
자바나 자바스크립트같은 언어를 컴파일하면 바이트 코드라는 형식으로 변환됩니다. 그래서 설명 편의상 앞으로 컴파일 결과 생성되는 컴퓨터가 이해할 수 있는 형태의 코드를 그냥 바이트코드라고 부르겠습니다

우선 컴파일러는 우리가 작성한 코드를 바로 바이트코드로 변환하는게 아니라 그 전에 AST(추상 문법 트리)라는 특별한 형태로 먼저 변환합니다. AST는 추상 문법 트리 라는 뜻인데요

다음 그림처럼 코드의 공백이나 주석 탭 등의 코드 실행에 관계없는 그런 요소들은 전부 제거하고 트리 형태의 자료구조에 코드를 쪼개서 저장 해 놓은 그런 형태를 말합니다.

왼쪽의 자바스크립트 코드를 AST 추상 문법 트리로 변환하면 오른쪽 처럼 바뀝니다. 물론 정확하게 이렇게 생겼다고 보기에는 조금 어렵구요 대충 이렇게 생겼다 라고 생각해주시면 됩니다.
이렇게 코드를 AST로 변환하고 나면 이제 마지막으로 컴파일러가 AST를 바이트코드로 변환하고 컴파일이 종료됩니다.

자 그래서 우리의 코드가 실행되는 과정을 정리하면 먼저 코드를 컴파일러가 AST로 변환하고 AST를 다시 바이트코드로 변환하고 이렇게 변환된 바이트코드를 컴퓨터가 실행하게 되는거죠

타입 안정성은 변수나 함수가 예상된 타입의 값을 갖도록 보장하는 것입니다. 이를 통해 많은 런타임 오류를 컴파일 시점에 방지할 수 있습니다.
//예제
function add(a: number, b: number): number {
return a + b;
}
console.log(add(5, 10)); // 15
console.log(add(5, 'hello')); // Compile-time error: Argument of type 'string' is not assignable to parameter of type 'number'.
위 코드에서 add 함수는 a와 b가 숫자 타입일 것을 명시하고 있습니다. 숫자가 아닌 문자열을 전달하면 컴파일 오류가 발생합니다.
타입스크립트는 변수나 함수의 반환 타입을 명시하지 않아도 타입을 추론할 수 있습니다. 이는 코드의 간결성을 유지하면서도 타입 안전성을 제공하는 데 도움을 줍니다.
//예제
let x = 10; // TypeScript infers x as a number
x = 20; // No error
x = 'hello'; // Compile-time error: Type 'string' is not assignable to type 'number'
function greet(name = 'World') {
return `Hello, ${name}!`;
}
let message = greet(); // TypeScript infers message as a string
위 코드에서, x는 처음에 숫자로 초기화되었기 때문에 number 타입으로 추론됩니다. greet 함수의 반환 타입도 자동으로 string으로 추론됩니다.
정적 타입 언어에서는 변수의 타입을 컴파일 시점에 검사합니다. 반면, 동적 타입 언어에서는 런타임에 타입을 검사합니다.
//예제
let num: number = 5;
num = 'hello'; // Compile-time error: Type 'string' is not assignable to type 'number'
TypeScript는 정적 타입을 사용하여 변수의 타입을 미리 지정하고, 잘못된 타입 할당을 컴파일 시점에 방지합니다.
//예제
let num = 5;
num = 'hello'; // No error, but may cause runtime errors elsewhere
JavaScript는 동적 타입을 사용하여 변수의 타입이 런타임에 결정됩니다.
제네릭은 다양한 타입에서 동작할 수 있는 재사용 가능한 컴포넌트를 만들기 위해 사용됩니다. 제네릭을 사용하면 코드의 타입 안정성을 유지하면서도 유연성을 높일 수 있습니다.
//예제
function identity<T>(arg: T): T {
return arg;
}
let output1 = identity<string>('hello'); // Explicit type argument
let output2 = identity<number>(10); // Explicit type argument
let output3 = identity('world'); // TypeScript infers type as string
let output4 = identity(20); // TypeScript infers type as number
위 코드에서 identity 함수는 제네릭 타입 T를 사용합니다. 호출할 때 타입을 명시적으로 지정하거나, TypeScript가 타입을 추론하도록 할 수 있습니다.
TypeScript의 타입 시스템은 코드의 안전성과 유지보수성을 크게 향상시킵니다. 타입 안정성을 통해 예상된 타입의 값을 보장하고, 타입 추론을 통해 코드의 간결성을 유지하며, 정적 타입을 통해 컴파일 시점에 오류를 방지합니다. 제네릭을 사용하면 다양한 타입에서 재사용 가능한 유연한 코드를 작성할 수 있습니다. 이러한 기능들을 통해 TypeScript는 JavaScript보다 더욱 안정적이고 견고한 코드를 작성할 수 있도록 도와줍니다.
‘tsconfig.json’ 파일은 TypeScript 컴파일러(tsc)에 대한 설정을 정의하는 데 사용됩니다. 이 파일을 통해 프로젝트의 컴파일 옵션을 구성하고, 포함할 파일과 제외할 파일 등을 지정할 수 있습니다.
npm i --save-dev typescript
tsc --init
{
"compilerOptions": {
"target": "es2016",
"module": "commonjs",
"esModuleInterop": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true
}
}


target : 이 속성은 컴파일된 JavaScript의 ECMAScript 버전을 설정합니다. ‘es2016’ 설정되어 있으므로 ES2016으로 컴파일됩니다.
module : 이 속성은 코드 생성 방식을 설정합니다. 여기서는 ‘commonjs’ 로 설정되어 있어 Node.js 와 호환되는 CommonJS 형태의 모듈 코드를 생성합니다.
esModuleInterop : 이 속성은 ES 모듈과 CommonJS 모듈 간의 상호 운용성을 활성화하는 옵션입니다. true로 설정되어 있으면 ES 모듈과 CommonJS 모듈을 상호 운용할 수 있습니다.
forceConsistentCasingInFileNames : ****이 속성은 파일 이름에서 대소문자가 일관되게 사용되도록 강제하는 옵션입니다. true로 설정되어 있으면 파일 이름의 대소문자가 일치하지 않는 경우 컴파일러가 경고를 발생시킵니다.
strict : 이 속성은 엄격한 타입 검사를 활성화하는 옵션입니다. true 로 설정되어 있으면 TypeScript 컴파일러가 더 엄격한 타입 검사를 수행합니다.
skipLibCheck : 이 속성은 라이브러리 검사를 건너뛰는 옵션입니다. true로 설정되어 있으면 컴파일 시 라이브러리의 검사를 건너뛰고 빠르게 컴파일할 수 있습니다. 하지만 이 옵션은 타입 안정성에 영향을 줄 수 있으므로 주의해야 합니다.
outDir: TypeScript 컴파일러가 컴파일된 JavaScript 파일을 저장할 디렉토리를 지정합니다. 이 속성은 컴파일된 JavaScript 파일들이 위치할 디렉토리 경로를 설정합니다. 현재 ‘outDir’ 이 ‘dist’ 로 설정되어 있으므로 TypeScript 소스 파일들이 컴파일되어 생성된 JavaScript 파일들은 ‘dist’ 디렉토리에 저장됩니다.
{
"compilerOptions": {
```
"outDir": "dist"
}
}
컴파일 결과 dist 폴더가 생성되고 index.js 파일이 생성되었습니다.

include : ‘include’ 속성은 TypeScript 컴파일러에게 어떤 파일을 컴파일할 것인지를 명시하는 역할을 합니다. 해당 설정은 src 디렉토리의 모든 하위 디렉토리 내의 모든 파일을 컴파일 대상으로 지정합니다.
{
"compilerOptions": {
```
},
"include": ["src/**/*"]
}
noUncheckedIndexedAccess : 디폴트 값은 false 입니다. 해당 속성의 값을 true로 설정한다면 배열이나 객체의 속성에 접근할 때 해당 속성이 존재하지 않을 가능성을 고려하도록 강제하는 옵션입니다. 이 속성을 활성화하면 예시를 들어 설명해보겠습니다.
const nums: number[] = [];
const a = 10 + nums[0]; // error
nums 배열은 현재 빈 배열인데 인덱스0의 값에 접근하려고 하니 에러가 발생합니다. 해당 속성을 false로 설정하면 에러가 사라집니다.
lib : 이 속성은 TypeScript 컴파일러가 사용할 라이브러리 파일들을 지정하는 데 사용됩니다. 컴파일 시 포함될 JavaScript 표준 라이브러리의 버전을 명시합니다. 또한 배열 형태이다 보니 라이브러리 옵션을 여러개 지정할 수 있습니다.
{
"compilerOptions": {
"lib": ["ES5"]
}
}
해당 코드는 TypeScript 컴파일러가 ES5 표준 라이브러리를 사용하도록 설정하는 것입니다. 따라서 ES5에 맞지 않는 문법을 사용했을 때 에러가 발생합니다.
TypeScript의 기본 타입을 사용하면 변수의 타입을 명확히 정의하여, 코드의 안정성과 가독성을 높일 수 있습니다. 각 기본 타입 string, number, boolean, null, any는 특정한 종류의 데이터를 나타내며, 이를 통해 프로그램이 예상대로 동작하도록 보장합니다.
문자열 타입으로, 텍스트 데이터를 나타냅니다.
let name: string = 'Alice';
console.log(name); // Alice
숫자 타입으로, 정수와 부동 소수점 숫자를 모두 포함합니다.
let age: number = 30;
console.log(age);
boolean 타입으로, 참(true) 또는 거짓(false) 값을 가집니다.
let isStudent: boolean = true;
console.log(isStudent); // true
null 타입으로, 값이 없음을 나타냅니다.
let emptyValue: null = null;
console.log(emptyValue); // null
모든 타입을 허용합니다. 주로 타입 검사를 피하고 싶을 때 사용합니다. 하지만, 타입 안전성을 떨어뜨릴 수 있으므로 주의가 필요합니다.
let variable: any = 'Hello';
console.log(variable); // Hello
variable = 42;
console.log(variable); // 42
variable = true;
console.log(variable); // true