Typescript: Perbandingan dengan Sistem Jenis Aliran Facebook

Dibuat pada 25 Nov 2014  ·  31Komentar  ·  Sumber: microsoft/TypeScript

Penafian: Masalah ini tidak dimaksudkan untuk membuktikan bahwa aliran lebih baik atau lebih buruk daripada TypeScript, saya tidak ingin mengkritik karya luar biasa dari kedua tim, tetapi untuk membuat daftar perbedaan dalam sistem tipe Flow dan TypeScript dan mencoba mengevaluasi fitur mana dapat meningkatkan TypeScript.

Juga saya tidak akan berbicara tentang fitur yang hilang di Flow karena tujuannya adalah seperti yang dinyatakan untuk meningkatkan TypeScript.
Akhirnya topik ini hanya tentang sistem tipe dan bukan tentang fitur es6 / es7 yang didukung.

mixed dan any

Dari dokumen arus:

  • mixed: "supertipe" dari semua tipe. Jenis apapun bisa mengalir menjadi campuran.
  • any: tipe "dinamis". Tipe apapun bisa mengalir ke apapun, begitu pula sebaliknya

Pada dasarnya itu berarti bahwa dengan aliran any setara dengan TypeScript any dan mixed sama dengan TypeScript {} .

Jenis Object dengan aliran

Dari flow doc:

Gunakan campuran untuk memberi anotasi pada lokasi yang dapat mengambil apa saja, tetapi jangan gunakan Objek sebagai gantinya! Membingungkan untuk melihat segala sesuatu sebagai objek, dan jika kebetulan Anda memang bermaksud "objek apa pun", ada cara yang lebih baik untuk menentukannya, sama seperti ada cara untuk menentukan "fungsi apa pun".

Dengan TypeScript Object setara dengan {} dan menerima jenis apa pun, dengan Flow Object setara dengan {} tetapi berbeda dari mixed , itu hanya akan menerima Object (dan bukan tipe primitif lainnya seperti string , number , boolean , atau function ).

function logObjectKeys(object: Object): void {
  Object.keys(object).forEach(function (key) {
    console.log(key);
  });
}
logObjectKeys({ foo: 'bar' }); // valid with TypeScript and Flow
logObjectKeys(3); // valid with TypeScript, Error with flow

Dalam contoh ini, parameter logObjectKeys diberi tag dengan tipe Object , untuk TypeScript yang setara dengan {} dan karenanya akan menerima tipe apa pun, seperti number dalam kasus panggilan kedua logObjectKeys(3) .
Dengan Flow, tipe primitif lainnya tidak kompatibel dengan Object sehingga pemeriksa tipe akan melaporkan dan kesalahan dengan panggilan kedua logObjectKeys(3) : _number tidak kompatibel dengan Object_.

Jenisnya bukan nol

Dari flow doc:

Dalam JavaScript, null secara implisit mengonversi ke semua tipe primitif; itu juga merupakan penghuni yang sah dari semua tipe objek.
Sebaliknya, Flow menganggap null sebagai nilai berbeda yang bukan bagian dari jenis lainnya.

lihat bagian Flow doc

Karena dokumen alur cukup lengkap, saya tidak akan menjelaskan fitur ini secara detail, hanya perlu diingat bahwa ini memaksa pengembang untuk memiliki setiap variabel untuk diinisialisasi, atau ditandai sebagai nullable, contoh:

var test: string; // error undefined is not compatible with `string`
var test: ?string;
function getLength() {
  return test.length // error Property length cannot be initialized possibly null or undefined value
}

Namun seperti untuk fitur pelindung tipe TypeScript, aliran memahami pemeriksaan non-null:

var test: ?string;
function getLength() {
  if (test == null) {
    return 0;
  } else {
    return test.length; // no error
  }
}

function getLength2() {
  if (test == null) {
    test = '';
  }
  return test.length; // no error
}

Jenis Persimpangan

lihat bagian Flow doc
lihat Masalah Correspondin TypeScript # 1256

Seperti jenis penyatuan dukungan aliran TypeScript, ini juga mendukung cara baru untuk menggabungkan jenis: Jenis Persimpangan.
Dengan objek, tipe persimpangan seperti mendeklarasikan mixin:

type A = { foo: string; };
type B = { bar : string; };
type AB = A & B;

AB memiliki untuk tipe { foo: string; bar : string;} ;

Untuk fungsi, ini setara dengan mendeklarasikan overload:

type A = () => void & (t: string) => void
var func : A;

setara dengan:

interface A {
  (): void;
  (t: string): void;
}
var func: A

Tangkapan resolusi umum

Pertimbangkan contoh TypeScript berikut:

declare function promisify<A,B>(func: (a: A) => B):   (a: A) => Promise<B>;
declare function identity<A>(a: A):  A;

var promisifiedIdentity = promisify(identity);

Dengan TypeScript promisifiedIdentity akan memiliki untuk tipe:

(a: {}) => Promise<{}>`.

Dengan aliran promisifiedIdentity akan memiliki untuk tipe:

<A>(a: A) => Promise<A>

Ketik inferensi

Flow secara umum mencoba menyimpulkan lebih banyak tipe daripada TypeScript.

Inferensi parameter

Mari kita lihat contoh ini:

function logLength(obj) {
  console.log(obj.length);
}
logLength({length: 'hello'});
logLength([]);
logLength("hey");
logLength(3);

Dengan TypeScript, tidak ada kesalahan yang dilaporkan, dengan aliran panggilan terakhir logLength akan menghasilkan kesalahan karena number tidak memiliki properti length .

Jenis yang disimpulkan berubah dengan penggunaan

Dengan aliran kecuali Anda secara tegas mengetik variabel Anda, jenis variabel ini akan berubah dengan penggunaan variabel ini:

var x = "5"; // x is inferred as string
console.log(x.length); // ok x is a string and so has a length property
x = 5; // Inferred type is updated to `number`
x *= 5; // valid since x is now a number

Dalam contoh ini x awalnya string jenis, tetapi ketika ditetapkan ke nomor jenis telah diubah menjadi number .
Dengan skrip ketikan tugas x = 5 akan menghasilkan kesalahan karena x sebelumnya ditugaskan ke string dan tipenya tidak dapat diubah.

Inferensi jenis Union

Perbedaan lainnya adalah Flow menyebarkan inferensi tipe ke belakang untuk memperluas tipe inferensi ke dalam gabungan tipe. Contoh ini dari facebook / flow # 67 (komentar)

class A { x: string; }
class B extends A { y: number; }
class C extends A { z: number; }

function foo() {
    var a = new B();
    if (true) a = new C(); // TypeScript reports an error, because a's type is already too narrow
    a.x; // Flow reports no error, because a's type is correctly inferred to be B | C
}

("dengan benar" berasal dari postingan asli.)
Karena aliran mendeteksi bahwa variabel a dapat memiliki tipe B atau C bergantung pada pernyataan bersyarat, sekarang disimpulkan menjadi B | C , dan pernyataan a.x tidak menghasilkan kesalahan karena kedua tipe memiliki properti x , jika kita mencoba mengakses properti z dan kesalahan akan muncul.

Ini berarti yang berikut akan dikompilasi juga.

var x = "5"; // x is inferred as string
if ( true) { x = 5; } // Inferred type is updated to string | number
x.toString(); // Compiles
x += 5; // Compiles. Addition is defined for both string and number after all, although the result is very different

Edit

  • Memperbarui bagian mixed dan any , karena mixed sama dengan {} tidak perlu misalnya.
  • Bagian yang ditambahkan untuk tipe Object .
  • Menambahkan bagian tentang jenis inferensi

_Jangan ragu untuk memberi tahu jika saya lupa sesuatu, saya akan mencoba memperbarui masalah._

Question

Komentar yang paling membantu

Secara pribadi, tangkapan umum dan non-nullability adalah target bernilai _high_ dari Flow. Saya akan membaca utas lainnya, tetapi saya ingin memasukkan 2c saya di sini juga.

Saya terkadang merasa bahwa manfaat menambahkan non-nullability bernilai hampir semua biaya. Ini adalah kondisi kesalahan kemungkinan tinggi dan sementara memiliki nullability default melemahkan nilai bawaan saat ini TypeScript tidak memiliki kemampuan untuk bahkan mendiskusikan nullability dengan hanya mengasumsikan itu terjadi di mana-mana.

Saya akan memberi anotasi pada setiap variabel yang dapat saya temukan sebagai non-nullable dalam sekejap.

Semua 31 komentar

Ini menarik dan merupakan titik awal yang baik untuk diskusi lebih lanjut. Apakah Anda keberatan jika saya membuat beberapa perubahan pengeditan pada postingan asli agar lebih jelas?

Hal-hal tak terduga di Flow (akan memperbarui komentar ini saat saya menyelidikinya lebih lanjut)

Inferensi tipe argumen fungsi ganjil:

/** Inference of argument typing doesn't seem
    to continue structurally? **/
function fn1(x) { return x * 4; }
fn1('hi'); // Error, expected
fn1(42); // OK

function fn2(x) { return x.length * 4; }
fn2('hi'); // OK
fn2({length: 3}); // OK
fn2({length: 'foo'}); // No error (??)
fn2(42); // Causes error to be reported at function definition, not call (??)

Tidak ada jenis inferensi dari literal objek:

var a = { x: 4, y: 2 };
// No error (??)
if(a.z.w) { }

Ini menarik dan merupakan titik awal yang baik untuk diskusi lebih lanjut. Apakah Anda keberatan jika saya membuat beberapa perubahan pengeditan pada postingan asli agar lebih jelas?

Merasa bebas Seperti yang saya katakan, tujuannya adalah untuk mencoba menginvestasikan sistem tipe aliran untuk melihat apakah beberapa fitur dapat masuk ke dalam TypeScript.

@RyanCavanaugh saya kira contoh terakhir:

var a = { x: 4, y: 2 };
// No error (??)
if(a.z.w) { }

Apakah bug terkait dengan algoritma pemeriksaan nol mereka, saya akan melaporkannya.

Aku s

type A = () => void & (t: string) => void
var func : A;

Setara dengan

Declare A : () => void | (t: string) => void
var func : A;

Atau mungkinkah?

@ Davidhanson90 tidak juga:

declare var func: ((t: number) => void) | ((t: string) => void)

func(3); //error
func('hello'); //error

dalam contoh ini aliran tidak dapat mengetahui tipe mana dalam tipe gabungan func sehingga melaporkan kesalahan pada kedua kasus

declare var func: ((t: number) => void) & ((t: string) => void)

func(3); //no error
func('hello'); //no error

func memiliki kedua tipe sehingga kedua panggilan tersebut valid.

Apakah ada perbedaan yang dapat diamati antara {} di TypeScript dan mixed di Flow?

@RyanCavanaugh Saya tidak begitu tahu setelah berpikir saya pikir itu kurang lebih sama masih memikirkannya.

mixed tidak memiliki properti, bahkan tidak properti yang diwarisi dari Object.prototype yang dimiliki {} (# 1108) Ini salah.

Perbedaan lainnya adalah Flow menyebarkan inferensi tipe ke belakang untuk memperluas tipe inferensi ke dalam gabungan tipe. Contoh ini dari https://github.com/facebook/flow/issues/67#issuecomment -64221511

class A { x: string; }
class B extends A { y: number; }
class C extends A { z: number; }

function foo() {
    var a = new B();
    if (true) a = new C(); // TypeScript reports an error, because a's type is already too narrow
    a.x; // Flow reports no error, because a's type is correctly inferred to be B | C
}

("dengan benar" berasal dari postingan asli.)

Ini berarti yang berikut akan dikompilasi juga.

var x = "5"; // x is inferred as string
if ( true) { x = 5; } // Inferred type is updated to string | number
x.toString(); // Compiles
x += 5; // Compiles. Addition is defined for both string and number after all, although the result is very different

Edit: Menguji potongan kedua dan benar-benar dapat dikompilasi.
Edit 2: Seperti yang ditunjukkan oleh @fdecampredon di bawah ini, if (true) { } sekitar tugas kedua diperlukan agar Flow menyimpulkan jenisnya sebagai string | number . Tanpa if (true) itu disimpulkan sebagai number sebagai gantinya.

Apakah Anda menyukai perilaku ini? Kami melalui rute ini ketika kami membahas jenis serikat pekerja dan nilainya meragukan. Hanya karena sistem tipe sekarang memiliki kemampuan untuk memodelkan tipe dengan beberapa status yang mungkin tidak berarti itu diinginkan untuk digunakan di mana-mana. Seolah-olah Anda telah memilih untuk menggunakan bahasa dengan pemeriksa tipe statis karena Anda menginginkan kesalahan kompiler ketika Anda membuat kesalahan, bukan hanya karena Anda suka menulis anotasi tipe;) Artinya, kebanyakan bahasa memberikan kesalahan dalam contoh seperti ini (terutama yang kedua) bukan karena kurangnya cara untuk memodelkan ruang tipe tetapi karena mereka benar-benar percaya ini adalah kesalahan pengkodean (untuk alasan yang sama banyak yang menghindari mendukung banyak operasi transmisi / konversi implisit).

Dengan logika yang sama, saya mengharapkan perilaku ini:

declare function foo<T>(x:T, y: T): T;
var r = foo(1, "a"); // no problem, T is just string|number

tapi saya benar-benar tidak menginginkan perilaku itu.

@danquirk Saya setuju dengan Anda bahwa menyimpulkan jenis serikat secara otomatis daripada melaporkan kesalahan bukanlah perilaku yang saya suka.
Tapi saya pikir itu berasal dari filosofi aliran, lebih dari bahasa nyata, tim aliran mencoba untuk membuat pemeriksa tipe saja, tujuan akhir mereka adalah untuk dapat membuat kode 'lebih aman' tanpa penjelasan tipe apa pun. Ini mengarah menjadi kurang ketat.

Ketegasan yang tepat bahkan bisa diperdebatkan mengingat dampak dari perilaku semacam ini. Seringkali itu hanya menunda kesalahan (atau menyembunyikan seluruhnya). Aturan inferensi tipe lama kami untuk argumen tipe sangat mencerminkan filosofi yang serupa. Jika ragu, kami menyimpulkan {} untuk parameter tipe daripada menjadikannya kesalahan. Ini berarti Anda dapat melakukan beberapa hal konyol dan masih melakukan beberapa perilaku minimal dengan aman pada hasilnya (yaitu hal-hal seperti toString ). Alasannya adalah beberapa orang melakukan hal-hal konyol di JS dan kita harus mencoba untuk mengizinkan apa yang kita bisa. Namun dalam praktiknya, sebagian besar kesimpulan ke {} sebenarnya hanya kesalahan, dan membuat Anda menunggu hingga pertama kali Anda menandai variabel tipe T untuk menyadari bahwa itu adalah {} (atau juga tipe gabungan yang tidak terduga) dan kemudian menelusuri ke belakang sangat mengganggu. Jika Anda tidak pernah berhenti melakukannya (atau tidak pernah mengembalikan sesuatu dari tipe T) Anda tidak melihat kesalahan sama sekali sampai runtime ketika sesuatu meledak (atau lebih buruk, data yang rusak). Demikian pula:

declare function foo(arg: number);
var x = "5";
x = 5;
foo(x); // error

Apa kesalahannya di sini? Apakah benar-benar meneruskan x menjadi foo ? Atau apakah itu menetapkan kembali x nilai dari jenis yang sama sekali berbeda dari yang diinisialisasi? Seberapa sering orang dengan sengaja melakukan inisialisasi ulang semacam itu vs menginjak sesuatu secara tidak sengaja? Bagaimanapun, dengan menyimpulkan tipe gabungan untuk x dapatkah Anda benar-benar mengatakan sistem tipe kurang ketat secara keseluruhan jika masih menghasilkan kesalahan (lebih buruk)? Jenis kesimpulan ini tidak terlalu ketat jika Anda tidak pernah melakukan sesuatu yang sangat berarti dengan jenis yang dihasilkan, yang umumnya sangat jarang.

Bisa dibilang menyisakan null dan undefined dapat dialihkan ke semua jenis menyembunyikan kesalahan dengan cara yang sama, sering kali variabel yang diketik dengan beberapa jenis dan menyembunyikan nilai null akan mengarah ke kesalahan saat runtime.

Bagian yang tidak penting dari pemasaran Flow didasarkan pada fakta bahwa pemeriksa ketik mereka lebih memahami kode di tempat-tempat di mana TS akan menyimpulkan any . Filosofinya adalah Anda tidak perlu menambahkan anotasi untuk membuat compiler menyimpulkan tipe. Itu sebabnya dial inferensi mereka diubah ke pengaturan yang jauh lebih permisif daripada TypeScript.

Ini tergantung pada apakah seseorang memiliki ekspektasi bahwa var x = new B(); x = new C(); (dimana B dan C keduanya berasal dari A) harus dikompilasi atau tidak, dan jika ya, apa yang harus disimpulkan?

  1. Seharusnya tidak dikompilasi.
  2. Harus mengompilasi dan disimpulkan sebagai tipe dasar paling banyak yang umum untuk tipe hierarki B dan C - A. Untuk contoh bilangan dan string itu akan menjadi {}
  3. Harus dikompilasi dan disimpulkan sebagai B | C .

TS saat ini melakukan (1) dan Flow (3). Saya lebih suka (1) dan (2) lebih dari (3).

Saya ingin menambahkan contoh @Arnavion ke masalah aslinya tetapi setelah bermain sedikit saya menyadari bahwa hal-hal di mana lebih aneh daripada apa yang kami pahami.
Dalam contoh ini:

var x = "5"; // x is inferred as string
x = 5; // x is infered as number now
x.toString(); // Compiles, since number has a toString method
x += 5; // Compiles since x is a number
console.log(x.length) // error x is a number

Sekarang :

var x = '';
if (true) {
  x = 5;
}

setelah contoh ini x adalah string | number
Dan jika saya melakukannya:

1. var x = ''; 
2. if (true) {
3.  x = 5;
4. }
5. x*=5;

Saya mendapat kesalahan di baris 1 yang mengatakan: myFile.js line 1 string this type is incompatible with myFile.js line 5 number

Saya masih perlu memikirkan logika di sini ....

Ada juga hal menarik tentang flow yang saya lupa:

function test(t: Object) { }

test('string'); //error

Pada dasarnya 'Object' tidak kompatibel dengan tipe primitif lainnya, saya pikir itu masuk akal.

'Pengambilan resolusi generik' jelas merupakan fitur yang harus dimiliki untuk TS!

@Yaahhhh . Dengan var x = "5"; x = 5; x tipe inferensi diperbarui menjadi number . Dengan menambahkan if (true) { } sekitar tugas kedua, pemeriksa ketik ditipu untuk mengasumsikan bahwa salah satu tugas itu valid, itulah sebabnya jenis yang disimpulkan diperbarui menjadi number | string sebagai gantinya.

Kesalahan yang Anda dapatkan myFile.js line 1 string this type is incompatible with myFile.js line 5 number benar, karena number | string tidak mendukung operator * (satu-satunya operasi yang diperbolehkan pada tipe gabungan adalah perpotongan semua operasi pada semua tipe Persatuan). Untuk memverifikasi ini, Anda dapat mengubahnya menjadi x += 5 dan Anda akan melihatnya dikompilasi.

Saya telah memperbarui contoh di komentar saya untuk memiliki if (true)

'Pengambilan resolusi generik' jelas merupakan fitur yang harus dimiliki untuk TS!

+1

@Arnavion , tidak yakin mengapa Anda lebih memilih {} daripada B | C . Menyisipkan B | C memperluas kumpulan program yang memeriksa tanpa mengorbankan kebenaran yang afaik adalah properti yang umumnya diinginkan dari sistem tipe.

Contoh

declare function foo<T>(x:T, y: T): T;
var r = foo(1, "a"); // no problem, T is just string|number

sudah salah ketik di bawah kompilator saat ini, kecuali T disimpulkan menjadi {} daripada string | number . Ini tidak mengkompromikan kebenaran tetapi secara umum kurang berguna.

Menyisipkan number | string alih-alih {} sepertinya tidak menjadi masalah bagi saya. Dalam kasus tertentu itu tidak memperluas kumpulan program yang valid, namun jika tipe berbagi struktur, sistem tipe menyadari itu dan membuat beberapa metode tambahan dan / atau properti yang valid tampaknya hanya seperti perbaikan.

Menyimpang B | C memperlebar kumpulan program yang salah ketik tanpa mengorbankan kebenaran

Saya pikir mengizinkan operasi + pada sesuatu yang bisa berupa string atau angka akan mengorbankan kebenaran, karena operasinya tidak sama satu sama lain. Ini tidak seperti situasi di mana operasi berada pada kelas basis umum (opsi saya 2) - dalam hal ini Anda dapat mengharapkan beberapa kesamaan.

Operator + tidak dapat dipanggil, karena akan memiliki dua kelebihan yang tidak kompatibel - satu di mana kedua argumen adalah angka, dan satu lagi di mana keduanya adalah string. Sejak B | C lebih sempit dari kedua string dan angka, itu tidak akan diizinkan sebagai argumen dalam kelebihan beban.

Kecuali fungsi adalah bivarian dengan argumen mereka sehingga mungkin menjadi masalah?

Saya berpikir bahwa karena var foo: string; console.log(foo + 5); console.log(foo + document); mengkompilasi bahwa string + operator memperbolehkan apapun di sisi kanan, jadi string | number akan memiliki + <number> sebagai operasi yang valid. Tapi Anda benar:

error TS2365: Operator '+' cannot be applied to types 'string | number' and 'number'.

Banyak komentar berfokus pada pelebaran otomatis jenis di Flow. Dalam kedua kasus, Anda dapat memiliki perilaku yang Anda inginkan dengan menambahkan anotasi. Dalam TS Anda akan memperluas secara eksplisit pada deklarasi: var x: number|string = 5; dan di Flow Anda akan membatasi pada deklarasi: var x: number = 5; . Saya pikir case yang tidak memerlukan deklarasi tipe haruslah yang paling sering digunakan orang. Dalam proyek saya, saya mengharapkan var x = 5; x = 'five'; menjadi kesalahan lebih sering daripada jenis serikat pekerja. Jadi saya akan mengatakan TS mendapatkan kesimpulan yang tepat untuk yang satu ini.

Adapun fitur Flow yang menurut saya paling berharga?

  1. Tipe bukan nol
    Menurut saya yang satu ini memiliki potensi yang sangat tinggi untuk mengurangi bug. Untuk kompatibilitas dengan definisi TS yang ada, saya membayangkannya lebih sebagai pengubah non-null string! daripada pengubah nullable Flow ?string . Saya melihat tiga masalah dengan ini:
    Bagaimana menangani inisialisasi anggota kelas? _ (mungkin mereka harus ditugaskan di ctor dan jika mereka dapat melarikan diri dari ctor sebelum penugasan mereka dianggap nullable) _
    Bagaimana menangani undefined ? _ (Alur langkah-langkah masalah ini) _
    Bisakah itu bekerja tanpa banyak deklarasi tipe eksplisit?
  2. Selisih antara mixed dan Object .
    Karena tidak seperti tipe primitif C # tidak bisa digunakan dimanapun obyek bisa. Coba Object.keys(3) di browser Anda dan Anda akan mendapatkan kesalahan. Tetapi ini tidak kritis karena saya pikir kasus tepi sedikit.
  3. Tangkapan resolusi generik
    Contoh itu masuk akal. Tetapi saya tidak dapat mengatakan bahwa saya sedang menulis banyak kode yang akan mendapat manfaat dari itu. Mungkin itu akan membantu dengan pustaka fungsional seperti Underscore?

Pada inferensi tipe gabungan otomatis: Saya berasumsi "tipe inferensi" dibatasi untuk deklarasi tipe. Mekanisme yang secara implisit menyimpulkan deklarasi tipe yang dihilangkan. Seperti := di Go. Saya bukan ahli teori tipe, tapi sejauh yang saya mengerti, inferensi tipe adalah pass kompilator yang menambahkan anotasi tipe eksplisit ke setiap deklarasi variabel implisit (atau argumen fungsi), disimpulkan dari tipe ekspresi yang ditugaskan darinya. Sejauh yang saya tahu, ini adalah cara kerjanya untuk .. yah .. setiap jenis mekanisme inferensi di luar sana. C #, Haskell, Go, mereka semua bekerja seperti ini. Atau tidak?

Saya memahami argumen tentang membiarkan JS kehidupan nyata menggunakan mendikte semantik TS, tetapi ini mungkin poin yang baik untuk mengikuti bahasa lain, sebagai gantinya. Jenis adalah satu-satunya perbedaan yang menentukan antara JS dan TS.

Saya suka banyak ide Flux, tapi yang ini, yah, jika benar-benar dilakukan seperti ini ... itu aneh.

Tipe bukan nol sepertinya fitur wajib untuk sistem tipe modern. Apakah mudah menambahkan ts?

Jika Anda ingin sedikit membaca tentang kerumitan menambahkan tipe non-nullable ke TS, lihat https://github.com/Microsoft/TypeScript/issues/185

Cukuplah untuk mengatakan, sebagus tipe non-nullable adalah sebagian besar bahasa populer saat ini tidak memiliki tipe non-nullable secara default (yang mana fitur tersebut benar-benar bersinar) atau fitur non-nullability umum sama sekali. Dan hanya sedikit, jika ada, yang mencoba menambahkannya (atau berhasil menambahkannya) setelah fakta karena kompleksitas dan fakta bahwa begitu banyak nilai non-nullability terletak di dalamnya menjadi default (mirip dengan immutability). Ini bukan untuk mengatakan kami tidak mempertimbangkan kemungkinan di sini, tetapi saya juga tidak akan menyebutnya sebagai fitur wajib.

Sebenarnya meskipun saya merindukan tipe non-null, fitur sebenarnya yang saya lewatkan dari flow adalah penangkapan generik, fakta bahwa ts menyelesaikan setiap generik menjadi {} membuatnya sangat sulit untuk digunakan dengan beberapa konstruksi fungsional, terutama kari.

Secara pribadi, tangkapan umum dan non-nullability adalah target bernilai _high_ dari Flow. Saya akan membaca utas lainnya, tetapi saya ingin memasukkan 2c saya di sini juga.

Saya terkadang merasa bahwa manfaat menambahkan non-nullability bernilai hampir semua biaya. Ini adalah kondisi kesalahan kemungkinan tinggi dan sementara memiliki nullability default melemahkan nilai bawaan saat ini TypeScript tidak memiliki kemampuan untuk bahkan mendiskusikan nullability dengan hanya mengasumsikan itu terjadi di mana-mana.

Saya akan memberi anotasi pada setiap variabel yang dapat saya temukan sebagai non-nullable dalam sekejap.

Ada cukup banyak fitur tersembunyi dalam aliran, tidak didokumentasikan di situs aliran. Termasuk tipe terikat dan eksistensial SuperType

http://sitr.us/2015/05/31/advanced-features-in-flow.html

Apakah halaman ini membantu?
0 / 5 - 0 peringkat

Masalah terkait

fwanicka picture fwanicka  ·  3Komentar

manekinekko picture manekinekko  ·  3Komentar

jbondc picture jbondc  ·  3Komentar

kyasbal-1994 picture kyasbal-1994  ·  3Komentar

siddjain picture siddjain  ·  3Komentar