الإعلان عن TypeScript 3.4 RC

قبل بضعة أيام ، أعلنا عن توفر مرشح الإصدار (RC) الخاص بنا من TypeScript 3.4. أملنا هو جمع الملاحظات والقضايا المبكرة لضمان سهولة إصدارنا النهائي واستخدامه على الفور.


لبدء استخدام RC ، يمكنك الحصول عليها من خلال NuGet ، أو استخدام npm مع الأمر التالي:


npm install -g typescript@rc 

يمكنك أيضًا الحصول على دعم محرر بواسطة



دعنا نستكشف الجديد في 3.4!




هذا المقال في مدونتنا

أسرع يبني لاحقة مع العلم --incremental


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


ولكن من غير الواقعي أن نتوقع من جميع المستخدمين الحفاظ على عملية tsc --watch تعمل بين عشية وضحاها لمجرد الحصول على بنيات أسرع صباح الغد. ماذا عن البرد يبني؟ خلال الأشهر القليلة الماضية ، كنا نعمل لمعرفة ما إذا كانت هناك طريقة لحفظ المعلومات المناسبة من - وضع الساعة إلى ملف واستخدامها من البناء إلى البناء.


يقدم TypeScript 3.4 علامة جديدة تسمى --incremental والتي تخبر TypeScript بحفظ المعلومات حول الرسم البياني للمشروع من التحويل البرمجي الأخير. في المرة التالية التي يتم فيها استدعاء --incremental مع - --incremental ، ستستخدم هذه المعلومات للكشف عن الطريقة الأقل تكلفة لفحص التغييرات وإرسالها إلى مشروعك.


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

بشكل افتراضي مع هذه الإعدادات ، عندما نقوم بتشغيل tsc ، سيبحث TypeScript عن ملف يسمى .tsbuildinfo في دليل الإخراج الخاص بنا ( ./lib ). إذا كان ./lib/.tsbuildinfo غير موجود ، فسيتم إنشاؤه. ولكن إذا حدث ذلك ، tsc استخدام هذا الملف للتحقق تدريجياً من ملفات الإخراج وتحديثها.


يمكن حذف ملفات .tsbuildinfo هذه بأمان ولا يكون لها أي تأثير على التعليمات البرمجية الخاصة بنا في وقت التشغيل - يتم استخدامها بشكل محض لجعل عمليات التجميع أسرع. يمكننا أيضًا تسمية أي شيء نريده ، ووضعهم في أي مكان نريد باستخدام علامة --tsBuildInfoFile .


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

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


المشاريع المركبة


جزء من الهدف من المشاريع المركبة ( tsconfig.json s مع مجموعة composite إلى true ) هو أنه يمكن بناء المراجع بين المشاريع المختلفة بشكل تدريجي. على هذا النحو ، ستنتج المشاريع المركبة دائمًا ملفات .tsbuildinfo .


outFile


عند استخدام outFile ، سوف يعتمد اسم ملف معلومات البناء على اسم ملف الإخراج. على سبيل المثال ، إذا كان ملف جافا سكريبت الخاص بنا هو ./output/foo.js ، ثم تحت علامة --incremental ، ستقوم TypeScript بإنشاء الملف ./output/foo.tsbuildinfo . كما ذكر أعلاه ، يمكن التحكم في ذلك --tsBuildInfoFile علامة --tsBuildInfoFile .


- تنسيق الملف والإصدار


في حين أن الملف الذي تم إنشاؤه بواسطة --incremental هو JSON ، فإن الملف لا يعني أن تستهلكه أي أداة أخرى. لا يمكننا توفير أي ضمانات لاستقرار محتوياته ، وفي الواقع ، فإن سياستنا الحالية هي أن أي إصدار واحد من TypeScript لن يفهم ملفات .tsbuildinfo إنشاؤها من إصدار آخر.


تحسينات لـ ReadonlyArray و tuples readonly


يجعل TypeScript 3.4 من الأسهل استخدام أنواع تشبه الصفيف للقراءة فقط.


بناء جملة جديد لـ ReadonlyArray


يصف نوع ReadonlyArray يمكن قراءتها فقط. لا يمكن لأي متغير ذي مؤشر إلى ReadonlyArray إضافة أو إزالة أو استبدال أي من عناصر الصفيف.


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

في حين أنه من الممارسات الجيدة في كثير من الأحيان استخدام ReadonlyArray over Array لغرض النية ، إلا أنه غالبًا ما يكون الألم نظرًا لأن المصفوفات تحتوي على بناء جملة أجمل. على وجه التحديد ، number[] هو نسخة مختصرة من Array<number> ، تمامًا مثل Date[] هو اختصار لـ Array<Date> .


يقدم TypeScript 3.4 بناء جملة جديد لـ ReadonlyArray باستخدام معدّل readonly جديد لأنواع الصفيف.


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

tuples readonly


يقدم TypeScript 3.4 أيضًا دعمًا جديدًا للصفوف المقروءة readonly . يمكننا بادئة أي نوع tuple بالكلمة الرئيسية readonly لجعلها tuple readonly ، مثلما نستطيع الآن مع بناء جملة مجموعة الاختزال المختصر. كما قد تتوقع ، على عكس التلاميذ العاديين الذين يمكن كتابة فتحات لهم ، يسمح التلاميذ المقروءة فقط بالقراءة من تلك المواضع.


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

بنفس الطريقة التي يكون بها tuples العادية هي الأنواع التي تمتد من Array - tuple مع عناصر من النوع T 1 و T 2 و ... T n يمتد من Array< T 1 | T 2 | ... T n > - tuples readonly هي الأنواع التي تمتد من ReadonlyArray . لذا فإن tuple readonly مع العناصر T 1 و T 2 و ... T n تمتد من ReadonlyArray< T 1 | T 2 | ... T n > .


readonly نوع معين readonly ومصفوفات readonly


في الإصدارات السابقة من TypeScript ، قمنا بتعميم الأنواع المعينة للعمل بشكل مختلف على أنواع تشبه الصفيف. هذا يعني أن النوع المعين مثل Boxify يمكن أن يعمل على المصفوفات Boxify على حد سواء.


 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]>; 

لسوء الحظ ، كانت الأنواع المعينة مثل نوع الأداة المساعدة Readonly غير فعالة على أنواع المصفوفات والأنواع.


 // 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]>; 

في TypeScript 3.4 ، يقوم معدّل readonly في نوع معين تلقائيًا بتحويل أنواع تشبه الصفيف إلى نظرائهم readonly .


 // 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]>; 

وبالمثل ، يمكنك كتابة نوع أداة مساعدة مثل النوع Writable والذي يزيل readonly ، وهذا من شأنه تحويل حاويات الصفيف readonly إلى معادلاتها القابلة للتغيير.


 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]>; 

محاذير


على الرغم من مظهره ، لا يمكن استخدام معدّل الكتابة readonly فقط إلا في بناء الجملة على أنواع الصفيف وأنواع الصفوف. انها ليست عامل نوع للأغراض العامة.


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

تأكيدات const


عند التصريح عن متغير أو خاصية قابلة للتغيير ، غالبًا ما يقوم TypeScript بتوسيع القيم للتأكد من أنه يمكننا تعيين الأشياء لاحقًا دون كتابة نوع صريح.


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

من الناحية الفنية ، كل قيمة حرفية لها نوع حرفي. أعلاه ، تم توسيع النوع "hello" إلى string الكتابة قبل استنتاج نوع لـ x .


قد يكون أحد الآراء البديلة هو القول بأن x لديه نوع الحرف الأصلي "hello" وأنه لا يمكننا تعيين "world" لاحقًا على هذا النحو:


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

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


 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; } 

يعد قابلية التشغيل أحد أفضل الأساليب البحثية التي يمكن لـ TypeScript استخدامها لتحديد وقت التوسع (بدلاً من تحليل برنامجنا بالكامل).


لسوء الحظ ، كما رأينا في المثال الأخير ، في خصائص JavaScript قابلة للتغيير افتراضيًا. هذا يعني أن اللغة ستعمل في الغالب على توسيع الأنواع غير المرغوب فيها ، مما يتطلب أنواعًا واضحة في أماكن معينة.


 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; } 

لا بأس بهذا إلى حد ما ، لكن مع زيادة تعقيد هياكل البيانات الخاصة بنا ، يصبح هذا الأمر مرهقًا.


لحل هذا ، يقدم TypeScript 3.4 بنية جديدة للقيم الحرفية تسمى تأكيدات const . بناء الجملة الخاص به هو تأكيد للنوع مع const بدلاً من اسم النوع (على سبيل المثال 123 as const ). عندما نبني تعبيرات حرفية جديدة مع تأكيدات const ، يمكننا الإشارة إلى اللغة التي


  • يجب عدم توسيع أنواع الحرف في هذا التعبير (على سبيل المثال عدم الانتقال من "hello" إلى string )
  • حرفية الكائن الحصول على خصائص readonly
  • مجموعة الحرفي تصبح tuples 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; 

خارج ملفات .tsx ، يمكن أيضًا استخدام بناء جملة تأكيد قوس الزاوية.


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

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


 // 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); } } 

لاحظ ما سبق لا يحتاج إلى تعليقات توضيحية من النوع. سمح تأكيد const لـ TypeScript بأخذ أكثر أنواع التعبير تعبيرًا.


محاذير


شيء واحد هو أن نلاحظ أن التأكيدات const لا يمكن إلا أن تطبق على الفور على التعبيرات الحرفية البسيطة.


 // 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; 

شيء آخر يجب مراعاته هو أن سياقات const لا تحول على الفور تعبيرًا ليكون غير قابل للتغيير تمامًا.


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

التحقق من النوع ل globalThis


قد يكون من الصعب بشكل مفاجئ الوصول إلى القيم أو الإعلان عنها في النطاق العالمي ، ربما لأننا نكتب الكود الخاص بنا في الوحدات النمطية (التي لا تتسرب إعلاناتها المحلية افتراضيًا) ، أو لأننا قد يكون لدينا متغير محلي يحجب اسم قيمة عالمية. في بيئات مختلفة ، هناك طرق مختلفة للوصول إلى ما هو فعال النطاق العالمي - global في العقدة أو window أو self أو frames في المتصفح ، أو this في مواقع معينة خارج الوضع الصارم. لا شيء من هذا واضح ، وغالبًا ما يترك المستخدمين يشعرون بعدم التأكد من أنهم يكتبون الرمز الصحيح.


يقدم برنامج TypeScript 3.4 دعمًا للتحقق من النوع الجديد الخاص بـ ECMAScript الجديد - وهو متغير globalThis يشير إلى النطاق العام. على عكس الحلول المذكورة أعلاه ، globalThis يوفر globalThis طريقة قياسية للوصول إلى النطاق العالمي الذي يمكن استخدامه عبر بيئات مختلفة.


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

globalThis قادر أيضًا على إظهار ما إذا كان قد تم تعريف متغير globalThis أم لا باعتباره const خلال معاملته كخاصية readonly عند الوصول إليه.


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

من المهم ملاحظة أن TypeScript لا يحول الإشارات إلى globalThis عند التحويل البرمجي إلى الإصدارات القديمة من ECMAScript. على هذا النحو ، ما لم تكن تستهدف متصفحات دائمة الخضرة (التي تدعم بالفعل globalThis ) ، فقد ترغب في استخدام polyfill مناسب بدلاً من ذلك.


تحويل إلى المعلمات المسماة


في بعض الأحيان ، تبدأ قوائم المعلمات في الحصول على غير عملي.


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

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


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

لا يعمل فريق TypeScript فقط على برنامج التحويل البرمجي - بل نوفر أيضًا الوظائف التي يستخدمها المحررون للميزات الغنية ، مثل الإكمالات ، والانتقال إلى التعريف ، وإعادة البناء. في TypeScript 3.4 ، قام متدربنا Gabriela Britto بتنفيذ إعادة بيع جديدة لتحويل الوظائف الحالية إلى استخدام نمط "المعلمات المسماة".


يتم تطبيق إعادة بناء على دالة لجعلها تأخذ المعلمات المسماة.


على الرغم من أننا قد نغير اسم الميزة من خلال الإصدار 3.4 النهائي الخاص بنا ونعتقد أنه قد يكون هناك مجال لبعض بيئة العمل ، إلا أننا نود أن تجرب هذه الميزة وتعطينا ملاحظاتك.


كسر التغييرات


المستوى الأعلى يتم كتابة this الآن


يتم الآن كتابة نوع المستوى الأعلى this كـ typeof globalThis بدلاً من any . نتيجة لذلك ، قد تتلقى أخطاء للوصول إلى قيم غير معروفة في this تحت noImplicitAny .


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

لاحظ أن التعليمات البرمجية المترجمة تحت noImplicitThis لن تواجه أي تغييرات هنا.


نشر وسيطات النوع العام


في بعض الحالات ، قد ينتج عن الاستنتاج المحسن الخاص بـ TypeScript 3.4 وظائف عامة ، بدلاً من تلك التي تأخذ وتعيد قيودها (عادةً {} ).


 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"); 

يمكن للتعليق التوضيحي الصريح على x أن يتخلص من الخطأ.


ما التالي؟


يُعد TypeScript 3.4 أول إصدار لدينا يتضمن خطة تكرارية تحدد خططنا لهذا الإصدار ، والتي تهدف إلى التوافق مع خارطة الطريق التي مدتها 6 أشهر . يمكنك مراقبة كل من هؤلاء ، وعلى صفحة خريطة طريق ميزة المتداول لدينا عن أي عمل قادم.


في الوقت الحالي ، نتطلع إلى سماع تجربتك مع الصليب الأحمر ، لذلك قدمها الآن واطلعنا على أفكارك!

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


All Articles