Menjelajahi Bagian Dalam Kompiler TypeScript

Kompiler TypeScript, yang sering disebut sebagai tsc, merupakan salah satu komponen inti ekosistem TypeScript. Kompiler ini mengubah kode TypeScript menjadi JavaScript sekaligus menerapkan aturan pengetikan statis. Dalam artikel ini, kita akan menyelami cara kerja internal kompiler TypeScript untuk lebih memahami cara kompiler tersebut memproses dan mengubah kode TypeScript.

1. Proses Kompilasi TypeScript

Kompiler TypeScript mengikuti serangkaian langkah untuk mengubah TypeScript menjadi JavaScript. Berikut ini adalah ikhtisar singkat dari proses tersebut:

  1. Menguraikan berkas sumber ke dalam Pohon Sintaksis Abstrak (AST).
  2. Mengikat dan memeriksa tipe AST.
  3. Memancarkan kode JavaScript keluaran dan deklarasi.

Mari kita bahas langkah-langkah ini secara lebih rinci.

2. Penguraian Kode TypeScript

Langkah pertama dalam proses kompilasi adalah mengurai kode TypeScript. Kompiler mengambil berkas sumber, mengurainya menjadi AST, dan melakukan analisis leksikal.

Berikut tampilan sederhana tentang cara mengakses dan memanipulasi AST menggunakan API internal TypeScript:

import * as ts from 'typescript';

const sourceCode = 'let x: number = 10;';
const sourceFile = ts.createSourceFile('example.ts', sourceCode, ts.ScriptTarget.Latest);

console.log(sourceFile);

Fungsi createSourceFile digunakan untuk mengubah kode TypeScript mentah menjadi AST. Objek sourceFile berisi struktur kode yang diurai.

3. Pengikatan dan Pemeriksaan Jenis

Setelah penguraian, langkah selanjutnya adalah mengikat simbol-simbol dalam AST dan melakukan pengecekan tipe. Fase ini memastikan bahwa semua pengenal ditautkan ke deklarasi masing-masing dan memeriksa apakah kode mengikuti aturan tipe TypeScript.

Pemeriksaan tipe dilakukan menggunakan kelas TypeChecker. Berikut ini contoh cara membuat program dan mengambil informasi tipe:

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));
    }
});

Dalam contoh ini, TypeChecker memeriksa jenis deklarasi variabel dan mengambil informasi jenis dari AST.

4. Emisi Kode

Setelah pengecekan tipe selesai, kompiler melanjutkan ke fase emisi. Di sinilah kode TypeScript diubah menjadi JavaScript. Output juga dapat mencakup file deklarasi dan peta sumber, tergantung pada konfigurasinya.

Berikut contoh sederhana cara menggunakan kompiler untuk memancarkan kode 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.');
}

Fungsi program.emit menghasilkan output JavaScript. Jika ada kesalahan selama emisi, kesalahan tersebut akan ditangkap dan ditampilkan.

5. Pesan Diagnostik

Salah satu tanggung jawab utama penyusun TypeScript adalah menyediakan pesan diagnostik yang bermakna bagi pengembang. Pesan-pesan ini dihasilkan selama fase pengecekan tipe dan emisi kode. Diagnostik dapat mencakup peringatan dan kesalahan, yang membantu pengembang mengidentifikasi dan menyelesaikan masalah dengan cepat.

Berikut cara mengambil dan menampilkan diagnostik dari kompiler:

const diagnostics = ts.getPreEmitDiagnostics(program);

diagnostics.forEach(diagnostic => {
    const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n');
    console.log(`Error ${diagnostic.code}: ${message}`);
});

Dalam contoh ini, diagnostik diekstraksi dari program dan dicetak ke konsol.

6. Transformasi TypeScript dengan API Kompiler

API kompiler TypeScript memungkinkan pengembang membuat transformasi kustom. Anda dapat memodifikasi AST sebelum mengeluarkan kode, yang memungkinkan kustomisasi dan alat pembuatan kode yang canggih.

Berikut contoh transformasi sederhana yang mengganti nama semua variabel menjadi 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]);

Transformasi ini mengunjungi setiap node di AST dan mengganti nama variabel sesuai kebutuhan.

Kesimpulan

Menjelajahi bagian dalam kompiler TypeScript memberikan pemahaman yang lebih mendalam tentang bagaimana kode TypeScript diproses dan diubah. Apakah Anda ingin membuat alat khusus atau meningkatkan pengetahuan Anda tentang cara kerja TypeScript, mempelajari bagian dalam kompiler dapat menjadi pengalaman yang mencerahkan.