타입스크립트 컴파일러의 동작을 설정하는 '설정 파일'로서, 컴파일 시 어떤 옵션을 사용하고 어떤 파일을 포함 또는 제외할지를 정의합니다. 파일 확장자 그대로 json 형태로 작성되어 있습니다.
{
/** typescript compiler 옵션 정의 */
"compilerOptions": {
/** 컴파일할 ECMAScript 버전 */
"target": "es5",
/** 컴파일 시 사용할 라이브러리 */
"lib": ["dom", "dom.iterable", "esnext"],
/** 컴파일 시 js 파일 포함 여부 */
"allowJs": true,
/** 선언 파일 유효성 검사 스킵 여부 */
"skipLibCheck": true,
/** 엄격한 타입 검사 여부 설정 */
"strict": true,
/** 파일 이름의 대소문자 형식 일관성 강제 여부 */
"forceConsistentCasingInFileNames": true,
/** 컴파일 후 JS 파일 생성하지 않음 여부 */
"noEmit": true,
/** CommonJS 모듈 및 ES6 모듈 간의 상호운용성 설정 */
"esModuleInterop": true,
/** 컴파일된 코드가 어떤 모듈 시스템을 사용할지 */
"module": "esnext",
/** 모듈 해결 전략 지정(node, classic, bundler) */
"moduleResolution": "bundler",
/** json 파일을 모듈처럼 불러와서 사용할지의 여부 */
"resolveJsonModule": true,
/** 파일 간의 의존성 강제 분리 여부 */
"isolatedModules": true,
/** JSX 구문 처리 방식 */
"jsx": "preserve",
/** 증분 컴파일 옵션 설정 */
"incremental": true,
/** TS 컴파일러 플러그인 설정 */
"plugins": [
{
"name": "next"
}
],
/** 모듈을 해결하기 위한 경로 별칭 설정 */
"paths": {
"@/*": ["./src/*"]
}
},
/** 컴파일에 포함될 파일 경로 설정 */
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
/** 컴파일에 제외할 파일 경로 설정 */
"exclude": ["node_modules"]
}
타입스크립트의 선언 파일은 .d.ts
확장자를 가진 파일을 의미합니다. JS는 동적 언어로 정적인 타입 정보가 부족한 경우가 많으므로, 타입스크립트 컴파일을 위해 코드 또는 외부 라이브러리의 타입 정보를 정의해주는 선언 파일을 사용합니다.
CommonJS와 ES6 (ECMAScript 2015)는 둘 다 모듈 시스템의 다른 접근 방식을 나타냅니다. 이 두 가지 모듈 형식은 JavaScript 코드를 구조화하고 모듈화하는 데 사용됩니다.
Node.js에서는 기본적으로 CommonJS 모듈 시스템을 사용합니다. CommonJS는 Node.js에서 모듈을 정의하고 가져오는 데 사용되며, require 함수와 module.exports 객체를 사용하여 모듈을 정의하고 공유합니다.
// 모듈 가져오기
const myModule = require('./myModule');
// 모듈 정의하기
module.exports = {
// 모듈 내용
};
반면에 ES6에서는 ECMAScript 2015부터 도입된 모듈 시스템을 사용할 수 있습니다. ES6 모듈 시스템은 import와 export 키워드를 사용하여 모듈을 가져오고 내보냅니다. 웹 개발에서는 주로 ES6 방식을 사용합니다.
// 모듈 가져오기
import myModule from './myModule';
// 모듈 내보내기
export default {
// 모듈 내용
};
AMD(Asynchronous Module Definition)는 JavaScript 모듈을 비동기적으로 정의하고 로드하기 위한 모듈 형식 중 하나입니다. CommonJS와 함께 모듈 시스템의 중요한 대안 중 하나로 등장한 개념입니다.
AMD는 주로 웹 브라우저 환경에서 사용되며, 주요 목표 중 하나는 웹 페이지의 로딩과 성능을 향상시키는 것입니다. 특히 브라우저에서 여러 모듈을 비동기적으로 로드할 때 발생하는 의존성 문제를 해결하기 위해 개발되었습니다.
AMD의 특징은 다음과 같습니다:
define
함수를 사용하여 모듈을 정의하고 의존성을 명시합니다.AMD의 기본적인 사용 예시는 아래와 같습니다:
// 모듈 정의
define(['dependency'], function(dependency) {
// 모듈 코드
return module;
});
// 모듈 사용
require(['myModule'], function(myModule) {
// 모듈 사용 코드
});
AMD는 주로 브라우저 환경에서 모듈을 로드하고 비동기적으로 사용해야 할 때 유용합니다. 하지만 CommonJS와 비교했을 때 문법이 더 복잡하고, Node.js와 같은 서버 사이드 환경에서는 사용되지 않는 특징이 있습니다. 이런 이유로 Node.js에서는 주로 CommonJS가 사용됩니다.
번들러의 주요 목적은 여러 개의 파일을 하나의 번들로 묶어서 웹 애플리케이션의 로딩 성능을 최적화하는 것입니다. 번들러는 여러 개의 모듈이나 파일 간의 의존성을 파악하고, 필요한 모든 코드를 하나의 번들 파일로 결합하여 최종 사용자가 로딩할 때 필요한 리소스 양을 줄입니다.
Webpack은 이러한 번들링 작업을 수행하는 대표적인 도구 중 하나입니다. Webpack은 다양한 모듈 시스템을 지원하며, 주로 ES6 모듈과 CommonJS를 다룹니다. Webpack은 의존성 그래프를 분석하여 필요한 모듈을 찾아 번들로 묶고, 코드 압축, 트랜스파일링, 이미지나 스타일 등의 리소스 관리도 함께 수행합니다.
웹 사이트 렌더링 시 로드해주는 기능뿐만 아니라, 번들링을 통해 브라우저에 전달되는 파일의 수를 줄여서 초기 로딩 속도를 향상시키는 것이 주요한 목적입니다. 번들러를 사용하면 여러 개의 파일을 하나의 파일로 결합하고, 필요한 코드만 불러오는 등 최적화된 방식으로 웹 애플리케이션의 성능을 향상시킬 수 있습니다.
ex) https://domain/path(segment/segment/...)
url에서 domain 다음에 나오는 요소를 path라고 하며, path를 구성하고 있는 각 요소를 segment라고 합니다.
URL은 웹에서 리소스의 주소를 나타내는 문자열입니다.
https://www.example.com:8080/path/to/resource?param1=value1¶m2=value2#section3
프로토콜/도메인(또는 ip주소)/포트번호/path(세그먼트로 구성)/쿼리스트링/프래그먼트
https://
www.example.com
8080
/path/to/resource
param1=value1¶m2=value2
#section3
URI(Uniform Resource Identifier)은 URL(Uniform Resource Locator)과 URN(Uniform Resource Name)을 포함하는 상위 개념입니다. 리소스의 고유한 식별자를 나타내는 통합된 형식을 의미합니다.
URN은 리소스가 위치에 의존하지 않고, 리소스 이름 자체를 고유한 식별자로 사용하는 것입니다. 예를 들어, "urn:isbn:0451450523"는 책의 ISBN 번호를 URN으로 나타낸 예시입니다.
<a>
태그는 외부 URL 또는 다른 페이지로 이동시 사용하며, 클릭 시 전체 페이지 리로딩이 발생하여 서버 요청을 보내고 전체 페이지를 새로 리로드합니다. 따라서 server side rendering이 사용되고, 전체 페이지 컨텐츠를 로드하기 때문에 성능이 저하될 수 있습니다.
<Link>
컴포넌트는 Next.js에서 제공하는 라우팅 기능을 활용하여 페이지 간의 네비게이션을 처리하는 데 사용됩니다. 페이지 간 전환 시, 서버 요청이 발생하지 않기 때문에 빠른 속도와 깔끔한 사용자 경험이 가능합니다. 오직 애플리케이션 내부에서 페이지 전환 시 필요한 자원만 로드됩니다.
여기서 next.js는 브라우저의 주소만 변경하고, 변경된 주소에 따라 필요한 컴포넌트만 렌더링하여 클라이언트 사이드 라우팅을 구현합니다. 이를 통해 변경이 필요한 부분만 실제 DOM 조작을 통해 업데이트하며 전체 페이지 리로딩을 방지하여 성능을 향상시킵니다.
브라우저의 뒤로가기/앞으로가기 기능을 통해 이전 페이지와 현재 페이지 간의 차이를 비교하고, 변경이 필요한 컴포넌트만 다시 렌더링하여 이를 '앱 쉘(Application Shell)'이라고 하는 가벼운 프레임워크로 구성합니다. 이런 방식은 사용자 경험을 향상시키고 성능을 개선하는 데 도움이 됩니다.
타입스크립트 제네릭은 코드를 더 유연하고 재사용 가능하게 만들어주는 기능입니다. 제네릭은 함수, 클래스, 인터페이스 등에서 사용되며, 동적인 타입을 사용할 때 유용합니다. 제네릭을 사용하면 타입을 추상화하여 여러 종류의 타입에서 동작할 수 있는 함수나 컴포넌트를 작성할 수 있습니다.
제네릭을 사용하는 주요 이점은 다음과 같습니다:
재사용성과 유연성: 제네릭을 사용하면 함수나 클래스를 여러 타입에서 재사용할 수 있습니다. 같은 로직을 다양한 타입에 대해 적용할 수 있습니다.
타입 안정성: 제네릭을 사용하면 코드 내부에서 타입 안정성을 유지하면서도 여러 타입을 다룰 수 있습니다. 컴파일러가 타입 검사를 수행하므로 런타임 에러를 방지할 수 있습니다. 만약 매개변수로 들어올 데이터의 타입이 정해지지 않았다고 any
를 사용하면, '모든 타입을 허용한다'는 뜻이기 때문에, 타입 오류를 검출할 수 없습니다.
타입 추론: 제네릭을 사용하면 컴파일러가 입력된 값의 타입을 추론하여 유추할 수 있습니다.
제네릭은 <T>
와 같이 꺾쇠 괄호 내에 타입 변수를 선언하는 방식으로 사용됩니다. 일반적으로 T
는 타입 변수의 이름으로 많이 사용되지만, 어떤 이름도 사용할 수 있습니다.
예를 들어, 아래는 제네릭을 사용하여 배열의 요소를 역순으로 반환하는 함수를 작성한 예시입니다:
function reverseArray<T>(array: T[]): T[] {
return array.reverse();
}
const numbers = [1, 2, 3, 4, 5];
const reversedNumbers = reverseArray(numbers); // [5, 4, 3, 2, 1]
const strings = ["apple", "banana", "cherry"];
const reversedStrings = reverseArray(strings); // ["cherry", "banana", "apple"]
위 코드에서 reverseArray
함수는 배열의 타입에 따라 동작합니다. 이 함수는 숫자 배열이든 문자열 배열이든 역순으로 반환할 수 있으며, 여러 타입에서 재사용할 수 있습니다.