Typescript: مقارنة مع Facebook Flow Type System

تم إنشاؤها على ٢٥ نوفمبر ٢٠١٤  ·  31تعليقات  ·  مصدر: microsoft/TypeScript

إخلاء المسؤولية: ليس الغرض من هذه المشكلة إثبات أن التدفق أفضل أو أسوأ من TypeScript ، ولا أريد أن أنتقد الأعمال المذهلة لكلا الفريقين ، لكني أريد سرد الاختلافات في نظام كتابة Flow و TypeScript ومحاولة تقييم الميزة يمكن أن تحسن TypeScript.

كما أنني لن أتحدث عن الميزات المفقودة في Flow لأن الغرض مذكور لتحسين TypeScript.
أخيرًا ، يتعلق هذا الموضوع فقط بنظام الكتابة وليس حول ميزات es6 / es7 المدعومة.

mixed و any

من مستند التدفق:

  • مختلط: "النوع الفائق" لجميع الأنواع. يمكن لأي نوع أن يتدفق إلى خليط.
  • أي: النوع "الديناميكي". يمكن لأي نوع أن يتدفق إلى أي نوع ، والعكس صحيح

هذا يعني أن التدفق any يعادل TypeScript any و mixed يعادل TypeScript {} .

النوع Object مع التدفق

من مستند التدفق:

استخدم مختلط لإضافة تعليق توضيحي لموقع يمكن أن يأخذ أي شيء ، لكن لا تستخدم الكائن بدلاً من ذلك! من المربك النظر إلى كل شيء على أنه كائن ، وإذا كنت تعني بأي حال من الأحوال "أي كائن" ، فهناك طريقة أفضل لتحديد ذلك ، تمامًا كما توجد طريقة لتحديد "أي وظيفة".

مع TypeScript Object ما يعادل {} ويقبل أي نوع ، مع Flow Object ما يعادل {} لكنه يختلف عن mixed ، لن يقبل إلا العنصر (وليس الأنواع البدائية الأخرى مثل string أو number أو boolean أو 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

في هذا المثال ، تم تمييز المعلمة logObjectKeys بالنوع Object ، لـ TypeScript الذي يعادل {} ولذا فإنه سيقبل أي نوع ، مثل number في حالة المكالمة الثانية logObjectKeys(3) .
باستخدام Flow ، لا تتوافق الأنواع الأولية الأخرى مع Object ولذا فإن مدقق النوع سيبلغ عن الخطأ في الاستدعاء الثاني logObjectKeys(3) : _number غير متوافق مع Object_.

النوع غير فارغ

من مستند التدفق:

في JavaScript ، يتحول null ضمنيًا إلى جميع الأنواع الأولية ؛ إنه أيضًا ساكن صالح لأي نوع كائن.
على النقيض من ذلك ، يعتبر Flow أن القيمة الفارغة هي قيمة مميزة ليست جزءًا من أي نوع آخر.

انظر قسم مستند التدفق

نظرًا لأن مستند التدفق مكتمل جدًا ، فلن أصف هذه الميزة بالتفصيل ، فقط ضع في اعتبارك أنه يجبر المطور على تهيئة كل المتغيرات ، أو وضع علامة عليها على أنها لاغية:

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
}

ومع ذلك ، كما هو الحال بالنسبة لميزة حارس TypeScript ، فإن التدفق يفهم الاختيار غير الفارغ:

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
}

نوع التقاطع

انظر قسم مستند التدفق
راجع إصدار المراسلة من TypeScript # 1256

مثل دعم تدفق TypeScript لأنواع الاتحاد ، فإنه يدعم أيضًا طريقة جديدة لدمج الأنواع: أنواع التقاطع.
مع الكائن ، تشبه أنواع التقاطع إعلان مزيج:

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

AB لديه لنوع { foo: string; bar : string;} ؛

بالنسبة للوظائف ، فإن ذلك يعادل إعلان الحمل الزائد:

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

يعادل:

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

التقاط الدقة العامة

ضع في اعتبارك مثال TypeScript التالي:

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

var promisifiedIdentity = promisify(identity);

مع TypeScript promisifiedIdentity سيكون للنوع:

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

مع التدفق promisifiedIdentity سيكون للنوع:

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

اكتب الاستدلال

يحاول التدفق بشكل عام استنتاج نوع أكثر من TypeScript.

استنتاج المعلمات

دعنا نلقي نظرة على هذا المثال:

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

باستخدام TypeScript ، لا يتم الإبلاغ عن أي أخطاء ، مع التدفق ، ستؤدي المكالمة الأخيرة logLength إلى حدوث خطأ لأن number لا يحتوي على خاصية length .

يتغير النوع المستنتج مع الاستخدام

مع flow ما لم تكتب المتغير صراحةً ، فإن نوع هذا المتغير سيتغير مع استخدام هذا المتغير:

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

في هذا المثال ، يكون لدى x نوع string مبدئيًا ، ولكن عند تعيينه لرقم تم تغيير النوع إلى number .
باستخدام الكتابة المطبوعة ، ستؤدي التخصيص x = 5 إلى حدوث خطأ نظرًا لأنه تم تعيين x سابقًا إلى string ولا يمكن تغيير نوعه.

استدلال أنواع الاتحاد

الفرق الآخر هو أن Flow ينتشر استدلال النوع للخلف لتوسيع النوع المستنتج إلى اتحاد نوع. هذا المثال من facebook / flow # 67 (تعليق)

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
}

("بشكل صحيح" من المشاركة الأصلية.)
نظرًا لأن التدفق اكتشف أن المتغير a يمكن أن يكون له نوع B أو C النوع اعتمادًا على العبارة الشرطية ، يتم استنتاجه الآن إلى B | C ، وهكذا لا ينتج عن العبارة a.x خطأ نظرًا لأن كلا النوعين لهما خاصية x ، إذا كنا سنحاول الوصول إلى الخاصية z وكان الخطأ قد ظهر.

هذا يعني أن ما يلي سيتم تجميعه أيضًا.

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

تعديل

  • تم تحديث القسم mixed و any ، نظرًا لأن mixed يعادل {} فلا حاجة على سبيل المثال.
  • تمت إضافة قسم للنوع Object .
  • قسم مضاف على نوع الاستدلال

_ لا تتردد في إبلاغك إذا نسيت شيئًا ما سأحاول تحديث المشكلة ._

Question

التعليق الأكثر فائدة

شخصيًا ، يعتبر الالتقاط العام وعدم قابلية الإبطال أهدافًا ذات قيمة عالية من التدفق. سأقرأ الخيط الآخر ، لكنني أردت أن أضع 2c هنا أيضًا.

أشعر أحيانًا أن ميزة إضافة عدم الإلغاء تساوي أي تكلفة تقريبًا. إنها حالة خطأ ذات احتمالية عالية ، وبينما يؤدي وجود قابلية افتراضية افتراضية إلى إضعاف القيمة المضمنة في الوقت الحالي ، تفتقر TypeScript إلى القدرة حتى على مناقشة قابلية العدول من خلال افتراض أنها الحالة في كل مكان.

أود أن أعلق توضيحيًا على كل متغير يمكن أن أجده غير قابل للإلغاء في ضربات القلب.

ال 31 كومينتر

هذا مثير للاهتمام ونقطة انطلاق جيدة لمزيد من المناقشة. هل تمانع إذا قمت بإجراء بعض تغييرات التحرير على المنشور الأصلي للتوضيح؟

أشياء غير متوقعة في Flow (سيتم تحديث هذا التعليق أثناء التحقيق فيه أكثر)

استنتاج نوع وسيطة دالة فردية:

/** 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 (??)

لا يوجد استدلال نوع من القيم الحرفية للكائن:

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

هذا مثير للاهتمام ونقطة انطلاق جيدة لمزيد من المناقشة. هل تمانع إذا قمت بإجراء بعض تغييرات التحرير على المنشور الأصلي للتوضيح؟

لا تتردد كما قلت ، الغرض من ذلك هو محاولة استثمار نظام نوع التدفق لمعرفة ما إذا كانت بعض الميزات يمكن أن تتناسب مع TypeScript واحد.

RyanCavanaugh أعتقد أن المثال الأخير:

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

هل الخلل مرتبط بخوارزمية الفحص الفارغة ، سأبلغ عنها.

يكون

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

أي ما يعادل

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

أو يمكن أن يكون؟

@ Davidhanson90 ليس حقًا:

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

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

في هذا المثال ، يتعذر على التدفق معرفة أي نوع في الاتحاد هو func لذا فهو يبلغ عن خطأ في كلتا الحالتين

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

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

func له كلا النوعين لذا كلا النداء صالح.

هل هناك أي فرق ملحوظ بين {} في TypeScript و mixed في التدفق؟

RyanCavanaugh لا أعرف حقًا بعد أن اعتقدت أنه إلى حد كبير لا يزال يفكر فيه.

mixed على أي خصائص ، ولا حتى الخصائص الموروثة من Object.prototype التي يمتلكها {} (# 1108) هذا خطأ.

الفرق الآخر هو أن Flow ينتشر استدلال النوع للخلف لتوسيع النوع المستنتج إلى اتحاد نوع. هذا المثال مأخوذ من 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
}

("بشكل صحيح" من المشاركة الأصلية.)

هذا يعني أن ما يلي سيتم تجميعه أيضًا.

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

تحرير: اختبر المقتطف الثاني وهو بالفعل يقوم بالتجميع.
تحرير 2: كما أشار fdecampredon أدناه ، فإن if (true) { } حول المهمة الثانية مطلوب لجعل Flow يستنتج النوع كـ string | number . بدون if (true) يتم الاستدلال عليه كـ number بدلاً من ذلك.

هل تحب هذا السلوك؟ ذهبنا في هذا الطريق عندما ناقشنا أنواع الاتحاد والقيمة مشكوك فيها. فقط لأن نظام الكتابة لديه الآن القدرة على تصميم أنواع مع حالات متعددة محتملة لا يعني أنه من المرغوب فيه استخدام تلك الأنواع في كل مكان. ظاهريًا ، اخترت استخدام لغة مع مدقق نوع ثابت لأنك تريد أخطاء المترجم عندما ترتكب أخطاء ، ليس فقط لأنك تحب كتابة التعليقات التوضيحية ؛) وهذا يعني أن معظم اللغات تعطي خطأ في مثال مثل هذا (على وجه الخصوص الثاني) ليس بسبب عدم وجود طريقة لنمذجة مساحة النوع ولكن لأنهم يعتقدون في الواقع أن هذا خطأ ترميز (لأسباب مماثلة يتجنب العديد من دعم الكثير من عمليات التحويل / التحويل الضمني).

بنفس المنطق أتوقع هذا السلوك:

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

لكنني حقًا لا أريد هذا السلوك.

@ dquirk أتفق معك في أن استنتاج نوع الاتحاد تلقائيًا بدلاً من الإبلاغ عن خطأ ليس سلوكًا يعجبني.
لكنني أعتقد أن هذا يأتي من فلسفة التدفق ، أكثر من اللغة الحقيقية ، يحاول فريق التدفق إنشاء مدقق نوع ببساطة ، وهدفهم النهائي هو أن يكونوا قادرين على إنشاء كود "أكثر أمانًا" بدون أي نوع من التعليقات التوضيحية. هذا يؤدي إلى أن تكون أقل صرامة.

إن الصرامة الدقيقة قابلة للنقاش حتى بالنظر إلى الضربة القاضية لتأثيرات هذا النوع من السلوك. غالبًا ما يكون مجرد تأجيل خطأ (أو إخفاء خطأ بالكامل). عكست قواعد الاستدلال من النوع القديم لحجج النوع إلى حد كبير فلسفة مماثلة. عند الشك ، استنتجنا {} لمعامل نوع بدلاً من جعله خطأ. هذا يعني أنه يمكنك القيام ببعض الأشياء الرهيبة وما زلت تقوم ببعض مجموعة الحد الأدنى من السلوكيات بأمان على النتيجة (أي أشياء مثل toString ). الأساس المنطقي هو أن بعض الأشخاص يقومون بأشياء أحمق في JS ويجب أن نحاول السماح بما في وسعنا. ولكن من الناحية العملية ، كانت غالبية الاستنتاجات إلى {} مجرد أخطاء ، مما يجعلك تنتظر حتى أول مرة قمت فيها بإزالة متغير من النوع T لتدرك أنه كان {} (أو بالمثل نوع اتحاد غير متوقع) ثم التتبع إلى الوراء كان مزعجًا في أحسن الأحوال. إذا لم تقم بإزالته مطلقًا (أو لم تُرجع شيئًا من النوع T مطلقًا) ، فلن تلاحظ الخطأ على الإطلاق حتى وقت التشغيل عندما ينفجر شيء ما (أو أسوأ من ذلك ، بيانات تالفة). بالمثل:

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

ما هو الخطأ هنا؟ هل تمرر بالفعل x إلى foo ؟ أم أنه كان يعيد تخصيص x من نوع مختلف تمامًا عما تمت تهيئته به؟ كم عدد المرات التي يقوم فيها الأشخاص عن عمد بهذا النوع من إعادة التهيئة مقابل الدوس عن طريق الخطأ على شيء ما؟ على أي حال ، من خلال استنتاج نوع الاتحاد لـ x هل يمكنك حقًا أن تقول أن نظام النوع كان أقل صرامة بشكل عام إذا كان لا يزال يؤدي إلى خطأ (أسوأ)؟ هذا النوع من الاستدلال يكون أقل صرامة فقط إذا لم تفعل شيئًا ذا مغزى بشكل خاص مع النوع الناتج ، وهو نادر جدًا بشكل عام.

يمكن القول إن ترك null و undefined قابلين للتخصيص لأي نوع يخفي الأخطاء بنفس الطريقة ، في معظم الأحيان ، سيؤدي المتغير المكتوب بنوع ما وإخفاء قيمة null إلى ظهور خطأ في وقت التشغيل.

يعتمد جزء لا يستهان به من تسويق Flow على حقيقة أن مدقق الكتابة الخاص بهم يجعل الشفرة أكثر منطقية في الأماكن التي يستنتج فيها TS any . فلسفته هي أنك لا تحتاج إلى إضافة تعليقات توضيحية لجعل المترجم يستنتج الأنواع. لهذا السبب يتم تحويل قرص الاستدلال إلى إعداد أكثر تساهلاً من إعداد TypeScript.

يتعلق الأمر بما إذا كان شخص ما لديه توقع بأن var x = new B(); x = new C(); (حيث يشتق كل من B و C من A) يجب أن يجمع أم لا ، وإذا كان كذلك ، فماذا يجب أن يستنتج؟

  1. لا ينبغي تجميع.
  2. يجب تجميعها والاستدلال عليها باعتبارها النوع الأساسي الأكثر اشتقاقًا الشائع في التسلسلات الهرمية لنوع B و C - A بالنسبة لمثال الرقم والسلسلة سيكون {}
  3. يجب تجميعها والاستدلال عليها كـ B | C .

يعمل TS حاليًا (1) و Flow يفعل (3). أفضل (1) و (2) أكثر بكثير (3).

كنت أرغب في إضافة أمثلة Arnavion إلى الإصدار الأصلي ولكن بعد اللعب قليلاً أدركت أن الأشياء فيها أغرب مما فهمناه.
في هذا المثال :

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

الآن :

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

بعد هذا المثال x تساوي string | number
وإذا فعلت:

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

تلقيت خطأ في السطر 1 يقول: myFile.js line 1 string this type is incompatible with myFile.js line 5 number

ما زلت بحاجة لمعرفة المنطق هنا ...

هناك أيضًا نقطة مثيرة للاهتمام حول التدفق نسيتها:

function test(t: Object) { }

test('string'); //error

بشكل أساسي "الكائن" غير متوافق مع النوع البدائي الآخر ، أعتقد أن المرء له معنى.

"التقاط الدقة العامة" هو بالتأكيد ميزة لا غنى عنها لـ TS!

fdecampredon نعم أنت على حق. مع نوع المستنتج var x = "5"; x = 5; x يتم تحديثه إلى number . بإضافة if (true) { } حول المهمة الثانية ، يتم خداع فاحص الكتابة على افتراض أن أي من التعيينات صحيحة ، وهذا هو سبب تحديث النوع المستنتج إلى number | string بدلاً من ذلك.

الخطأ الذي تحصل عليه myFile.js line 1 string this type is incompatible with myFile.js line 5 number صحيح ، لأن number | string لا يدعم عامل التشغيل * (العمليات الوحيدة المسموح بها على نوع الاتحاد هي تقاطع جميع العمليات على جميع أنواع الاتحاد). للتحقق من ذلك ، يمكنك تغييره إلى x += 5 وسترى أنه يجمع.

لقد قمت بتحديث المثال في تعليقي للحصول على if (true)

"التقاط الدقة العامة" هو بالتأكيد ميزة لا غنى عنها لـ TS!

+1

Arnavion ، لست متأكدًا من سبب تفضيلك لـ {} على B | C . يؤدي استنتاج B | C إلى توسيع مجموعة البرامج التي تقوم بفحص نوع الكتابة دون المساس بالصحة التي تعتبر afaik خاصية مرغوبة بشكل عام لأنظمة النوع.

المثال

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

تحقق من الكتابة بالفعل ضمن المترجم الحالي ، باستثناء أن T يُستنتج أنها {} بدلاً من string | number . هذا لا يضر بالصحة ولكنه أقل فائدة بشكل عام.

لا يبدو استنتاج number | string بدلاً من {} مشكلة بالنسبة لي. في هذه الحالة بالذات ، لا يوسع مجموعة البرامج الصالحة ، ولكن إذا كانت الأنواع تشترك في البنية ، فإن نظام النوع الذي يدرك ذلك ويجعل بعض الأساليب الإضافية و / أو الخصائص الصالحة يبدو مجرد تحسين.

يؤدي استنتاج B | C إلى توسيع مجموعة البرامج التي تتحقق من نوع الكتابة دون المساومة على صحتها

أعتقد أن السماح بالعملية + على شيء يمكن أن يكون إما سلسلة أو رقمًا يضر بالصحة ، نظرًا لأن العمليات لا تشبه بعضها البعض على الإطلاق. الأمر لا يشبه الحالة التي تنتمي فيها العملية إلى فئة أساسية مشتركة (خياري 2) - في هذه الحالة يمكنك توقع بعض التشابه.

لن يكون عامل التشغيل + قابلاً للاستدعاء ، حيث سيكون له حملان زائدان غير متوافقين - أحدهما حيث تكون كلتا الوسيطتين أرقامًا ، والآخر يكون كلاهما فيه سلاسل. منذ ب | C أضيق من كل من السلسلة والرقم ، ولن يُسمح بها كوسيطة في أي من التحميل الزائد.

ماعدا الوظائف هي ثنائية المتغير كتبوا حججهم بحيث قد يكون ذلك مشكلة؟

اعتقدت أنه نظرًا لأن var foo: string; console.log(foo + 5); console.log(foo + document); يجمع أن السلسلة + عامل التشغيل يسمح بأي شيء على الجانب الأيمن ، لذلك فإن string | number سيكون + <number> كعملية صحيحة. لكنك على حق:

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

ركزت الكثير من التعليقات على التوسيع التلقائي للأنواع في Flow. في كلتا الحالتين ، يمكنك الحصول على السلوك الذي تريده عن طريق إضافة تعليق توضيحي. في TS ، يمكنك التوسيع بشكل صريح عند الإعلان: var x: number|string = 5; وفي التدفق ، ستقيد عند الإعلان: var x: number = 5; . أعتقد أن الحالة التي لا تتطلب تصريحًا بالنوع هي الحالة التي يستخدمها الأشخاص كثيرًا. في مشاريعي ، أتوقع أن يكون خطأ var x = 5; x = 'five'; أكثر من نوع الاتحاد. لذلك أقول إن TS حصل على الاستدلال الصحيح على هذا.

بالنسبة إلى ميزات Flow التي أعتقد أنها الأكثر قيمة؟

  1. أنواع غير فارغة
    أعتقد أن هذا واحد لديه إمكانات عالية جدًا في تقليل الأخطاء. للتوافق مع تعريفات TS الحالية ، أتخيلها كمُعدِّل غير فارغ string! بدلاً من مُعدِّل Flow's nullable ?string . أرى ثلاث مشكلات في هذا:
    كيف يتم التعامل مع تهيئة أعضاء الفصل؟ _ (ربما يجب تعيينهم في المُنشئ وإذا كان بإمكانهم الهروب من المُنشئ قبل التعيين ، فسيتم اعتبارهم لاغيين) _
    كيفية التعامل مع undefined ؟ _ (خطوات جانب التدفق هذه المشكلة) _
    هل يمكن أن يعمل بدون الكثير من إقرارات النوع الصريحة؟
  2. الفرق بين mixed و Object .
    لأنه على عكس الأنواع البدائية C # لا يمكن استخدامها في كل مكان يمكن للكائن. جرب Object.keys(3) في متصفحك وسيظهر لك خطأ. لكن هذا ليس حرجًا لأنني أعتقد أن حالات الحافة قليلة.
  3. التقاط الدقة العامة
    المثال فقط منطقي. لكن لا يمكنني القول أنني أكتب الكثير من التعليمات البرمجية التي قد تستفيد من ذلك. ربما سيساعد في المكتبات الوظيفية مثل Underscore؟

في الاستدلال التلقائي لنوع الاتحاد: أفترض أن "استدلال النوع" يقتصر على إعلان النوع. آلية تستنتج ضمنيًا إعلان نوع مهمل. مثل := في Go. أنا لست مُنظِّرًا للنوع ، ولكن بقدر ما أفهم ، فإن الاستدلال على الكتابة هو عبارة عن مرور مترجم يضيف شرحًا واضحًا للنوع لكل إعلان متغير ضمني (أو وسيطة دالة) ، مستدل عليه من نوع التعبير الذي يتم تعيينه منه. وبقدر ما أعرف ، هذه هي الطريقة التي تعمل بها .. حسنًا .. كل آلية استدلال أخرى موجودة. C # ، Haskell ، Go ، كلهم ​​يعملون بهذه الطريقة. أم لا؟

أفهم الحجة حول السماح لـ JS الواقعية باستخدام دلالات TS ، ولكن ربما تكون هذه نقطة جيدة لمتابعة اللغات الأخرى بدلاً من ذلك. الأنواع هي الفرق الوحيد المحدد بين JS و TS ، بعد كل شيء.

أنا أحب الكثير من أفكار Flux ، لكن هذه الفكرة ، حسنًا ، إذا تم تنفيذها بهذه الطريقة بالفعل ... فهذا غريب تمامًا.

تبدو الأنواع غير الفارغة كميزة إلزامية لنظام الكتابة الحديث. هل سيكون من السهل إضافة إلى ts؟

إذا كنت تريد بعض القراءة الخفيفة حول تعقيدات إضافة أنواع غير قابلة للإلغاء إلى TS ، فراجع https://github.com/Microsoft/TypeScript/issues/185

يكفي القول ، كما هو الحال مع الأنواع غير القابلة للإلغاء ، فإن الغالبية العظمى من اللغات الشائعة اليوم لا تحتوي على أنواع غير قابلة للإلغاء افتراضيًا (وهو المكان الذي تتألق فيه الميزة حقًا) أو أي ميزة عامة غير قابلة للإلغاء على الإطلاق. وقد حاول عدد قليل ، إن وجد ، إضافته (أو إضافته بنجاح) بعد الحقيقة بسبب التعقيد وحقيقة أن الكثير من قيمة عدم قابلية الإبطال تكمن في كونها القيمة الافتراضية (على غرار الثبات). هذا لا يعني أننا لا نفكر في الاحتمالات هنا ، لكنني لن أسميها ميزة إلزامية أيضًا.

في الواقع بقدر ما أفتقد النوع غير الفارغ ، فإن الميزة الحقيقية التي أفتقدها من التدفق هي التقاط عام ، وحقيقة أن ts حل كل عام إلى {} يجعل من الصعب حقًا استخدامه مع بعض الإنشاءات الوظيفية ، خاصةً الكاري.

شخصيًا ، يعتبر الالتقاط العام وعدم قابلية الإبطال أهدافًا ذات قيمة عالية من التدفق. سأقرأ الخيط الآخر ، لكنني أردت أن أضع 2c هنا أيضًا.

أشعر أحيانًا أن ميزة إضافة عدم الإلغاء تساوي أي تكلفة تقريبًا. إنها حالة خطأ ذات احتمالية عالية ، وبينما يؤدي وجود قابلية افتراضية افتراضية إلى إضعاف القيمة المضمنة في الوقت الحالي ، تفتقر TypeScript إلى القدرة حتى على مناقشة قابلية العدول من خلال افتراض أنها الحالة في كل مكان.

أود أن أعلق توضيحيًا على كل متغير يمكن أن أجده غير قابل للإلغاء في ضربات القلب.

هناك الكثير من الميزات المخفية في التدفق ، غير موثقة في موقع التدفق. بما في ذلك نوع SuperType المرتبط والوجودي

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

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات