Language-tools: كتابة الدعائم المكونة Svelte / الأحداث / الفتحات

تم إنشاؤها على ١١ أغسطس ٢٠٢٠  ·  24تعليقات  ·  مصدر: sveltejs/language-tools

هناك العديد من المشكلات حول هذا بالفعل (# 424 ، # 304 ، # 273 ، # 263) ، لكنني أردت إنشاء واحدة موحدة لإجراء مناقشة حول الأساليب التي يمكننا اتباعها.
العلاقات العامة ذات الصلة: # 437

لاحظ أن هذه المشكلة لا تتعلق بكتابة ملف d.ts ، سيأتي هذا لاحقًا كمسألة منفصلة.

هل طلب الميزة الخاص بك متعلق بمشكلة؟
في الوقت الحالي ، لا يمكن كتابة مدخلات / مخرجات أحد المكونات في ظل ظروف معينة:

  • لا يمكن تحديد علاقة عامة بين الدعائم والأحداث / الفتحات (الأدوية الجنسية)
  • لا يمكن تحديد الأحداث وأنواعها
  • لا يمكن تحديد الفتحات وأنواعها بطريقة معينة

صِف الحل الذي تريده
طريقة لكتابة الدعائم / الأحداث / الفتحات بشكل صريح.

الاقتراح: واجهة محجوزة جديدة ComponentDef والتي ، عند تعريفها ، تُستخدم كواجهة برمجة تطبيقات عامة للمكون بدلاً من استنتاج الأشياء من الكود.

مثال (مع تعليقات حول ما هو محتمل غير ممكن):

<script lang="ts"
   interface ComponentDef<T> { // <-- note that we can use generics as long as they are "defined" through props
      props: {  items: T[]  }
      events: {  itemClick: CustomEvent<T>  }
      slots: { default: { item: T } }
  }

   // generic type T is not usable here. Is that a good solution? Should it be possible?
   // Also: How do we make sure the types match the component definition?
  export items: any[];

   // ...

   // We cannot make sure that the dispatched event and its type are correct. Is that a problem?
   // Maybe enhance the type definitions in the core repo so createEventDispatcher accepts a record of eventname->type?
   dispatch('itemClick', item);
</script>
<!-- ... -->
<slot item={item}> <!-- again, we cannot make sure this actually matches the type definition -->

عندما يستخدم شخص ما المكون الآن ، سيحصل على الأنواع الصحيحة من الدعائم / الأحداث / الفتحات وأيضًا تشخيص الأخطاء عندما يكون هناك خطأ ما:

<Child
     items="{['a', 'string']}"
     on:itemClick="{event => event.detail === 1 /* ERROR, number not comparable to type string */}"
/>

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

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

MustafaHosny اللهم امين يارب _

enhancement

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

ربما أستخدم المصطلحات الخاطئة هنا ... أو آمل أنني فعلت شيئًا خاطئًا.

مثال على ما أتمنى أن أفعله:

"" html


{option.myLabelProp}

{# كل خيار كخيار} {/كل}

ال 24 كومينتر

يبدو من المعقول ، أن هناك بالفعل مشكلة Svelte حول القدرة على حقن الفتحات في وقت التشغيل. https://github.com/sveltejs/svelte/issues/2588 والعلاقات العامة التي تنفذها https://github.com/sveltejs/svelte/pull/4296 ، يبدو أنه قد يكون هناك تداخل ، أو على الأقل بعض الفرص محاذاة الواجهات (إذا كان هناك أي توافق ، فلا تزال هناك بعض الأسئلة المعلقة مع العلاقات العامة أعلاه).

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

مثير للانتباه.
أتساءل عما إذا كان بإمكاننا فعل شيء مثل

<script lang="ts" generic="T"> 
    type T = unknown
    export let items: T[]
    let item:T = items[0]
</script>
<slot b={item}></slot>

مما سيؤدي إلى تجريد type T = unknown أثناء فحص الكتابة وإضافته بدلاً من ذلك كوسيطة عامة إلى المكون.

//...
render<T>() {
    export let items: T[]
    let item:T = items[0]
}

فكرة جيدة حول إضافته إلى الوظيفة render !

أعتقد أننا يمكن أن نحصل على نفس النتائج مع

<script lang="ts">
    interface ComponentDef<T> {
       ...
    } 
    type T = unknown
    export let items: T[]
    let item:T = items[0]
</script>
<slot b={item}></slot>

باستخراج T من تعريف الواجهة.

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

لا أريد حقًا أن أضطر إلى كتابة interface ComponentDef<T>{ props: {} } وصطفها مع كل واحدة من صادراتي. يعمل Svelte جيدًا في تقليل الأحرف المكتوبة مقارنةً بـ React ، وهذا يبدو وكأنه خطوة إلى الوراء. على وجه الخصوص ، يتطلب الأمر تكرار أنواع كل تصدير في الدعائم ، وهو أمر غير ممتع (ومن المؤكد أن يؤدي إلى مشاكل متكررة).

أحب طريقة تفكيرhalfnelson . يجب الكشف عن الصادرات كدعامات. لا أعرف كيف تبدو الوحدة مرة واحدة

سؤال سريع آخر ، كما قرأته في بعض القضايا ذات الصلة: لم أواجه مشكلة في استخدام تعليقات JSDoc لكتابة الأشياء ، بما في ذلك الخيار @template .

بينما يجب أن نبقي عقلًا متفتحًا لـ JSDoc (حتى باستخدام JSDoc داخل HTML) ، يجب أن أحذر من أنه ، سواء تم استخدامه من خلال WebStorm أو VS Code ، فهو ببساطة ليس معبرًا مثل TypeScript. على سبيل المثال ، لا يطبق النوع true ؛ أنا متأكد من أنه لا يعمل أنواع الفهرس ؛ وإذا كنت أتذكر ، فلا يمكنك الحصول على Record<keyof X, any> أيضًا. أستمر في الاصطدام بالجدران معها. نجح @template ، لكنه كان محدودًا جدًا أيضًا. وأعتقد أنه يعمل بشكل مختلف اعتمادًا على IDE أيضًا.

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

حول النفقات العامة للكتابة: هذا صحيح ولكن ستكون هناك حاجة إليه فقط في المواقف التي تريد فيها استخدام الأدوية العامة و / أو كتابة الأحداث / الفتحات بشكل ضمني. من الناحية النظرية ، يمكننا أن نستنتج كل هذا بأنفسنا ، لكن هذا يصعب تنفيذه. ومن الأمثلة على مثل هذه المشكلات التي يصعب تنفيذها دعم سيناريوهات الفتحات المتقدمة كما هو الحال في # 263 ، وجمع كل أحداث المكونات الممكنة (وهو أمر سهل إذا كان المستخدم سيستخدم createEventDispatcher فقط ، ولكن يمكنه أيضًا استيراد وظيفة والتي يلتف أشياء createEventDispatcher ).

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

هذا يعني:

  • ComponentDef هو عمل الكل في واحد إذا احتجت إليه
  • ComponentEvents مخصص لكتابة الأحداث فقط
  • ComponentSlots مخصص للكتابة فقط
  • بناء مثل <script generic="T"> إذا كنت بحاجة فقط للأدوية
  • مزيج من ComponentEvents/ComponentSlots/generic="T"

shirakaba لا يجب أن يكون دعم نوع JSDoc غنيًا بالميزات مثل النص المطبوع. أشك في أن الكثير من الناس قد يكتبون مكونات عامة معها. أيضًا نظرًا لأننا نستخدم خدمة اللغة المطبوعة ، يمكن استيراد الكثير من الأنواع المتقدمة بسهولة من ملف منسوخ.

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

interface ComponentDef {
      slots: { default: { item: string } }
  }

يمكننا إنشاء فصل دراسي

class DefaultSlot extends Svelte2TsxComponent<ComponentDef['slots']['default']>{ }

وتحويل الفتحة الافتراضية إلى

<DeafaultSlot />

(ترنيم فقط كمستخدم) بالنسبة لي ، الكتابة الإضافية ليست مشكلة لأنني يجب أن أقوم بالكثير منها على أي حال أثناء العمل مع TypeScript.

بالنسبة للواجهة مقابل الخاصية generic ، نظرًا لوجود حالات يتم فيها عرض المتغيرات للمستهلك فقط ، سيكون من الأفضل DX دعم الخاصية. ولكن في هذه الملاحظة ، هل من الممكن دعم export type T بدلاً من generic="T" ؟

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

أفهم. لا يبقى طويلاً ، لكن هل هو بناء جملة غير صالح أم أنه خطأ "نوع غير معروف / غير معروف"؟ أنا أسأل لأنني لا أعرف كيف يتعامل مترجم TypeScript مع الحالتين. لدي فقط تحفظات على إضافة سمة مخصصة إلى علامة script ، خاصةً مع اسم عام مثل "عام" :)

الكل في الكل ، بالنسبة لي ، يعد هذا أمرًا رائعًا وربما يجبر المستخدم على كتابة المتغيرات المصدرة عند استخدام المكون أمرًا جيدًا (رمز أكثر قابلية للقراءة).

عندما تكتب export type T; ، فإن TS سيظهر خطأ في بناء الجملة. أيضا ، كيف تصوغ القيود؟ سوف يتسبب export type T extends string; في حدوث المزيد من أخطاء بناء الجملة عليك. أتفهم تمامًا تحفظك على سمة مخصصة ، لكنني أعتقد أنها الطريقة الأقل إزعاجًا. من الطرق الأخرى أن يكون لديك أسماء أنواع محجوزة مثل T1 أو T2 لكن هذا ليس مرنًا بدرجة كافية (كيف تضيف قيودًا؟).

سيكون البديل هو كتابة المكون بالكامل عبر ComponentDef ، حيث يمكنك إضافة الأدوية الجنسية بحرية ، كما في المثال الوارد في المنشور الأول. لكن هذا يأتي على حساب المزيد من الكتابة.

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

ربما فاتني هذا ولكن هل تقسيمه خيار؟

<script>
  import type { Foo } from './foo';
  export let items: Foo[];
  interface ComponentSlots<T> {}
  interface ComponentEvents<T> {}
</script>

هل سيؤدي ذلك إلى تقليل حمل الكتابة في معظم الحالات؟

نعم هذا ممكن

dummdidumm هل من الممكن العمل على دعم interface ComponentSlots {} (مع أو بدون دعم للأدوية) في هذه الأثناء؟ أم أن تقديم ذلك يتعارض مع الأشياء التي نوقشت هنا؟

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

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

لقد قمت الآن بإنشاء RFC حول هذا الموضوع: https://github.com/sveltejs/rfcs/pull/38
يجب أن تستمر المناقشة حول API هناك.

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

سيكون هذا ضخمًا! أنا حزين حاليًا لأن استخدام خصائص الفتحة هو دائمًا أي شيء.

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

ربما أستخدم المصطلحات الخاطئة هنا ... أو آمل أنني فعلت شيئًا خاطئًا.

مثال على ما أتمنى أن أفعله:

"" html


{option.myLabelProp}

{# كل خيار كخيار} {/كل}

حسنًا ، أفهم ، نعم الآن هذا غير ممكن ، لذا عليك الرجوع إلى any[] . إذا كان هذا يسمح فقط بـ string[] ، فستتم كتابة الفتحة الخاصة بك على أنها string ، وهو ما قصدته بعبارة "يمكن استنتاج النوع".

هناك حل مؤقت لطيف لكتابة مكونات التحقق التي صادفتها في "Svelte and Sapper in Action" بواسطة Mark Volkmann وهو استخدام مكتبة React من أنواع props جنبًا إلى جنب مع $$ props.

هذا هو رمز عنصر Todo على سبيل المثال:

import PropTypes from "prop-types/prop-types";

const propTypes = {
    text: PropTypes.string.isRequired,
    checked: PropTypes.bool,
};

// Interface for Todo items
export interface TodoInterface {
    id: number;
    text: string;
    checked: boolean;
}

PropTypes.checkPropTypes(propTypes, $$props, "prop", "Todo");

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

ما زلت أبدأ في جافا سكريبت ، لذا يرجى تصحيح ما إذا كان أي من هذا خطأ.

أعتقد أن فحص النوع أمر لا بد منه لأي قاعدة بيانات منتجة ، سواء فحص ثابت أو فحص نوع الدعائم في وقت التشغيل.

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

تحرير: لم تجرب هذا لأي شيء بخلاف التحقق من صحة الدعائم ، اسمح لي أن أعرف ما إذا كان سيعمل أيضًا مع الفتحات / الأحداث!

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