يمكننا الوصول إلى...؟؟


5. ما الذي ينجح: الصف المدمر

type Provider = \\\"PROVIDER A\\\" | \\\"PROVIDER B\\\";type ProviderAOpts = { ... };type ProviderBOpts = { ... };function connect(  ...[provider, options]:    | [\\\"PROVIDER A\\\", ProviderAOpts]    | [\\\"PROVIDER B\\\", ProviderBOpts]) {  switch (provider) {    case \\\"PROVIDER A\\\":      // options is ProviderAOpts ✅    case \\\"PROVIDER B\\\":      // options is ProviderBOpts ✅    ...  }}
connect(\\\"PROVIDER A\\\", { ... });connect(\\\"PROVIDER B\\\", { ... });                      ^ autocomplete works ✅

إذن الأمر هو أننا نقوم بتدمير صف (مصفوفة) بالأنواع الدقيقة التي نريدها.

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


6. ما الذي ينجح: حل Tuple المعمم

type Provider = \\\"PROVIDER A\\\" | \\\"PROVIDER B\\\";type ProviderAOpts = { ... };type ProviderBOpts = { ... };type ProviderOpts = {  \\\"PROVIDER A\\\": ProviderAOpts;  \\\"PROVIDER B\\\": ProviderBOpts;};// solves to // [\\\"PROVIDER A\\\", ProviderAOpts] | [\\\"PROVIDER B\\\", ProviderBOpts]type ConnectOptions = {  [K in keyof ProviderOpts]: [K, ProviderOpts[K]];}[keyof ProviderOpts]; function connect(...[provider, options]: ConnectOptions) {  switch (provider) {    case \\\"PROVIDER A\\\":      // options is ProviderAOpts ✅    case \\\"PROVIDER B\\\":      // options is ProviderBOpts ✅    ...  }}
connect(\\\"PROVIDER A\\\", { ... });connect(\\\"PROVIDER B\\\", { ... });                      ^ autocomplete works ✅

7. ليرة تركية، د. نسخ لصق، شكرا

type Provider = \\\"PROVIDER A\\\" | \\\"PROVIDER B\\\";type ProviderAOpts = { ... };type ProviderBOpts = { ... };type ProviderOpts = {  \\\"PROVIDER A\\\": ProviderAOpts;  \\\"PROVIDER B\\\": ProviderBOpts;};// aux type to extract the key and the options from ProviderOptstype KeyOpts = {  [K in keyof T]: [K, T[K]];}[keyof T];function connect(...[provider, options]: KeyOpts) {  switch (provider) {    case \\\"PROVIDER A\\\":      // options is ProviderAOpts ✅    case \\\"PROVIDER B\\\":      // options is ProviderBOpts ✅    ...  }}
connect(\\\"PROVIDER A\\\", { ... });connect(\\\"PROVIDER B\\\", { ... });                      ^ autocomplete works ✅

شكرًا لماتيوس ولينز على المساعدة؟.

شكرا على القراءة؟.

","image":"http://www.luping.net/uploads/20241104/17307234156728be5752a02.jpg","datePublished":"2024-11-07T10:48:39+08:00","dateModified":"2024-11-07T10:48:39+08:00","author":{"@type":"Person","name":"luping.net","url":"https://www.luping.net/articlelist/0_1.html"}}
"إذا أراد العامل أن يؤدي عمله بشكل جيد، فعليه أولاً أن يشحذ أدواته." - كونفوشيوس، "مختارات كونفوشيوس. لو لينجونج"
الصفحة الأمامية > برمجة > Ts المتقدمة: المعلمات التابعة والنقابات المستنتجة والتفاعل الصحي على تويتر.

Ts المتقدمة: المعلمات التابعة والنقابات المستنتجة والتفاعل الصحي على تويتر.

تم النشر بتاريخ 2024-11-07
تصفح:877

Advanced Ts: Dependent parameters, inferred unions and a healthy interaction on Twitter.

في كل مرة أكتب فيها بشخصية Foo باستخدام TypeScript، أشعر بثقل الهزيمة.

هناك سيناريو واحد حيث يكون هذا الشعور شديدًا بشكل خاص: عندما تأخذ دالة معلمة تعتمد على "الوضع" النشط.

أكثر وضوحًا مع بعض أمثلة التعليمات البرمجية:

type Provider = "PROVIDER A" | "PROVIDER B";
type ProviderAOpts = { ... };
type ProviderBOpts = { ... };

function connect(provider: Provider, options: ProviderAOpts | ProviderBOpts)  {
  switch (provider) {
    case "PROVIDER A":
      // options is ProviderAOpts
    case "PROVIDER B":
      // options is ProviderBOpts
  }
}

(حاولت استخدام أسماء أكثر واقعية بدلاً من foo وgoo وdog وcat).

إذا قضيت بعض الوقت في استخدام TypeScript، فقد تشك في أننا اعتدنا على التعامل مع هذا باستخدام ProviderAOpts، مثل ProviderBOpts.


ولكن هناك وقت تضرب فيه بقبضتك على الطاولة وتقول: "لا أكثر!"


1. ما الذي لا ينجح

أول ما يتبادر إلى ذهني دائمًا في هذه الحالات هو استخدام التحميل الزائد للوظيفة:

function connect(provider: "PROVIDER A", options: ProviderAOpts): void;
function connect(provider: "PROVIDER B", options: ProviderBOpts): void;

function connect(provider: Provider, options: ProviderAOpts | ProviderBOpts) {
  switch (provider) {
    case "PROVIDER A":
    // (options as ProviderAOpts) ❌
    case "PROVIDER B":
    // (options as ProviderBOpts) ❌
  }
}

وهو ما لا يعمل. لم يتم استنتاج توقيع الوظيفة بشكل صحيح. معلمة الخيارات هي دائمًا ProviderAOpts | موفرBOpts. والتي سوف تحل إلى الاتحاد المشترك.

لا يربط Ts كلا المعلمتين بشكل صحيح.


2. ما الذي يعمل ولكن لا يربط المعلمات

الأداة التالية التي أحاول تجربتها هي مسندات النوع:

type ConnectOptions = ProviderAOpts | ProviderBOpts;

function isAOptions(options: ConnectOptions): options is ProviderAOpts {
  return (options as ProviderAOpts).$$$ !== undefined;
}

function isBOptions(options: ConnectOptions): options is ProviderBOpts {
  return (options as ProviderBOpts).$$$ !== undefined;
}

function connect(provider: Provider, options: ConnectOptions) {
  switch (provider) {
    case "PROVIDER A":
      if (isAOptions(options)) {
        ...
      }
    case "PROVIDER B":
      if (isBOptions(options)) {
        ...
      }
  }
  ...
}

لكن بصراحة، لم نحل أي شيء. لقد نقلنا للتو كما هو الحال تحت السجادة؟ تم تقديم ifs إضافية، وما زلنا لا نربط المعلمات.


3. ما لا ينفعني ويبكيني

الأدوية العامة. حاولت استخدام الأدوية العامة لربط المعلمات. لا يعمل:

function connect(
  provider: T,
  options: T extends "PROVIDER A" ? ProviderAOpts : ProviderBOpts
) {
  switch (provider) {
    case "PROVIDER A":
    // (options as ProviderAOpts) ❌
    case "PROVIDER B":
    // (options as ProviderBOpts) ❌
  }
}

لقد حاولت جاهدا ووصلت إلى هذا الحد
ولكن في النهاية، لا يهم حتى
كان علي أن أسقط لأخسر كل شيء
ولكن في النهاية، لا يهم حتى
?‍?


4. ما الذي ينجح ولكنه يجبرنا على تغيير توقيع الوظيفة

تعديل معلمات الاختيارات بإضافة نوع الموفر يؤدي إلى الحيلة:

type Provider = "PROVIDER A" | "PROVIDER B";

type ProviderOptsBase = {
  provider: Provider;
}

type ProviderAOpts = ProviderOptsBase & {
  provider: "PROVIDER A";
  ...;
};

type ProviderBOpts = ProviderOptsBase & {
  provider: "PROVIDER B";
  ...;
};

function connect(options: ConnectOptions) {
  switch (options.provider) {
    case "PROVIDER A":
      // options is ProviderAOpts ✅
    case "PROVIDER B":
      // options is ProviderBOpts ✅
  }
}

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


تويتر للإنقاذ

شكرًا لماتيوس بورزينسكي (@AndaristRake) ولينز ويبر (@phry)

يمكننا الوصول إلى...؟؟


5. ما الذي ينجح: الصف المدمر

type Provider = "PROVIDER A" | "PROVIDER B";
type ProviderAOpts = { ... };
type ProviderBOpts = { ... };

function connect(
  ...[provider, options]:
    | ["PROVIDER A", ProviderAOpts]
    | ["PROVIDER B", ProviderBOpts]
) {
  switch (provider) {
    case "PROVIDER A":
      // options is ProviderAOpts ✅
    case "PROVIDER B":
      // options is ProviderBOpts ✅
    ...
  }
}
connect("PROVIDER A", { ... });
connect("PROVIDER B", { ... });
                      ^ autocomplete works ✅

إذن الأمر هو أننا نقوم بتدمير صف (مصفوفة) بالأنواع الدقيقة التي نريدها.

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


6. ما الذي ينجح: حل Tuple المعمم

type Provider = "PROVIDER A" | "PROVIDER B";
type ProviderAOpts = { ... };
type ProviderBOpts = { ... };

type ProviderOpts = {
  "PROVIDER A": ProviderAOpts;
  "PROVIDER B": ProviderBOpts;
};

// solves to 
// ["PROVIDER A", ProviderAOpts] | ["PROVIDER B", ProviderBOpts]
type ConnectOptions = {
  [K in keyof ProviderOpts]: [K, ProviderOpts[K]];
}[keyof ProviderOpts]; 

function connect(...[provider, options]: ConnectOptions) {
  switch (provider) {
    case "PROVIDER A":
      // options is ProviderAOpts ✅
    case "PROVIDER B":
      // options is ProviderBOpts ✅
    ...
  }
}
connect("PROVIDER A", { ... });
connect("PROVIDER B", { ... });
                      ^ autocomplete works ✅

7. ليرة تركية، د. نسخ لصق، شكرا

type Provider = "PROVIDER A" | "PROVIDER B";
type ProviderAOpts = { ... };
type ProviderBOpts = { ... };

type ProviderOpts = {
  "PROVIDER A": ProviderAOpts;
  "PROVIDER B": ProviderBOpts;
};

// aux type to extract the key and the options from ProviderOpts
type KeyOpts = {
  [K in keyof T]: [K, T[K]];
}[keyof T];


function connect(...[provider, options]: KeyOpts) {
  switch (provider) {
    case "PROVIDER A":
      // options is ProviderAOpts ✅
    case "PROVIDER B":
      // options is ProviderBOpts ✅
    ...
  }
}
connect("PROVIDER A", { ... });
connect("PROVIDER B", { ... });
                      ^ autocomplete works ✅

شكرًا لماتيوس ولينز على المساعدة؟.

شكرا على القراءة؟.

بيان الافراج تم إعادة إنتاج هذه المقالة على: https://dev.to/manuartero/advanced-ts-dependent-parameters-inferred-unions-and-a-healthy-interaction-on-twitter-13bc?1 إذا كان هناك أي انتهاك، من فضلك اتصل بـ [email protected]
أحدث البرنامج التعليمي أكثر>

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

Copyright© 2022 湘ICP备2022001581号-3