وضع صارم في TypeScript: وصف العلم ، والأمثلة

- علم صارم يتضمن الأعلام التالية:


--strictNullChecks
--alwaysStrict
--noImplicitAny
--noImplicitThis
--strictBindCallApply
--strictFunctionTypes
--strictPropertyInitialization

نعطي أمثلة ونحاول أن نفهم في مكان واحد ما يعنيه كل هذا.

// I. - strictNullChecks


المشكلة الشهيرة مع NPE (استثناء مؤشر فارغ ، خطأ مليار دولار) في سياق TS.
بشكل افتراضي ، في جميع أنواع TS تكون خالية (Nullable) وهذا يعني أنه يمكننا تمرير | "غير محدد" | "Null" حيث يُتوقع أي نوع آخر (حتى بدائي):

const bar1: { foo: number } = undefined;
const bar2: { foo: number } = null;
const bar3: number = null;
const bar4: string = null;

الأمثلة الأكثر إثارة للاهتمام هي استدعاء الأسلوب ، والذي قد لا يكون

declare var smth: { optionalMethod?(): string; };
smth.optionalMethod();

من الواضح أيضًا أنه لا يمكننا إرجاع "غير محدد" | "Null" حيث من غير الواضح أن هذا متوقع

function getIt(): { data: number } {
  // Type 'undefined' is not assignable to type '{ data: number; }'
  return undefined;
}
getIt().data;
 

سيتعين علينا الإشارة صراحةً إلى أن كلمة "غير محددة" يمكن أن تعود ، وبعد ذلك فقط نتلقى خطأً

function getIt(): { data: number } | undefined {
  return undefined;
}
// “Object is possibly 'undefined'”
getIt().data;
 

وكمكافأة - عمليات أكثر أمانًا ، حيث قد لا تكون هناك نتيجة ، سيكون هناك خطأ في تشغيل العلم وسيكون عليك التحقق صراحة من أن "العثور" على شيء ما وجد:

// Object is possibly 'undefined'
[{ name: 'John', age: 4 }]
 .find(el => el.age === 42)
 .name;
 

// الثاني. - دائما صارم


لإضافة تعليق توضيحي "استخدام صارم" لكل ملف ، مما يجعل سلوك JS أكثر وضوحًا

// III. - لا ضمني


يحظر الاستخدام الضمني لـ "أي" في TS ، أي كود بدون تعليق توضيحي

 // Parameter 'a' implicitly has an 'any' type
 function id(arg) {
   return arg;
 }

إنه يساعد كثيرًا في الاستيراد بدون نمط من مكتبات الجهات الخارجية ، حيث يعرض تثبيت تعريفات الأنواع

 /* Could not find a declaration file for module '3rd-party-lib'. '/node_modules/3rd-party-lib/index.js' implicitly has an 'any' type.

Try `npm install @types/3rd-party-lib` if it exists or add a new declaration (.d.ts) file containing `declare module '3rd-party-lib';`*/

import * as session from '3rd-party-lib';
 

// IV. --التصحيحالتصحيحالتطبيق


ويتضمن فحصًا من النوع "أكثر صرامة" لـ "bind" / "call" / "تنطبق" ، بدون إشارة - كل هذا عبارة عن TS صالح.

 function getFullName(name: string, surname: string): string {
   return name + surname;
 }
 
 getFullName.call(null, 'John', 42);
 getFullName.apply(null, ['John', 42]);
 getFullName.bind(null)('John');
 getFullName.bind(null, 'John')();
 getFullName.bind(null, 'John')(42);
 

// V. --strictPropertyInitialization + --strictNullChecks


يساعد على تتبع أن جميع الخصائص تمت تهيئتها في المُنشئ ؛ يجب أيضًا تمكين --strictNullChecks لتعطيل أنواع Nullable.

 class User {
// Property 'name' has no initializer and is not definitely assigned in the constructor
   name: string;
 }

ومع ذلك ، إذا لم تكن المهمة في المنشئ نفسه ، أقنع TS بأن كل شيء على ما يرام.

 class User2 {
  // Property 'name' has no initializer and is not definitely assigned in the constructor
   name: string;
     
   constructor(name: string) {
     this.initializeName();
   }
 
   initializeName() {
     this.name = 'John'
   }
 }

إذا لم تتمكن من إقناع TS بأن الملكية ستتم تهيئتها تمامًا ، يمكنك أن تقول "أقسم بأمي ، سأقوم بالتأكيد بالتهيئة!" أو باختصار "!"

class User3 {
   // definite assignment assertion
   name!: string;
 }
 


// السادس. - أنواع الوظائف الصارمة


إزالة التحقق من المتغيرات للبحث عن الحجج.

باختصار ، المتغير في البرمجة - هذه هي القدرة على تمرير Supertype / Subtype هناك ، حيث يكون النوع متوقعًا. على سبيل المثال ، هناك شكل هرمي -> دائرة -> مستطيل ، هل من الممكن نقل أو إرجاع شكل / مستطيل إذا كان من المتوقع أن تكون الدائرة ؟

برمجة خيار ، SO

interface Shape { name: string };
interface Circle extends Shape { width: number };
interface Rectangle extends Circle { height: number };
 
declare var logSC: (figure: Shape) => Circle;
declare var logRC: (figure: Rectangle) => Circle;
 
declare var logCC: (figure: Circle) => Circle;
 
declare var logCS: (figure: Circle) => Shape;
declare var logCR: (figure: Circle) => Rectangle;
 
declare var wlogBB: (fn: (figure: Circle) => Circle) => void;
 
wlogBB(logCC);
wlogBB(logSC);
wlogBB(logCR);
 
// always Error
wlogBB(logCS);
// Error with --strictFunctionTypes
wlogBB(logRC);

من المفهوم أن الدالة لا يجب أن تحور الوسيطة التي تم تمريرها (تعمل كمنتج نوع) ، لا توجد أخطاء في TS ، في الواقع - هناك

const squares: Square[] = [{ name: 'Square', width: 5 }];
 
// function looks like a consumer of argument
function addSmth(arg: Shape[]) {
 // work with argument as a producer
 arg.push({ name: 'Square' });
}
addSmth(squares);
 

// السابع. - لا شيء ضمني


إذا تم تحديد الوظيفة خارج الكائن / الفئة ، فسوف يطلب منك TS الإشارة صراحةً إلى ما سيشير إليه "هذا" باستخدام أول وسيطة زائفة تسمى "هذا"

// TS force to add annotation for 'this'
 function getName(this: { name: string }, surname: string): string {
   return this.name;
 }
 
 // The 'this' is not assignable
 getName.call({}, 'Smith');
 getName.apply({}, ['Smith']);
 getName.bind({})('Smith');

ستكون المكالمات صالحة

const somePerson = { name: 'John', getName };
const fullName: string = somePerson.getName('Smith')
 
getName.call({name: 'John'}, 'Smith');
getName.apply({name: 'John'}, ['Smith']);
getName.bind({name: 'John'})('Smith');
 

يمكن أن تتسبب وظائف المُنشئ في حدوث مشكلات

function Person(this: { name: string }, name: string) {
   this.name = name;
 }
 // 'new' expression, whose target lacks a construct signature
 // Use class )
 const person = new Person('John');
 

مكافأة مثيرة للاهتمام هي إضافة مقارنة بين طرق ربط السياق للفئات.

class A {
   x = 42;
 
   constructor() {
     this.getBound = this.getBound.bind(this);
   }
 
   getSimple(): number {
     return this.x;
   }
 
   // Has to add type for 'this', TS dont force it
   getSimpleAnnotated(this: A): number {
     return this.x;
   }
 
   getArrow = (): number => this.x;
 
   getBound(this: A): number {
     return this.x;
   }
 }
 
 const a = new A();
 
 // False positive: TS - ok, Runtime - error
 const getSimple = a.getSimple;
 getSimple();
 
 // Correct: TS - error, Runtime - error
 const getSimpleAnnotated = a.getSimpleAnnotated;
 getSimpleAnnotated();
 
 // Correct: TS - ok, Runtime - ok
 const getArrow = a.getArrow;
 getArrow();
 
 // False negative: TS - error, Runtime - ok
 const getBound = a.getBound;
 getBound();
 

All Articles