تايب سكريبت - نوع ماب لعضو من المجموعة


أحاول إنشاء زوج مربوط يحدد نوع عضو معين:

export type Argument<T = unknown> = {
  value: T;
};

export type TypesOf<T extends Argument[]> = {[Index in keyof T]: T[Index]["value"]};

إذن، TypesOf<[{value: number}, {value: string}]> يجب أن يُنتج [number, string].

ومع ذلك، أحصل على هذا الخطأ:

Type '"value"' cannot be used to index type 'T[Index]'.

تحرير :

سؤال إضافي بعد تطبيق حل @jcalz:

const tuple = [{value: 1}, {value:"foo"}] as const;
type V = TypesOf<typeof tuple>;

أتلقى خطأ:

Type 'readonly [{ readonly value: 1; }, { readonly value: "foo"; }]' does not satisfy the constraint 'Argument<unknown>[]'.
  The type 'readonly [{ readonly value: 1; }, { readonly value: "foo"; }]' is 'readonly' and cannot be assigned to the mutable type 'Argument<unknown>[]'.

الإجابة رقم 1

تنفيذ TypesOf الذي تقدمه يعمل، من حيث أن TypesOf<[{value: number}, {value: string}]> فعلاً يقيم إلى [number, string]. تؤدي الأنواع المربوطة على المصفوفات والصفوف إلى مصفوفات وصفوف.

لكن هناك مشكلة، تم الإبلاغ عنها في microsoft/TypeScript#27995 حيث أن المترجم لا يدرك أنه داخل النوع المعين implementation {[I in keyof T]: ...T[I]...} أن I سينتهي به الأمر بأن يكون مجرد مؤشرات شبيهة بالأرقام. فهو يعتقد أن I قد تكون أشياء مثل "push" و "pop"، وبالتالي لا يمكن افتراض أن T[I] سيكون من نوع Argument:

export type TypesOf<T extends Argument[]> =
    { [I in keyof T]: T[I]["value"] };
// -----------------> ~~~~~~~~~~~~~
// Type '"value"' cannot be used to index type 'T[I]'.

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


في حالات مثل هذه، أميل إلى استخدام نوع الأداة Extract<T, U> لمساعدة المترجم على الاقتناع بأن نوعًا معينًا سيكون قابلًا للتعيين إلى نوع آخر. إذا كان لديك النوع T الذي أنت تعرف أنه سيكون قابلًا للتعيين إلى U، ولكن المترجم لا يعرف ذلك، يمكنك استخدام Extract<T, U> بدلاً من T. عندما يتم تحديد T لاحقًا، سيقيم Extract<T, U> على أنه مجرد T إذا كنت على صواب بشأن القدرة على التعيين. وسترى المترجم أن Extract<T, U> قابل للتعيين لكل من T وU.

في حالتنا، نحن نعلم أن T[I] سيكون قابلًا للإسناد إلى Argument لكن المترجم لا يعلم ذلك. لذلك، فإن الحل البديل التالي باستخدام Extract<T[I], Argument> سيمنع خطأ المترجم دون التأثير على ناتج TypesOf:

export type TypesOf<T extends Argument[]> =
    { [I in keyof T]: Extract<T[I], Argument>["value"] }; // no error

type Z = TypesOf<[{ value: number }, { value: string }]>;
// type Z = [number, string]

يبدو جيدا!

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