Tutorial Dasar Dasar TypeScript

Tutorial TypeScript yang membahas lima dasar TypeScript untuk programmer JavaScript. TypeScript digunakan di banyak perusahaan besar, tutorial TypeScript ini adalah tempat yang bagus untuk memulai belajar TypeScript. Tutorial ini akan menjelaskan mulai dari apa itu TypeScript, 5 dasar Typescript termasuk interface dan enum dan contoh penggunaannya untuk melakukan validasi sederhana sebuah form. Dalam tutorial ini diasumsikan bahwa kalian sudah memiliki dasar JavaScript dan juga sedikit NodeJs. Tutorial ini juga dilengkapi dengan video tutorial yang bisa diakses di channel Youtube MyPHPtutorials.

Video Tutorial Dasar Dasar TypeScript

tutorial dasar dasar TypeScript

Materi tutorial TypeScript ini:

  1. Apa itu TypeScript & Keuntungannya?
  2. Install & Setup TypeScript
  3. Menggunakan Tipe Data Primitive
  4. Array & Tuple
  5. Enum
  6. Interface

Apa Itu TypeScript & Keuntungan Menggunakan TypeScript

Menurut website TypeScript di https://www.typescriptlang.org/, "TypeScript is JavaScript with syntax for types", yang dapat diartikan "TypeScript adalah JavaScript yang ditambahkan dengan sintaks untuk types atau tipe data". Yang artinya semua kode JavaScript yang selama ini kita kenal bisa langsung dipakai, dengan sintaks tambahan untuk mendefinisikan types. Seperti kita ketahui JavaScript tidak memiliki fitur untuk mendefinisikan tipe dari sebuah variable. Dengan TypeScript kita dapat mendefinisikan tipe data dari sebuah variable, tipe data input parameter sebuah fungsi, and juga tipe data output dari sebuah fungsi.

TypeScript memberikan keuntungan seperti integrasi yang lebih baik dengan editor sehingga dapat melihat error lebih awal langsung di editor. Kode TypeScript dikonversi menjadi kode JavaScript yang bisa berjalan Browser, NodeJs dan Deno. TypeScript mengerti JavaScript dan penambahan types memberikan tool yang bagus tanpa tambahan kode.

Install & Setup TypeScript

Proses instalasi TypeScript sangat sederhana. Pertama pastikan bahwa kalian sudah menginstall NodeJS, yang dapat didownload di https://nodejs.dev/. Setelah NodeJs terinstall maka kalian akan memiliki command npm. Bukan terminal atau command prompt di Windows (bagi pengguna Windows). Dan jalankan command di bawah.

npm install typescript --save-dev

Jika kalian ingin menginstall secara global bisa gunakan

npm install -g typescript

Setelah terinstall kita perlu membuat file tsconfig.json. File ini digunakan untuk memberitahu cara TypScript dikonversi ke Javascript. Gunakan command di bawah

./node_modules/.bin/tsc --init

kalau kalian install TypeScript secara global gunakan

tsc --init

yang akan menghasilkan file tsconfig.json seperti di bawah

{
  "compilerOptions": {
    /* Visit https://aka.ms/tsconfig.json to read more about this file */

    /* Projects */
    // "incremental": true,                              /* Enable incremental compilation */
    // "composite": true,                                /* Enable constraints that allow a TypeScript project to be used with project references. */
    // "tsBuildInfoFile": "./",                          /* Specify the folder for .tsbuildinfo incremental compilation files. */
    // "disableSourceOfProjectReferenceRedirect": true,  /* Disable preferring source files instead of declaration files when referencing composite projects */
    // "disableSolutionSearching": true,                 /* Opt a project out of multi-project reference checking when editing. */
    // "disableReferencedProjectLoad": true,             /* Reduce the number of projects loaded automatically by TypeScript. */

    /* Language and Environment */
    "target": "es2016",                                  /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
    // "lib": [],                                        /* Specify a set of bundled library declaration files that describe the target runtime environment. */
    // "jsx": "preserve",                                /* Specify what JSX code is generated. */
    // "experimentalDecorators": true,                   /* Enable experimental support for TC39 stage 2 draft decorators. */
    // "emitDecoratorMetadata": true,                    /* Emit design-type metadata for decorated declarations in source files. */
    // "jsxFactory": "",                                 /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */
    // "jsxFragmentFactory": "",                         /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
    // "jsxImportSource": "",                            /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */
    // "reactNamespace": "",                             /* Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit. */
    // "noLib": true,                                    /* Disable including any library files, including the default lib.d.ts. */
    // "useDefineForClassFields": true,                  /* Emit ECMAScript-standard-compliant class fields. */

    /* Modules */
    "module": "commonjs",                                /* Specify what module code is generated. */
    // "rootDir": "./",                                  /* Specify the root folder within your source files. */
    // "moduleResolution": "node",                       /* Specify how TypeScript looks up a file from a given module specifier. */
    // "baseUrl": "./",                                  /* Specify the base directory to resolve non-relative module names. */
    // "paths": {},                                      /* Specify a set of entries that re-map imports to additional lookup locations. */
    // "rootDirs": [],                                   /* Allow multiple folders to be treated as one when resolving modules. */
    // "typeRoots": [],                                  /* Specify multiple folders that act like `./node_modules/@types`. */
    // "types": [],                                      /* Specify type package names to be included without being referenced in a source file. */
    // "allowUmdGlobalAccess": true,                     /* Allow accessing UMD globals from modules. */
    // "resolveJsonModule": true,                        /* Enable importing .json files */
    // "noResolve": true,                                /* Disallow `import`s, `require`s or `<reference>`s from expanding the number of files TypeScript should add to a project. */

    /* JavaScript Support */
    // "allowJs": true,                                  /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */
    // "checkJs": true,                                  /* Enable error reporting in type-checked JavaScript files. */
    // "maxNodeModuleJsDepth": 1,                        /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */

    /* Emit */
    // "declaration": true,                              /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
    // "declarationMap": true,                           /* Create sourcemaps for d.ts files. */
    // "emitDeclarationOnly": true,                      /* Only output d.ts files and not JavaScript files. */
    // "sourceMap": true,                                /* Create source map files for emitted JavaScript files. */
    // "outFile": "./",                                  /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */
    // "outDir": "./",                                   /* Specify an output folder for all emitted files. */
    // "removeComments": true,                           /* Disable emitting comments. */
    // "noEmit": true,                                   /* Disable emitting files from a compilation. */
    // "importHelpers": true,                            /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
    // "importsNotUsedAsValues": "remove",               /* Specify emit/checking behavior for imports that are only used for types */
    // "downlevelIteration": true,                       /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
    // "sourceRoot": "",                                 /* Specify the root path for debuggers to find the reference source code. */
    // "mapRoot": "",                                    /* Specify the location where debugger should locate map files instead of generated locations. */
    // "inlineSourceMap": true,                          /* Include sourcemap files inside the emitted JavaScript. */
    // "inlineSources": true,                            /* Include source code in the sourcemaps inside the emitted JavaScript. */
    // "emitBOM": true,                                  /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
    // "newLine": "crlf",                                /* Set the newline character for emitting files. */
    // "stripInternal": true,                            /* Disable emitting declarations that have `@internal` in their JSDoc comments. */
    // "noEmitHelpers": true,                            /* Disable generating custom helper functions like `__extends` in compiled output. */
    // "noEmitOnError": true,                            /* Disable emitting files if any type checking errors are reported. */
    // "preserveConstEnums": true,                       /* Disable erasing `const enum` declarations in generated code. */
    // "declarationDir": "./",                           /* Specify the output directory for generated declaration files. */
    // "preserveValueImports": true,                     /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */

    /* Interop Constraints */
    // "isolatedModules": true,                          /* Ensure that each file can be safely transpiled without relying on other imports. */
    // "allowSyntheticDefaultImports": true,             /* Allow 'import x from y' when a module doesn't have a default export. */
    "esModuleInterop": true,                             /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */
    // "preserveSymlinks": true,                         /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
    "forceConsistentCasingInFileNames": true,            /* Ensure that casing is correct in imports. */

    /* Type Checking */
    "strict": true,                                      /* Enable all strict type-checking options. */
    // "noImplicitAny": true,                            /* Enable error reporting for expressions and declarations with an implied `any` type.. */
    // "strictNullChecks": true,                         /* When type checking, take into account `null` and `undefined`. */
    // "strictFunctionTypes": true,                      /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
    // "strictBindCallApply": true,                      /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */
    // "strictPropertyInitialization": true,             /* Check for class properties that are declared but not set in the constructor. */
    // "noImplicitThis": true,                           /* Enable error reporting when `this` is given the type `any`. */
    // "useUnknownInCatchVariables": true,               /* Type catch clause variables as 'unknown' instead of 'any'. */
    // "alwaysStrict": true,                             /* Ensure 'use strict' is always emitted. */
    // "noUnusedLocals": true,                           /* Enable error reporting when a local variables aren't read. */
    // "noUnusedParameters": true,                       /* Raise an error when a function parameter isn't read */
    // "exactOptionalPropertyTypes": true,               /* Interpret optional property types as written, rather than adding 'undefined'. */
    // "noImplicitReturns": true,                        /* Enable error reporting for codepaths that do not explicitly return in a function. */
    // "noFallthroughCasesInSwitch": true,               /* Enable error reporting for fallthrough cases in switch statements. */
    // "noUncheckedIndexedAccess": true,                 /* Include 'undefined' in index signature results */
    // "noImplicitOverride": true,                       /* Ensure overriding members in derived classes are marked with an override modifier. */
    // "noPropertyAccessFromIndexSignature": true,       /* Enforces using indexed accessors for keys declared using an indexed type */
    // "allowUnusedLabels": true,                        /* Disable error reporting for unused labels. */
    // "allowUnreachableCode": true,                     /* Disable error reporting for unreachable code. */

    /* Completeness */
    // "skipDefaultLibCheck": true,                      /* Skip type checking .d.ts files that are included with TypeScript. */
    "skipLibCheck": true                                 /* Skip type checking all .d.ts files. */
  }
}

File di atas berisi setting dasar dan beberapa dokumentasi. Pada bagian target berisi es2016 yang artinya JavaScript file yang dibentuk akan kompatibel dengan ECMAScript 2016. Kita bisa mengubahnya menjadi es2017 atau menggunakan ECMAScript 2017 untuk dapat menggunakan fitur JavaScript yang lebih baru.

Untuk mencoba cara kerjanya kita bisa membuat contohHello world, buatlah sebuah file index.ts, extensi file .ts adalah untuk kode TypeScript. Kemudian tambahakan console.log('Hello World'); dan disimpan filenya. Kembali ke command prompt atau terminal dan jalankan ./node_modules/.bin/tsc atau yang menginstall global cukup gunakan tsc. Maka file JavaScript index.js akan terbuat, yang isinya kurang lebih sama dengan isi TypeScript. File index.js inilah yang bisa dipakai di browser (dalam file html). Agar tidak selalu mengetik command tsc setiap melakukan perubahan kode, kita bisa menggunakan opsi --watch seperti ./node_modules/.bin/tsc --watch. Maka setiap perubahan yang dilakukan di file .ts akan langsung dikonversi menjadi kode di file .js.

Menggunakan Tipe Data Primitive di TypeScript

Di TypeScript kita bisa mendefinisikan tipe data untuk setiap variable termasuk tipe data primitive seperti string, number dan boolean. Cara mendefinisikannya adalah nama variable diikuti dengan tanda titik dua : dan tipe data seperti di bawah

let nama: string;
let nilai: number;
let hasil: boolean;

nama = 'Ayu';
nama = 'Joni';

nilai = 10;

hasil = false;

dengan mendefinisikan tipe data dari variable pada saat kalian menaruh nilai dengan tipe data berbeda kalian akan melihat error di editor kalian. Misal kalau kalian set nama = 123, maka editor kalian akan mengeluarkan error Type 'number' is not assignable to type 'string', Pada saat menjalakan command tsc juga akan keluar error yang sama.

Kemudian ada juga cara implisit yang mana TypeScript memperkirakan tipe data sebuah variable seperti

let nama = 'Joni';
let nilai = 123;
let hasil = true;

variable nama di atas akan langsung diset dengan tipe data string, sehingga kalau nilanya diubah menjadi dengan number sepertinama = 123 akan mengeluarkan error serupa seperti di atas. Demikian pula dengan variable nilai dan hasil yang masing masing tipe datanya menjadi number dan boolean.

Array & Tuple

Definisi tipe data array juga sederhana seperti di atas, nama variable diikuti dengan tanda titik dua dan tipe data dan tanda kurung siku [] seperti di bawah.

let namaSiswa: string[] = [];
let nilaiSiswa: number[] = [];

namaSiswa.push("Budi");
nilaiSiswa.push(10);

Variable namaSiswa adalah array dengan tipe data string untuk setiap elemennya. Jadi namaSiswa.push(1234) akan menghasilkan error karena 1234 adalah number, demikian pula sebaliknya dengan nilaiSiswa yang merupakan array number yang tidak bisa elemennya memiliki tipe data string. Jika kalian ingin setiap elemen array memiliki tipe data berbeda bisa menggunakan tipe any, seperti

let hasil: any[] = []
hasil.push(123);
hasil.push('test');
hasil.push(true);

Kemudian ada tipe Tuple, yang merupakan sub dari tipe array, yang mana panjang dan tipe datanya sudah ditentukan. Misalnya sebuah koordinat memiliki nilai x dan y. Cara mendifisikannya adalah seperti:

let koordinat: [x: number, y: number];
koordinat = [1, 10];

// koordinat = [1, "10"]; akan terjadi error karena "10" adalah string.

Enum

Enum adalah variable special yang merepresentasikan kumpulan dari konstanta. Enum ada dua jenis, string dan numeric. Cara mendefinisikannya adalah dimulai dengan enum dan nama dari enum seperti contoh untuk jenis string seperti di bawah

enum JenisKelamin {
 L = "Laki Laki",
 P = Perempuan
}

Cara menggunakannya sederhana JenisKelamin.P misalnya, nilai yang ada didalamnya adalah "Perempuan" (bukan P) . Kemudian untuk contoh numeric

enum Arah {
    UP,
    DOWN,
    RIGHT,
    LEFT
}

nilai dari Arah.UP adalah 0, Arah.DOWN adalah 1, Arah.RIGHT = 2, dan Arah.LEFT = 3. Kita juga bisa set nilai awal seperti di bawah

enum Arah {
    UP = 1,
    DOWN,
    RIGHT,
    LEFT
}

Jadi nilai dari Arah.UP adalah 1, dan seterusnya sampai nilai Arah.LEFT adalah 4.

Interface

Interface adalah cara untuk mendefinisikan sebuah object/class dengan struktur tertentu. Misalnya seorang Siswa harus memiliki nama, email, nis dan kelas. Untuk mendefinisikan interface dimulai dengan kata kunci interface diikuti dengan nama interface seperti:

interface Siswa {
    nama: string;
    email: string;
    nis: string;
    kelas: string;
}

cara menggunakannya dalam sebuah variable adalah

let dataSiswa: Siswa = {
    nama: 'Budi',
    email: 'info@example.com',
    nis: '0001',
    kelas: 'XI'
}

agar sebuah properti dari Siswa bersifat opsional maka kita bisa menggunakan tanda ? seperti:

interface Siswa {
    nama: string;
    email: string;
    nis: string;
    kelas: string;
    alamat?: string;
}

maka alamat boleh tidak diisi. Ada juga cara yang lebih dinamis untuk menambahkan property lain pada siswa menggunakan cara seperti:

interface Siswa {
    nama: string;
    email: string;
    nis: string;
    kelas: string;
    [key: string: string | number;
}

yang artinya Siswa harus memiliki data nama, email, nis dan kelas, tapi boleh ditambahkan data lainnya seperti:

let dataSiswa: Siswa = {
    nama: 'Budi',
    email: 'info@example.com',
    nis: '0001',
    kelas: 'XI',
    umur: 17,
    alamat: 'jalan denpasar'
}

Contoh Validasi Form Sederhana dengan TypeScript

Pertama buatlah file index.ts dan sebuah form html seperti di bawah.

<!DOCTYPE html>
<html>
    <head>
        <title>Belajar TypeScript</title>
    </head>
    <body>
        <form>
            <p>
                <label>Nama</label>
                <input type="text" id="nama" name="nama">
            </p>
            <p>
                <label>Email</label>
                <input type="email" id="email" name="email">
            </p>
            <p>
                <label>Kelas</label>
                <select id="kelas" name="kelas">
                </select>
            </p>
            <p>
                <button type="button" onclick="kirimData()">Kirim</button>
            </p>
        </form>
        <script src="src/index.js"></script>
    </body>
</html>

Kemudian edit file index.ts, pertama buat enum untuk Kelas dan interface Siswa

enum Kelas {
    X = 'Kelas 10',
    XI = 'Kelas 11',
    XII = 'Kelas 12'
}

interface Siswa {
    nama: string,
    email: string,
    kelas: string
}

kemudian buat fungsi untuk menampilkan opsi kelas menggunakan nilai enum yang ada.

function renderKelas(): void {
    const select = document.getElementById('kelas');
    Object.values(Kelas).forEach((value: string) => {
        const option = document.createElement('option');
        option.text = value;
        select?.appendChild(option);
    })
}

renderKelas();

Untuk melakukan validasi saat tombol kirim diklik, tambahkan fungsi processData di bawah:

function processData(): void {
    const data: Siswa = {
        nama: (<HTMLInputElement> document.getElementById('nama')).value,
        email: (<HTMLInputElement> document.getElementById('email')).value,
        kelas: (<HTMLInputElement> document.getElementById('kelas')).value,
    };

    const hasil = validasi(data);

    if (hasil == '') {
        alert('data sudah benar');
    } else {
        alert(hasil);
    }
}

function validasi(data: Siswa): string {
    if (!data.email) {
        return 'Email tidak boleh kosong';
    }

    if (!data.nama) {
        return 'Nama tidak boleh kosong';
    }

    if (!data.kelas) {
        return 'Kelas tidak boleh kosong';
    }

    return '';
}

Fungsi processData karena tidak memberikan timpal balik atau return, makan fungsi di tambahkan sintaks : void yang artinya tidak ada timpal balik. Sedangkan fungsi validasi memberikan umpan balik berupan string pesan kesalahan. Jadi ditambahkan sintaks :string.

Kesimpulan

Pada tutorial TypeScript ini telah dijelaskan lima dasar TypeScript yang meliputi instalasi dan setup TypeScript, penggunakan tipe data sederhana atau primitive di TypeScript, menggunakan Array dan Tuple, mendefinisikan enum dan juga interface. Dalam video tutorial juga didemonstrasikan lebih jelas lima dasar TypeCcript ini. Selamat mencoba, kalau ada pertanyaan silahkan gunakan kolom komentar.