Typescript: تكوين أنواع من القيم في المصفوفة

تم إنشاؤها على ٢٢ أكتوبر ٢٠١٨  ·  16تعليقات  ·  مصدر: microsoft/TypeScript


إصدار TypeScript: 3.0.3


مصطلحات البحث: اكتب بناءً على القيم الموجودة في المصفوفة

هل هناك ميزة حالية أو مخططة لإنشاء نوع من سلاسل في مصفوفة؟

الشفرة

const values = ['A', 'B']
type Foo = OneOf<values> // Is there a way of doing this?

const v1: Foo = 'A' // This should work
const v2: Foo = 'D' // This should give me an error since 'D' doesn't exist in values

على غرار كيفية عمل keyof :

const values = {
  A: 'A',
  B: 'B'
}
type Foo = keyof typeof values
const v1: Foo = 'A'
const v2: Foo = 'D' // Type '"D"' is not assignable to type '"A" | "B"'

القضايا ذات الصلة:https://github.com/Microsoft/TypeScript/issues/20965

رابط إلى الملعب http://www.typescriptlang.org/play/#src = let٪ 20vals1٪ 20٪ 3D٪ 20٪ 5B'A '٪ 2C٪ 20'B'٪ 5D٪ 0D٪ 0Atype٪ 20Foo1٪ 20٪ 3D٪ 20OneOf٪ 3Cvals1٪ 3E٪ 20٪ 2F٪ 2F٪ 20Is٪ 20there٪ 20a٪ 20way٪ 20of٪ 20doing٪ 20this٪ 3F٪ 0D٪ 0A٪ 0D٪ 0Alet٪ 20v1٪ 3A٪ 20Foo1٪ 20٪ 3D٪ 20 ' A '٪ 20٪ 2F٪ 2F٪ 20This٪ 20should٪ 20work٪ 0D٪ 0Alet٪ 20v2٪ 3A٪ 20Foo1٪ 20٪ 3D٪ 20'D'٪ 20٪ 2F٪ 2F٪ 20 هذا٪ 20 يجب٪ 20 إعطاء٪ 20me٪ 20an٪ 20 خطأ٪ 20 منذ٪ 20'D '٪ 20 لا يوجد٪ 20 موجود٪ 20 في٪ 20 قيم٪ 0D٪ 0A٪ 0D٪ 0 منفذ٪ 20vals2٪ 20٪ 3D٪ 20٪ 7B٪ 0D٪ 0A٪ 20٪ 20A٪ 3A٪ 20'A '٪ 2C٪ 0D٪ 0A٪ 20٪ 20B٪ 3A٪ 20'B'٪ 0D٪ 0A٪ 7D٪ 0D٪ 0Atype٪ 20Foo2٪ 20٪ 3D٪ 20keyof٪ 20typeof٪ 20vals2٪ 0D٪ 0Alet٪ 20v3٪ 3A٪ 20Foo2 ٪ 20٪ 3D٪ 20'A '٪ 0D٪ 0Alet٪ 20v4٪ 3A٪ 20Foo2٪ 20٪ 3D٪ 20'D'٪ 20٪ 2F٪ 2F٪ 20Type٪ 20 '٪ 22D٪ 22'٪ 20is٪ 20not٪ 20 ٪ 20 to٪ 20type٪ 20 '٪ 22A٪ 22٪ 20٪ 7C٪ 20٪ 22B٪ 22'

Question

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

في [email protected] وما فوق. حلها هكذا

export const type = <const>[
  'room',
  'room_with_gifter',
  'user_send'
];

export interface Activity {
  id?: string;
  type: typeof type[number];
}

ال 16 كومينتر

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

هذا ممكن:

function stringLiterals<T extends string>(...args: T[]): T[] { return args; }
type ElementType<T extends ReadonlyArray<unknown>> = T extends ReadonlyArray<infer ElementType> ? ElementType : never;

const values = stringLiterals('A', 'B');
type Foo = ElementType<typeof values>;

const v1: Foo = 'A' // This should work
const v2: Foo = 'D' // This should give me an error since 'D' doesn't exist in values

بالتأكيد ليس من الواضح كيفية القيام بذلك بالرغم من ذلك. # 27179 مرتبط.

هذا لا يزال يستخدم المعلومات المعروفة بشكل ثابت من قبل المترجم. في هذه المرحلة ، لا أفهم ما هي الميزة التي انتهت بمجرد قول ”A” | “B” .

fatcerberus من المفيد تجنب تكرار المعلومات - إذا كتبت للتو const values = ["A", "B"]; type Foo = "A" | "B"; فمن السهل على شخص ما تغيير أحدهما بينما ينسى تغيير الآخر. يمكنك كتابة const values: Foo[] =["A", "B"]; ، لكن هذا لا يزال عرضة لإضافة إدخال إضافي إلى Foo ونسيان وضعه في values .

أين نحن من هذا الآن؟

قال Like @ andy-ms أنه سيكون من المفيد حقًا تجنب تكرار المعلومات يدويًا.
ومثلما قال

بناءً على إجابة @ andy-ms ، وباستخدام تأكيدات const المقدمة في النسخة المطبوعة 3.4 ، أصبح من الممكن الآن القيام بشيء كهذا

const values = ['A', 'B'] as const
type ElementType < T extends ReadonlyArray < unknown > > = T extends ReadonlyArray<
  infer ElementType
>
  ? ElementType
  : never

type Foo = ElementType<typeof values> // this is correctly inferred as literal "A" | "B"

تم وضع علامة "سؤال" على هذه المشكلة ولم تشهد أي نشاط حديثًا. تم إغلاقه تلقائيًا لأغراض التدبير المنزلي. إذا كنت لا تزال تنتظر ردًا ، فعادة ما تكون الأسئلة مناسبة بشكل أفضل لتدفق المكدس .

في [email protected] وما فوق. حلها هكذا

export const type = <const>[
  'room',
  'room_with_gifter',
  'user_send'
];

export interface Activity {
  id?: string;
  type: typeof type[number];
}

بدلا من هذا:

export const items = <const>[
  'room',
  'room_with_gifter',
  'user_send'
];

export interface Activity {
  id?: string;
  type: typeof items[number];
}

انت تستطيع فعل ذالك:

export const items = [
  'room',
  'room_with_gifter',
  'user_send'
] as const;

export type Item = typeof items;

export interface Activity {
  id?: string;
  type: Item;
}

image

_ حقًا لا أحب استخدام type كاسم متغير ._

@ 7kms

في [email protected] وما فوق. حلها هكذا

export const type = <const>[
  'room',
  'room_with_gifter',
  'user_send'
];

export interface Activity {
  id?: string;
  type: typeof type[number];
}

الآن ماذا لو كان لدي هذا في الفصل؟

class Class {
  const list = <const>[
   'room',
   'room_with_gifter',
   'user_send'
 ];

 const withType: typeof list[number];
}

لا يعمل. أنا أيضًا لا أستطيع أن أفعل this.list[number] . أيضا ، من أجل خاصتي
usecase ، لا يمكنني تعيين list ليكون static

@ 7kms

في [email protected] وما فوق. حلها هكذا

export const type = <const>[
  'room',
  'room_with_gifter',
  'user_send'
];

export interface Activity {
  id?: string;
  type: typeof type[number];
}

الآن ماذا لو كان لدي هذا في الفصل؟

class Class {
  const list = <const>[
   'room',
   'room_with_gifter',
   'user_send'
 ];

 const withType: typeof list[number];
}

لا يعمل. أنا أيضًا لا أستطيع أن أفعل this.list[number] . أيضا ، من أجل خاصتي
usecase ، لا يمكنني تعيين list ليكون static

vegerot لا يمكنك استخدام const مباشرة في نطاق class ، لذا فإن البنية غير صحيحة.

@ 7kms

في [email protected] وما فوق. حلها هكذا

export const type = <const>[
  'room',
  'room_with_gifter',
  'user_send'
];

export interface Activity {
  id?: string;
  type: typeof type[number];
}

الآن ماذا لو كان لدي هذا في الفصل؟

class Class {
  const list = <const>[
   'room',
   'room_with_gifter',
   'user_send'
 ];

 const withType: typeof list[number];
}

لا يعمل. أنا أيضًا لا أستطيع أن أفعل this.list[number] . أيضا ، من أجل خاصتي
usecase ، لا يمكنني تعيين list ليكون static

vegerot لا يمكنك استخدام const مباشرة في نطاق class ، لذا فإن البنية غير صحيحة.

@ 7kms بلدي سيئة. لقد قمت بنسخ ولصق الكثير. ما قصدت قوله هو

class Class {
  private list = <const>[
   'room',
   'room_with_gifter',
   'user_send'
 ];

 private withType: typeof list[number];

// OR
  private withType2: typeof this.list[number];

}

الخ كل لا يعمل.
أيضًا ، بالنسبة لحالة الاستخدام الخاصة بي ، لا يمكنني تعيين القائمة لتكون ثابتة

@ 7kms

في [email protected] وما فوق. حلها هكذا

export const type = <const>[
  'room',
  'room_with_gifter',
  'user_send'
];

export interface Activity {
  id?: string;
  type: typeof type[number];
}

الآن ماذا لو كان لدي هذا في الفصل؟

class Class {
  const list = <const>[
   'room',
   'room_with_gifter',
   'user_send'
 ];

 const withType: typeof list[number];
}

لا يعمل. أنا أيضًا لا أستطيع أن أفعل this.list[number] . أيضا ، من أجل خاصتي
usecase ، لا يمكنني تعيين list ليكون static

vegerot لا يمكنك استخدام const مباشرة في نطاق class ، لذا فإن البنية غير صحيحة.

@ 7kms بلدي سيئة. لقد قمت بنسخ ولصق الكثير. ما قصدت قوله هو

class Class {
  private list = <const>[
   'room',
   'room_with_gifter',
   'user_send'
 ];

 private withType: typeof list[number];

// OR
  private withType2: typeof this.list[number];

}

الخ كل لا يعمل.
أيضًا ، بالنسبة لحالة الاستخدام الخاصة بي ، لا يمكنني تعيين القائمة لتكون ثابتة

class Class {
  private list = [
    "room",
    "room_with_gifter",
    "user_send"
  ] as const

  private withType: Class["list"][number]
}

vegerot ماذا عن هذا؟

eyalch هذا رائع! شكرا لك. اعتقدت أن الحل سيتضمن typeof أو شيء من هذا القبيل. هل يمكنك تقديم شرح سريع لكيفية عمل ذلك ، أو ربطني بالكتيب حيث تتم مناقشة ذلك؟

eyalch هذا رائع! شكرا لك. اعتقدت أن الحل سيتضمن typeof أو شيء من هذا القبيل. هل يمكنك تقديم شرح سريع لكيفية عمل ذلك ، أو ربطني بالكتيب حيث تتم مناقشة ذلك؟

vegerot بالتأكيد ، أعتقد أنه "نوع فهرس". تجده هنا في الكتيب: https://www.typescriptlang.org/docs/handbook/advanced-types.html#index -types

يسرني أني استطعت المساعدة!

مرحبًا٪ username٪ ، إذا كان الحل ElementType لا يناسبك أيضًا ،
انتبه إلى as const بعد المصفوفة . إنه أمر بالغ الأهمية

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