فيجوال ستوديو كود - كيف يمكنني رؤية العقد الكامل الموسع لنوع TypeScript؟


إذا كان لدي مجموعة من الأنواع التي تبدو هكذا:

type ValidValues = string | number | null
type ValidTypes = "text" | "time" | "unknown"

type Decorated = {
  name?: string | null
  type?: ValidTypes
  value?: ValidValues
  title: string
  start: number
}

type Injected = {
  extras: object
}

// overriding the types from Decorated
type Text = Decorated & Injected & {
  name: string
  type: "text"
  value: string
}

كدّي الفعلي يحتوي على المزيد من الأمور، لكن هذا يوضح الفكرة الأساسية. لا أريد أن أضطر إلى الوثوق بنفسي للحصول على العلاقات بين الأنواع بشكل صحيح. أريد أدوات لتُظهر لي ما تُـ„قيم„ تعريف النوع Text، بعد كل جبر الأنواع.

لذلك بالنسبة للمثال أعلاه، آمل أن الحقول المحددة في Text ستتجاوز الإعلانات السابقة التي تمت في نوع Decorated، ويجب أن يعرض إخراج التلميح الافتراضي شيئًا مثل هذا:

{
  name: string
  type: "text"
  value: string
  title: string
  start: number
  extras: object
}

هل هناك أي طريقة ملائمة للحصول على هذه المعلومات؟

الإجابة رقم 1

المعلومات السريعة لنوع ما المعروضة باستخدام IntelliSense غالبًا ما تترك شيئًا مرغوبًا فيه؛ عادةً ما تحصل على تمثيل واحد لأي نوع معين، والذي قد يكون موجزًا جدًا أو حتى مطولًا جدًا لأغراضك. هناك بعض الاقتراحات لجعله أكثر مرونة (مثل microsoft/TypeScript#25784 و microsoft/TypeScript#28508) بحيث يمكن للمستخدمين توسيع/طي تعريفات النوع في بيئات تطويرهم. لكنني لا أعرف ما إذا كان سيتم تنفيذها في المستقبل القريب أو حتى البعيد، لذلك لن ننتظر ذلك.


إليك نوع مستعار أستخدمه أحيانًا لمحاولة توسيع نوع بالطريقة التي تتحدث عنها:

// expands object types one level deep
type Expand<T> = T extends infer O ? { [K in keyof O]: O[K] } : never;

// expands object types recursively
type ExpandRecursively<T> = T extends object
  ? T extends infer O ? { [K in keyof O]: ExpandRecursively<O[K]> } : never
  : T;

تستخدم تلك استنتاج النوع الشرطي لـ "نسخ" نوع T إلى متغير نوع جديد O ثم نوع مماثل للهوية يتم تعيينه والذي يتكرر عبر خصائص النوع المنسوخ.

استنتاج النوع الشرطي هو من الناحية المفهومية عملية لا تفعل شيئًا، لكنه يُستخدم لتوزيع أنواع الاتحاد ولإجبار المترجم على تقييم فرع "الصحيح" من الشرط (إذا قمت بإعادة تعريف Expand<T> بدونه، في بعض الأحيان سيقوم المترجم ببساطة بطباعة النوع المعين {[K in keyof RelevantType]: RelevantType[K]}، وهو ليس ما تريد رؤيته).

الفرق بين Expand و ExpandRecursively هو ما إذا كان يجب مجرد عرض أنواع الخصائص كما هي (Expand)، أو إذا كان يجب توسيع أنواع الخصائص (ExpandRecursively). يساعد هذا في الحالة المتكررة بعدم محاولة التعمق في الأنواع الأولية، ولهذا السبب تم تضمين شرط T extends object.


حسنًا، لنرى ما الذي سيحدث عندما نستخدمه على نوعك. لا نحتاج إلى ExpandRecursively في حالتك، ولكن يمكننا استخدامه... يعطي نفس النتيجة:

type ExpandedText = Expand<Text>;

والذي، عندما نحوم فوقه في بيئة التطوير المتكاملة (TypeScript Playground وVSCode على أي حال)، يتم عرضه كالتالي:

/* type ExpandedText = {
  name: string;
  type: "text";
  value: string;
  title: string;
  start: number;
  extras: object;
 } */

كما أردت.

رابط إلى الكود

الإجابة رقم 2

مجرد تكملة لإجابة jcalz مع نسخ تعمل مع الدوال.

المساعدون المعدلون:

export type Expand<T> = T extends (...args: infer A) => infer R
  ? (...args: Expand<A>) => Expand<R>
  : T extends infer O
  ? { [K in keyof O]: O[K] }
  : never;

export type ExpandRecursively<T> = T extends (...args: infer A) => infer R
  ? (...args: ExpandRecursively<A>) => ExpandRecursively<R>
  : T extends object
  ? T extends infer O
    ? { [K in keyof O]: ExpandRecursively<O[K]> }
    : never
  : T;

للاختبار، أقوم بإضافة مفتاح subobject إلى نوع Text، وإضافة واجهة دالة:

type Text = Decorated &
  Injected & {
    name: string;
    type: "text";
    value: string;
    subobject: Injected;
  };

interface SomeFunction {
  (...args: Text[]): Injected & { error: boolean };
}

هذا يعطي:

الأشياء لا تزال تعمل بشكل جيد:

الإجابة رقم 3

لقد وجدت أن هذا الامتداد في VS Code يعمل بشكل مثالي لهذا:

تحسين مظهر TypeScript: معاينات أنواع أفضل

يُظهر حتى الأنواع المتداخلة بعمق عند التمرير فوقها.