TypeScript의 컴파일러 내부 탐색
TypeScript의 컴파일러는 종종 tsc
이라고도 하며, TypeScript 생태계의 핵심 구성 요소 중 하나입니다. 정적 타이핑 규칙을 적용하면서 TypeScript 코드를 JavaScript로 변환합니다. 이 글에서는 TypeScript 컴파일러의 내부 작동 방식을 살펴보고 TypeScript 코드를 처리하고 변환하는 방법을 더 잘 이해해 보겠습니다.
1. TypeScript 컴파일 프로세스
TypeScript 컴파일러는 TypeScript를 JavaScript로 변환하기 위해 일련의 단계를 따릅니다. 다음은 프로세스에 대한 개략적인 개요입니다.
- 소스 파일을 AST(추상 구문 트리)로 구문 분석합니다.
- AST 바인딩 및 유형 검사.
- 출력 JavaScript 코드와 선언을 내보냅니다.
이러한 단계를 더 자세히 살펴보겠습니다.
2. TypeScript 코드 구문 분석
컴파일 프로세스의 첫 번째 단계는 TypeScript 코드를 구문 분석하는 것입니다. 컴파일러는 소스 파일을 가져와 AST로 구문 분석하고 어휘 분석을 수행합니다.
다음은 TypeScript의 내부 API를 사용하여 AST에 액세스하고 조작하는 방법을 간략하게 나타낸 것입니다.
import * as ts from 'typescript';
const sourceCode = 'let x: number = 10;';
const sourceFile = ts.createSourceFile('example.ts', sourceCode, ts.ScriptTarget.Latest);
console.log(sourceFile);
createSourceFile
함수는 원시 TypeScript 코드를 AST로 변환하는 데 사용됩니다. sourceFile
객체는 코드의 구문 분석된 구조를 포함합니다.
3. 바인딩 및 유형 검사
구문 분석 후 다음 단계는 AST의 심볼을 바인딩하고 유형 검사를 수행하는 것입니다. 이 단계에서는 모든 식별자가 해당 선언에 연결되어 있는지 확인하고 코드가 TypeScript의 유형 규칙을 따르는지 확인합니다.
유형 검사는 TypeChecker
클래스를 사용하여 수행됩니다. 다음은 프로그램을 만들고 유형 정보를 검색하는 방법의 예입니다.
const program = ts.createProgram(['example.ts'], {});
const checker = program.getTypeChecker();
// Get type information for a specific node in the AST
sourceFile.forEachChild(node => {
if (ts.isVariableStatement(node)) {
const type = checker.getTypeAtLocation(node.declarationList.declarations[0]);
console.log(checker.typeToString(type));
}
});
이 예에서 TypeChecker
는 변수 선언의 유형을 확인하고 AST에서 유형 정보를 검색합니다.
4. 코드 방출
타입 검사가 완료되면 컴파일러는 방출 단계로 넘어갑니다. 여기서 TypeScript 코드가 JavaScript로 변환됩니다. 구성에 따라 출력에는 선언 파일과 소스 맵도 포함될 수 있습니다.
다음은 컴파일러를 사용하여 JavaScript 코드를 내보내는 방법의 간단한 예입니다.
const { emitSkipped, diagnostics } = program.emit();
if (emitSkipped) {
console.error('Emission failed:');
diagnostics.forEach(diagnostic => {
const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n');
console.error(message);
});
} else {
console.log('Emission successful.');
}
program.emit
함수는 JavaScript 출력을 생성합니다. 방출 중에 오류가 있으면 캡처하여 표시합니다.
5. 진단 메시지
TypeScript 컴파일러의 주요 책임 중 하나는 개발자에게 의미 있는 진단 메시지를 제공하는 것입니다. 이러한 메시지는 유형 검사 및 코드 방출 단계 모두에서 생성됩니다. 진단에는 경고 및 오류가 포함될 수 있으므로 개발자가 문제를 신속하게 식별하고 해결하는 데 도움이 됩니다.
컴파일러에서 진단 결과를 검색하고 표시하는 방법은 다음과 같습니다.
const diagnostics = ts.getPreEmitDiagnostics(program);
diagnostics.forEach(diagnostic => {
const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n');
console.log(`Error ${diagnostic.code}: ${message}`);
});
이 예에서는 진단 결과가 프로그램에서 추출되어 콘솔에 인쇄됩니다.
6. 컴파일러 API를 사용한 TypeScript 변환
TypeScript 컴파일러 API를 사용하면 개발자가 사용자 정의 변환을 만들 수 있습니다. 코드 방출 전에 AST를 수정하여 강력한 사용자 정의 및 코드 생성 도구를 사용할 수 있습니다.
다음은 모든 변수의 이름을 newVar
으로 바꾸는 간단한 변환의 예입니다.
const transformer = (context: ts.TransformationContext) => {
return (rootNode: T) => {
function visit(node: ts.Node): ts.Node {
if (ts.isVariableDeclaration(node)) {
return ts.factory.updateVariableDeclaration(
node,
ts.factory.createIdentifier('newVar'),
node.type,
node.initializer
);
}
return ts.visitEachChild(node, visit, context);
}
return ts.visitNode(rootNode, visit);
};
};
const result = ts.transform(sourceFile, [transformer]);
console.log(result.transformed[0]);
이 변환은 AST의 각 노드를 방문하고 필요에 따라 변수의 이름을 바꿉니다.
결론
TypeScript의 컴파일러 내부를 탐색하면 TypeScript 코드가 처리되고 변환되는 방식에 대한 더 깊은 이해가 제공됩니다. 사용자 지정 도구를 빌드하거나 TypeScript 작동 방식에 대한 지식을 향상시키려는 경우 컴파일러의 내부를 파헤치는 것은 계몽적인 경험이 될 수 있습니다.