Mengumumkan TypeScript 3.4 RC

Beberapa hari yang lalu kami mengumumkan ketersediaan kandidat rilis kami (RC) dari TypeScript 3.4. Harapan kami adalah untuk mengumpulkan umpan balik dan masalah awal untuk memastikan rilis akhir kami mudah untuk diambil dan digunakan segera.


Untuk mulai menggunakan RC, Anda bisa mendapatkannya melalui NuGet , atau menggunakan npm dengan perintah berikut:


npm install -g typescript@rc 

Anda juga dapat memperoleh dukungan editor dengan



Mari menjelajahi apa yang baru dalam 3.4!




Artikel ini di blog kami.

--incremental selanjutnya yang lebih cepat dengan bendera --incremental


Karena file TypeScript dikompilasi, itu memperkenalkan langkah menengah antara menulis dan menjalankan kode Anda. Salah satu tujuan kami adalah untuk meminimalkan waktu yang dibuat mengingat perubahan apa pun pada program Anda. Salah satu cara untuk melakukannya adalah dengan menjalankan TypeScript dalam mode --watch . Ketika file berubah dalam mode --watch , TypeScript dapat menggunakan grafik dependensi proyek Anda yang telah dibangun sebelumnya untuk menentukan file mana yang berpotensi terpengaruh dan perlu diperiksa ulang dan berpotensi dipancarkan kembali. Ini dapat menghindari pengecekan tipe-penuh dan memancarkan kembali yang bisa mahal.


Tapi itu tidak realistis untuk mengharapkan semua pengguna untuk menjaga tsc --watch proses tsc --watch berjalan semalam hanya untuk membangun lebih cepat besok pagi. Bagaimana dengan cold build? Selama beberapa bulan terakhir, kami telah berupaya untuk melihat apakah ada cara untuk menyimpan informasi yang sesuai dari mode --watch ke file dan menggunakannya dari build hingga build.


TypeScript 3.4 memperkenalkan flag baru bernama --incremental yang memberitahu TypeScript untuk menyimpan informasi tentang grafik proyek dari kompilasi terakhir. Saat berikutnya TypeScript dipanggil dengan --incremental , itu akan menggunakan informasi itu untuk mendeteksi cara paling murah untuk mengetik-periksa dan memancarkan perubahan pada proyek Anda.


 // tsconfig.json { "compilerOptions": { "incremental": true, "outDir": "./lib" }, "include": ["./src"] } 

Secara default dengan pengaturan ini, ketika kita menjalankan tsc , TypeScript akan mencari file bernama .tsbuildinfo di direktori output kami ( ./lib ). Jika ./lib/.tsbuildinfo tidak ada, itu akan dihasilkan. Tetapi jika ya, tsc akan mencoba menggunakan file itu untuk secara bertahap mengetikkan dan memperbarui file output kami.


File .tsbuildinfo ini dapat dihapus dengan aman dan tidak berdampak pada kode kami saat runtime - mereka murni digunakan untuk membuat kompilasi lebih cepat. Kita juga dapat memberi nama mereka apa pun yang kita inginkan, dan menempatkannya di mana saja yang kita inginkan menggunakan flag --tsBuildInfoFile .


 // front-end.tsconfig.json { "compilerOptions": { "incremental": true, "tsBuildInfoFile": "./buildcache/front-end", "outDir": "./lib" }, "include": ["./src"] } 

Selama tidak ada orang lain yang mencoba menulis ke file cache yang sama, kita harus dapat menikmati build dingin inkremental yang lebih cepat.


Proyek komposit


Bagian dari maksud dengan proyek komposit ( tsconfig.json 's dengan set composite ke true ) adalah bahwa referensi antara proyek yang berbeda dapat dibangun secara bertahap. Dengan demikian, proyek komposit akan selalu menghasilkan file .tsbuildinfo .


outFile


Ketika outFile digunakan, nama file informasi build akan didasarkan pada nama file output. Sebagai contoh, jika file JavaScript output kami adalah ./output/foo.js , maka di bawah flag --incremental, TypeScript akan menghasilkan file ./output/foo.tsbuildinfo . Seperti di atas, ini dapat dikontrol dengan flag --tsBuildInfoFile .


Format file dan versi - --incremental


Meskipun file yang dihasilkan oleh --incremental adalah JSON, file tersebut tidak berarti dikonsumsi oleh alat lain. Kami tidak dapat memberikan jaminan stabilitas untuk isinya, dan pada kenyataannya, kebijakan kami saat ini adalah bahwa salah satu versi dari TypeScript tidak akan mengerti file .tsbuildinfo dihasilkan dari versi lain.


Perbaikan untuk ReadonlyArray dan readonly tuple


TypeScript 3.4 membuatnya sedikit lebih mudah untuk menggunakan tipe read-only array-like.


Sintaks baru untuk ReadonlyArray


Tipe ReadonlyArray menggambarkan Array s yang hanya dapat dibaca. Variabel apa pun dengan pegangan ke ReadonlyArray tidak dapat menambah, menghapus, atau mengganti elemen array apa pun.


 function foo(arr: ReadonlyArray<string>) { arr.slice(); // okay arr.push("hello!"); // error! } 

Meskipun sering kali merupakan praktik yang baik untuk menggunakan ReadonlyArray atas Array untuk tujuan maksud, sering kali terasa menyakitkan karena array memiliki sintaks yang lebih bagus. Secara khusus, number[] adalah versi singkatan dari Array<number> , sama seperti Date[] adalah singkatan untuk Array<Date> .


TypeScript 3.4 memperkenalkan sintaks baru untuk ReadonlyArray menggunakan pengubah readonly baru untuk tipe array.


 function foo(arr: readonly string[]) { arr.slice(); // okay arr.push("hello!"); // error! } 

tuple readonly


TypeScript 3.4 juga memperkenalkan dukungan baru untuk tuple readonly . Kita dapat mengawali setiap jenis tuple dengan kata kunci readonly untuk menjadikannya tuple readonly , seperti halnya kita sekarang dapat dengan sintaksis array shorthand. Seperti yang Anda duga, tidak seperti tuple biasa yang slotnya dapat ditulis, tuple readonly hanya mengizinkan pembacaan dari posisi itu.


 function foo(pair: readonly [string, string]) { console.log(pair[0]); // okay pair[1] = "hello!"; // error } 

Cara yang sama dengan tupel biasa adalah tipe yang memanjang dari Array - tuple dengan elemen tipe T 1 , T 2 , ... T n memanjang dari Array< T 1 | T 2 | ... T n > - readonly tuple adalah tipe yang diperluas dari ReadonlyArray . Jadi tuple readonly dengan elemen T 1 , T 2 , ... T n memanjang dari ReadonlyArray< T 1 | T 2 | ... T n > .


pengubah tipe readonly dipetakan dan array readonly


Dalam versi sebelumnya dari TypeScript, kami menggeneralisasi tipe yang dipetakan untuk beroperasi secara berbeda pada tipe array-like. Ini berarti bahwa tipe yang dipetakan seperti Boxify dapat bekerja pada array dan tuple.


 interface Box<T> { value: T } type Boxify<T> = { [K in keyof T]: Box<T[K]> } // { a: Box<string>, b: Box<number> } type A = Boxify<{ a: string, b: number }>; // Array<Box<number>> type B = Boxify<number[]>; // [Box<string>, Box<number>] type C = Boxify<[string, boolean]>; 

Sayangnya, tipe yang dipetakan seperti tipe utilitas Readonly secara efektif no-ops pada tipe array dan tuple.


 // lib.d.ts type Readonly<T> = { readonly [K in keyof T]: T[K] } // How code acted *before* TypeScript 3.4 // { readonly a: string, readonly b: number } type A = Readonly<{ a: string, b: number }>; // number[] type B = Readonly<number[]>; // [string, boolean] type C = Readonly<[string, boolean]>; 

Dalam TypeScript 3.4, pengubah readonly dalam tipe yang dipetakan akan secara otomatis mengkonversi tipe seperti array ke rekan readonly sesuai.


 // How code acts now *with* TypeScript 3.4 // { readonly a: string, readonly b: number } type A = Readonly<{ a: string, b: number }>; // readonly number[] type B = Readonly<number[]>; // readonly [string, boolean] type C = Readonly<[string, boolean]>; 

Demikian pula, Anda dapat menulis jenis utilitas seperti jenis dipetakan Writable yang menghapus readness -ness, dan yang akan mengkonversi wadah array readonly kembali ke setara mereka yang bisa berubah.


 type Writable<T> = { -readonly [K in keyof T]: T[K] } // { a: string, b: number } type A = Writable<{ readonly a: string; readonly b: number }>; // number[] type B = Writable<readonly number[]>; // [string, boolean] type C = Writable<readonly [string, boolean]>; 

Peringatan


Terlepas dari kemunculannya, pengubah tipe hanya- readonly hanya dapat digunakan untuk sintaks pada tipe array dan tipe tuple. Ini bukan tipe operator tujuan umum.


 let err1: readonly Set<number>; // error! let err2: readonly Array<boolean>; // error! let okay: readonly boolean[]; // works fine 

pernyataan const


Ketika mendeklarasikan variabel atau properti yang bisa berubah, TypeScript sering memperluas nilai untuk memastikan bahwa kita dapat menetapkan hal-hal nanti tanpa menulis tipe eksplisit.


 let x = "hello"; // hurray! we can assign to 'x' later on! x = "world"; 

Secara teknis, setiap nilai literal memiliki tipe literal. Di atas, tipe "hello" diperlebar ke string tipe sebelum menyimpulkan tipe untuk x .


Salah satu pandangan alternatif mungkin mengatakan bahwa x memiliki tipe literal asli "hello" dan bahwa kita tidak dapat menetapkan "world" nanti seperti:


 let x: "hello" = "hello"; // error! x = "world"; 

Dalam hal ini, itu tampak ekstrem, tetapi dapat berguna dalam situasi lain. Sebagai contoh, TypeScripters sering membuat objek yang dimaksudkan untuk digunakan dalam serikat yang didiskriminasi.


 type Shape = | { kind: "circle", radius: number } | { kind: "square", sideLength: number } function getShapes(): readonly Shape[] { let result = [ { kind: "circle", radius: 100, }, { kind: "square", sideLength: 50, }, ]; // Some terrible error message because TypeScript inferred // 'kind' to have the type 'string' instead of // either '"circle"' or '"square"'. return result; } 

Mutability adalah salah satu heuristik niat terbaik yang TypeScript dapat gunakan untuk menentukan kapan harus melebar (daripada menganalisis seluruh program kami).


Sayangnya, seperti yang kita lihat pada contoh terakhir, dalam properti JavaScript bisa berubah secara default. Ini berarti bahwa bahasa tersebut akan sering memperluas jenis yang tidak diinginkan, membutuhkan jenis eksplisit di tempat-tempat tertentu.


 function getShapes(): readonly Shape[] { // This explicit annotation gives a hint // to avoid widening in the first place. let result: readonly Shape[] = [ { kind: "circle", radius: 100, }, { kind: "square", sideLength: 50, }, ]; return result; } 

Sampai pada titik tertentu ini tidak apa-apa, tetapi karena struktur data kami menjadi semakin kompleks, ini menjadi rumit.


Untuk mengatasi ini, TypeScript 3.4 memperkenalkan konstruksi baru untuk nilai-nilai literal yang disebut pernyataan const . Sintaksnya adalah pernyataan tipe dengan const menggantikan nama tipe (mis. 123 as const ). Ketika kita membangun ekspresi literal baru dengan pernyataan const , kita dapat memberi sinyal ke bahasa itu


  • tidak ada tipe literal dalam ekspresi yang harus diperlebar (mis. tidak beralih dari "hello" ke string )
  • objek literal mendapatkan properti hanya readonly
  • array literal menjadi tupel hanya readonly

 // Type '10' let x = 10 as const; // Type 'readonly [10, 20]' let y = [10, 20] as const; // Type '{ readonly text: "hello" }' let z = { text: "hello" } as const; 

Di luar file .tsx , sintaks pernyataan braket sudut juga dapat digunakan.


 // Type '10' let x = <const>10; // Type 'readonly [10, 20]' let y = <const>[10, 20]; // Type '{ readonly text: "hello" }' let z = <const>{ text: "hello" }; 

Fitur ini sering berarti bahwa tipe-tipe yang seharusnya digunakan hanya untuk mengisyaratkan ketidakberubahan pada kompiler seringkali dapat dihilangkan.


 // Works with no types referenced or declared. // We only needed a single const assertion. function getShapes() { let result = [ { kind: "circle", radius: 100, }, { kind: "square", sideLength: 50, }, ] as const; return result; } for (const shape of getShapes()) { // Narrows perfectly! if (shape.kind === "circle") { console.log("Circle radius", shape.radius); } else { console.log("Square side length", shape.sideLength); } } 

Perhatikan penjelasan di atas tidak diperlukan jenis. Pernyataan const memungkinkan TypeScript untuk mengambil tipe ekspresi yang paling spesifik.


Peringatan


Satu hal yang perlu diperhatikan adalah bahwa pernyataan const hanya dapat diterapkan segera pada ekspresi literal sederhana.


 // Error! // A 'const' assertion can only be applied to a string, number, boolean, array, or object literal. let a = (Math.random() < 0.5 ? 0 : 1) as const; // Works! let b = Math.random() < 0.5 ? 0 as const : 1 as const; 

Hal lain yang perlu diingat adalah bahwa konteks const tidak segera mengubah ekspresi menjadi tidak berubah sepenuhnya.


 let arr = [1, 2, 3, 4]; let foo = { name: "foo", contents: arr, }; foo.name = "bar"; // error! foo.contents = []; // error! foo.contents.push(5); // ...works! 

Ketik-periksa untuk globalThis


Bisa jadi sangat sulit untuk mengakses atau mendeklarasikan nilai dalam lingkup global, mungkin karena kita sedang menulis kode kita dalam modul (yang deklarasi lokalnya tidak bocor secara default), atau karena kita mungkin memiliki variabel lokal yang membayangi nama nilai global. Di lingkungan yang berbeda, ada berbagai cara untuk mengakses apa yang secara efektif ruang lingkup global - global di Node, window , self , atau frames di browser, atau this di lokasi tertentu di luar mode ketat. Tidak ada yang jelas, dan sering membuat pengguna merasa tidak yakin apakah mereka menulis kode yang benar.


TypeScript 3.4 memperkenalkan dukungan untuk pengecekan tipe-global ECMAScript baru ini - variabel global yang mengacu pada cakupan global. Berbeda dengan solusi di atas, globalThis memberikan cara standar untuk mengakses ruang lingkup global yang dapat digunakan di berbagai lingkungan.


 // in a global file: let abc = 100; // Refers to 'abc' from above. globalThis.abc = 200; 

globalThis juga dapat mencerminkan apakah variabel global dideklarasikan sebagai const dengan memperlakukannya sebagai properti hanya readonly saat diakses.


 const answer = 42; globalThis.answer = 333333; // error! 

Penting untuk dicatat bahwa TypeScript tidak mengubah referensi ke globalThis ketika mengkompilasi ke versi ECMAScript yang lebih lama. Dengan demikian, kecuali Anda menargetkan browser yang selalu hijau (yang sudah mendukung globalThis ), Anda mungkin ingin menggunakan polyfill yang sesuai sebagai gantinya.


Konversikan ke parameter bernama


Terkadang, daftar parameter mulai menjadi berat.


 function updateOptions( hue?: number, saturation?: number, brightness?: number, positionX?: number, positionY?: number positionZ?: number) { // .... } 

Dalam contoh di atas, terlalu mudah bagi penelepon untuk mencampur urutan argumen yang diberikan. Pola JavaScript yang umum adalah sebagai gantinya menggunakan "objek opsi", sehingga setiap opsi secara eksplisit diberi nama dan urutan tidak pernah masalah. Ini mengemulasi fitur yang oleh bahasa lain disebut "parameter bernama".


 interface Options { hue?: number, saturation?: number, brightness?: number, positionX?: number, positionY?: number positionZ?: number } function updateOptions(options: Options = {}) { // .... } 

Tim TypeScript tidak hanya bekerja pada kompiler - kami juga menyediakan fungsionalitas yang editor gunakan untuk fitur yang kaya seperti penyelesaian, pergi ke definisi, dan refactor. Dalam TypeScript 3.4, staf magang kami Gabriela Britto telah menerapkan refactoring baru untuk mengonversi fungsi yang ada untuk menggunakan pola "bernama parameter" ini.


Refactoring sedang diterapkan ke fungsi untuk membuatnya mengambil parameter bernama.


Meskipun kami dapat mengubah nama fitur dengan rilis final 3.4 kami dan kami percaya mungkin ada ruang untuk beberapa ergonomi, kami akan senang bagi Anda untuk mencoba fitur tersebut dan memberi kami umpan balik Anda.


Memecah perubahan


Level this ini sekarang diketik


Jenis tingkat this ini sekarang diketik sebagai jenis typeof globalThis bukan any . Sebagai konsekuensinya, Anda mungkin menerima kesalahan untuk mengakses nilai yang tidak diketahui pada this bawah noImplicitAny .


 // previously okay in noImplicitAny, now an error this.whargarbl = 10; 

Perhatikan bahwa kode yang dikompilasi di bawah noImplicitThis tidak akan mengalami perubahan apa pun di sini.


Argumen tipe umum yang disarankan


Dalam kasus-kasus tertentu, inferensi TypeScript 3.4 yang ditingkatkan mungkin menghasilkan fungsi yang generik, bukan yang mengambil dan mengembalikan kendala mereka (biasanya {} ).


 declare function compose<T, U, V>(f: (arg: T) => U, g: (arg: U) => V): (arg: T) => V; function list<T>(x: T) { return [x]; } function box<T>(value: T) { return { value }; } let f = compose(list, box); let x = f(100) // In TypeScript 3.4, 'x.value' has the type // // number[] // // but it previously had the type // // {}[] // // So it's now an error to push in a string. x.value.push("hello"); 

Anotasi jenis eksplisit pada x dapat menghilangkan kesalahan.


Apa selanjutnya


TypeScript 3.4 adalah rilis pertama kami yang memiliki rencana iterasi yang menguraikan rencana kami untuk rilis ini, yang dimaksudkan untuk menyelaraskan dengan peta jalan 6 bulan kami . Anda dapat mengawasi keduanya, dan pada halaman roadmap fitur bergulir kami untuk pekerjaan yang akan datang.


Saat ini kami sedang menantikan untuk mendengar tentang pengalaman Anda dengan RC, jadi cobalah sekarang dan beri tahu kami pendapat Anda!

Source: https://habr.com/ru/post/id443996/


All Articles