Apa yang dilakukan kata kunci ʻis` dalam skrip ketikan?

114

Saya menemukan beberapa kode yang terlihat seperti ini:

export function foo(arg: string): arg is MyType {
    return ...
}

Saya belum bisa mencari isdi dokumen atau google, itu kata yang cukup umum dan muncul di setiap halaman.

Apa yang dilakukan kata kunci dalam konteks itu?

Drew
sumber

Jawaban:

126
function isString(test: any): test is string{
    return typeof test === "string";
}

function example(foo: any){
    if(isString(foo)){
        console.log("it is a string" + foo);
        console.log(foo.length); // string function
    }
}
example("hello world");

Menggunakan predikat tipe "test is string" dalam format di atas (alih-alih hanya menggunakan boolean untuk tipe kembalian, setelah isString () dipanggil, jika fungsi mengembalikan nilai true, TypeScript akan mempersempit tipe menjadi string dalam blok apa pun yang dilindungi oleh memanggil fungsi tersebut. Kompilator akan berpikir bahwa foo adalah string di blok below-guarded (dan HANYA di blok below-guarded)

{
    console.log("it is a string" + foo);
    console.log(foo.length); // string function
}

Jenis predikat hanya digunakan dalam waktu kompilasi. Hasil file .js (runtime) tidak akan memiliki perbedaan karena tidak mempertimbangkan TYPE.

Saya akan mengilustrasikan perbedaan dalam empat contoh di bawah ini.

Misalnya 1: kode contoh di atas tidak akan memiliki kesalahan kompilasi dan kesalahan runtime.

Misalnya 2: kode contoh di bawah ini akan memiliki kesalahan kompilasi (serta kesalahan runtime) karena TypeScript telah mempersempit tipe menjadi string dan memeriksa bahwa toExponential bukan milik metode string.

function example(foo: any){
    if(isString(foo)){
        console.log("it is a string" + foo);
        console.log(foo.length);
        console.log(foo.toExponential(2));
    }
}

Misalnya 3: kode contoh di bawah ini tidak memiliki kesalahan kompilasi tetapi akan memiliki kesalahan runtime karena TypeScript HANYA akan mempersempit jenis menjadi string di blok yang dilindungi tetapi tidak setelahnya, oleh karena itu foo.toExponential tidak akan membuat kesalahan kompilasi (TypeScript tidak menganggapnya tipe string). Namun, dalam runtime, string tidak memiliki metode toExponential, sehingga akan mengalami error runtime.

function example(foo: any){
    if(isString(foo)){
        console.log("it is a string" + foo);
        console.log(foo.length);
    }
    console.log(foo.toExponential(2));
}

Misalnya 4: jika kita tidak menggunakan "test is string" (predikat tipe), TypeScript tidak akan mempersempit jenis di blok yang dilindungi dan kode contoh di bawah ini tidak akan memiliki kesalahan kompilasi tetapi akan memiliki kesalahan waktu proses.

function isString(test: any): boolean{
    return typeof test === "string";
}
function example(foo: any){
    if(isString(foo)){
        console.log("it is a string" + foo);
        console.log(foo.length);
        console.log(foo.toExponential(2));
    }
}

Kesimpulannya adalah bahwa "test is string" (predikat tipe) digunakan dalam waktu kompilasi untuk memberi tahu pengembang bahwa kode tersebut akan memiliki peluang untuk mengalami error runtime. Untuk javascript, pengembang tidak akan TAHU kesalahan pada waktu kompilasi. Ini adalah keuntungan menggunakan TypeScript.

ARIES CHUI
sumber
12

Satu-satunya penggunaan yang saya tahu adalah salah satu contoh Anda: menentukan "predikat tipe" ( arg is MyType) di Penjaga Jenis yang ditentukan pengguna

Lihat Pengaman Jenis yang Ditentukan Pengguna dalam referensi ini

Berikut referensi lainnya

Bruno Grieder
sumber
1
Saya melihat ini di dokumen juga, keputusan desain yang sangat aneh, kasus ini benar-benar dapat ditangani dengan mengembalikan tipe, booleanbukan?
benjaminz
2
@benjaminz Ini mungkin menjamin pertanyaan itu sendiri tentang SO tapi saya dapat menunjukkan kepada Anda contoh singkat tentang bagaimana mereka berbeda. Kata iskunci sebenarnya mentransmisikan jenis dan dapat menangkap kesalahan jenis nanti dalam kode. Lihat contoh ini untuk info lebih lanjut.
styfle
@benjaminz Saya tidak melihat bagaimana ini bisa ditangani oleh boolean. Ketikan perlu mengetahui bahwa fungsi yang Anda lewati suatu objek berfungsi seperti penjaga tipe. Jika itu hanya mengembalikan tipe benar atau salah, bagaimana Ketikan tahu bahwa itu memang penjaga tipe dan bukan hanya beberapa fungsi arbitrer yang mengembalikan nilai benar jika objeknya benar. Bagaimana cara mengetahui untuk mempersempit tipe objek? Kedua, bagaimana cara mengetahui tipe objek yang akan dipersempit? Bagaimana jika parameternya adalah salah satu dari tiga jenis? Perlu diketahui bahwa truesesuai dengan tipe tertentu.
pushkin