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

تم إنشاؤها على ٢٥ مارس ٢٠١٥  ·  32تعليقات  ·  مصدر: microsoft/TypeScript

يتطلب التنصيب أن تحتوي التعدادات على أنواع قيم رقمية (نأمل قريبًا أن يتضمن هذا أيضًا أنواع قيم السلسلة).

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

تعد Enums طريقة مناسبة لتحديد مجال أنواع قيمة الأرقام والسلسلة ، في حالات مثل

export interface UserInterfaceColors {
    [index: UserInterfaceElement]: ColorInfo;
}
export interface ColorInfo {
    r: number;
    g: number;
    b: number;
    a: number;
}
export enum UserInterfaceElement {
    ActiveTitleBar = 0,
    InactiveTitleBar = 1,
}
Fix Available Suggestion

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

يجب أن يكون ممكنًا الآن مع MappedTypes .

لذلك يمكن أن يكون المثال في OP:

export type UserInterfaceColors = {
    [P in UserInterfaceElement]: ColorInfo;
}

ال 32 كومينتر

+1 ، هذه طريقة رائعة للقواميس الآمنة من النوع.

+1

إذا تبنى فريق TS "أنواع المجموعات" # 3105 ، فسيكون ذلك ناجحًا أيضًا:

interface SomeArrayLikeThing {
    [index: 0...255]: number;
}

enum foo {
 [prop: string]: 0...255
 a,
 b,
 c
}

interface SomeArrayLikeThingByEnum {
    [index: foo]: number;
}

من المحتمل أن يتطلب على الأقل في المترجم شيئًا مثل:

export interface ObjectIndex {
       valueType: Type        // any
       keyType?: Type         // string|number or any subset type
}
export interface ResolvedType extends ObjectType, UnionType {
       members: SymbolTable;              // Properties by name
       properties: Symbol[];              // Properties
       callSignatures: Signature[];       // Call signatures of type
       constructSignatures: Signature[];  // Construct signatures of type
       stringIndex?: ObjectIndex;            // String index
       numberIndex?: ObjectIndex;        // Numeric index
}

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

enum Color { red, green, blue }
enum Size { small, medium, large }
interface Alpha {
  [c: Color]: string;
}
interface Beta {
  [c: Size]: string;
}
interface Gamma {
  [c: number]: string;
}
interface Delta {
  [c: Color]: string;
  [c: Size]: string;
}

أشياء واضحة:

  • لا يمكنك فهرسة Alpha بواسطة Size

الأشياء غير الواضحة:

  • هل يمكن Alpha لـ Beta ؟
  • هل يمكن Gamma لـ Alpha ؟ والعكس صحيح؟
  • هل يمكنني فهرسة Alpha بواسطة number ؟
  • هل يعتبر Delta إقرارًا قانونيًا؟ (يميل بقوة نحو _لا _)

(أ)

هل ألفا قابل للتخصيص لبيتا؟
هل دلتا إعلان قانوني؟

لا

(ب)

هل يمكنني فهرسة ألفا برقم؟
هل جاما قابل للتخصيص لـ Alpha؟ والعكس صحيح؟

نعم (للأسف) ، اتبع isTypeAssignableTo ()

const enum Color { red, green, blue }
let a: number;
let b: Color;
a = 4;
b = 4; // unfortunately (c)

interface Alpha {
  [c: Color]: string;
}
let c: Alpha;
c[Color.red];
c[0];
c[4]; // unfortunately (c)

سأكون سعيدًا إذا تغيرت (ج) في النهاية بحيث لا تقبل تعدادات الثوابت إلا الثوابت أو الأنواع ضمن نطاق قيمها.

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

سيكون من الرائع شرح تفاصيل Meh (تاريخ اجتماع التبادل)

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

إذن فهو قيد على الموارد وليس تعقيدًا تقنيًا؟

RyanCavanaugh لا budget لهؤلاء؟

مثال أكثر تفصيلاً:

type Foo = {};
interface IndexTypes {
  [oneTo5: 1...5]: string;
  [sixTo20: 6...20]: number;
  [someSymbol]: Foo;
}
let a: IndexTypes;
a[0]; // string
a[6]; // number
a[someSymbol]; // Foo

الرموز الداعمة تعني أن تعقيدك budget يرتفع على أي حال.

الآن لدى المترجم شيء مثل:

export interface ResolvedType extends ObjectType, UnionType {
       members: SymbolTable;              // Properties by name
       properties: Symbol[];              // Properties
       callSignatures: Signature[];       // Call signatures of type
       constructSignatures: Signature[];  // Construct signatures of type
       stringIndex?: ObjectIndex;            // String index
       numberIndex?: ObjectIndex;        // Numeric index
       otherIndexes?: ObjectIndex[]
}

فقط لا ترى ما يمكنك فعله other things .

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

+1 مهتم بأي أنماط أخرى لتحقيق أمان النوع المتمثل في القدرة فقط على فهرسة كائن باستخدام تعداد ثابت محدد أو (كما أشار jbondc) للأسف رقم أيضًا .

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

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

enum Domestic {
    Cat,
    Dog
}

enum Wild {
    Bear,
    Tiger
}

class AnimalController<T> {

    private _lists: { [key:T]: IAnimal[] };

    // constructor...

    public register( type:T, animal:IAnimal ) {
        this._lists[ +type ].push( animal );
    }

    public getListByType( type:T ): IAnimal[] {
        return this._lists[ +type ]; // << cast enum to number
    }
}

var dac = new AnimalController<Domestic>();

// register animals ...

dac.getListByType( Domestic.Cat ); // OK

// correctly fails with "not assignable" error.
dac.getListByType( Wild.Bear );

إذا كان بدلاً من ذلك getListByType() يقبل أي رقم. على سبيل المثال:

public getListByType( type:number ): IAnimal[] {
    return this._lists[ type ];
}

// This would not be caught at compile time and since
// Domestic.Cat and Wild.Bear are the same value 
// it would return a valid ( but very wrong ) list...
dac.getListByType( Wild.Bear );

يرجى النظر في تراكم هذا بدلا من إغلاق.

يرجى النظر في تضمين هذه الميزة .. ماذا عن ربط سلسلة مع تعداد ، هي ممارسة شائعة جدًا لربط أي نوع من البيانات بالتعداد.

إذا كان بإمكان الأشخاص "التفاعل" مع OP بدلاً من نشر إجراءات 1+ ، فسيكون ذلك مفيدًا من حيث تقليل الضوضاء هنا ومساعدتنا في الحصول على عدد دقيق من التعليقات. شكرا!

(تم حذف +1 ، بجدية ، استخدم ردود الفعل)

أنا أتفاعل بلا خجل مع جميع المشاركات في هذا الموضوع

يجب أن يكون ممكنًا الآن مع MappedTypes .

لذلك يمكن أن يكون المثال في OP:

export type UserInterfaceColors = {
    [P in UserInterfaceElement]: ColorInfo;
}

mhegazy : يبدو أنه قد يكون أصعب قليلاً من ذلك في الممارسة؟

export enum MyEnum {
    First = 0,
    Second = 1,
}

export type EnumMap = {
    [P in MyEnum]: string;
}

// [ts] Type '{ [x: number]: string; }' is not assignable to type 'EnumMap'.
//      Property '0' is missing in type '{ [x: number]: string; }'.
const doesntWork: EnumMap = {
    [MyEnum.First]: "first",
    [MyEnum.Second]: "second",
};

const works: EnumMap = {
    0: "first",
    1: "second",
};

// but then this is allowed, should it be?
works["foo"] = "bar";
// but then: 
// [ts] Property 'foo' does not exist on type 'EnumMap'.
type test = typeof works["foo"]

يمكنك استخدام أي نوع كمفتاح لـ Map وإذا كنت تريد حقًا كتابة مفاتيح كائنات آمنة ، فيمكنك لفها.

class DictValues<V> {
    [key: string]: V;
    [key: number]: V;
}

interface ToStringer {
  toString(): string;
}

class Dict<K extends ToStringer, V> {
  private _values: DictValues<V> = Object.create(null);

  get(key: K): V {
    return this._values[key.toString()];
  }

  set(key: K, value: V): void {
    this._values[key.toString()] = value;
  }

  has(key: K): boolean {
    return this._values.hasOwnProperty(key.toString());
  }

  values(): DictValues<V> {
    return this._values;
  }
}

mhegazy : أحصل على Type 'UserInterfaceColors' is not assignable to type 'string' عند استخدام الكود الذي يجب أن يعمل:

export type UserInterfaceColors = {
    [P in UserInterfaceElement]: ColorInfo;
}

إلى جانب البتات @ JKillian المذكورة تجعلني أعتقد أنه يجب إعادة فتح هذا (أو على الأقل إزالة علامة Fixed )

تم كسر هذا بواسطة https://github.com/Microsoft/TypeScript/pull/12425. هل تمانع في تسجيل إصدار جديد للسماح بالحرفيات الرقمية كقيود للأنواع المعينة؟

مرحبًا ، سأستفيد أيضًا من القدرة على استخدام نوع معلن كمؤشر ، حتى أتمكن من تقييد نوع الفهارس التي يتم استخدامها.

على سبيل المثال:

declare type validationTypes = 'email' | 'number' | 'abn';

interface IField {
  label:                string;
  model:                string;
  type:                 fieldType;
  placeholder?:         string;
  addon?:               string;
}

interface IEmailValidation {
  email:              string;
}
interface IRequiredValidation {
  required:             string;
}


interface IEmailField extends IField {
  type:                'email';
  validation:        IDictionary<IEmailValidation | IRequiredValidation>
}

ما أحاول تحقيقه هو أن التحقق سيكون قاموسًا وله مفتاح "البريد الإلكتروني" ونوع قيمة السلسلة والتحقق المطلوب.

لن يكون لحقل النص سوى التحقق المطلوب.

يبدو كائن جافا سكريبت على النحو التالي:

const emailField =        {
          "label":                "Email Address",
          "model":               "emailaddress",
          "type":                 "email",
          "placeholder":          "Please enter an email address",
          "validation": {
            "required":          "An email address is required",
            "email":              "Please enter a valid email address"
          }
        }

لا يمكنني الآن السماح إلا بجميع عمليات التحقق الممكنة ولكن لا يمكنني تقييد مجموعة عمليات التحقق لكل نوع حقل. هذا بسبب أن الفهرس يجب أن يكون قيد السلسلة أو الرقم.

إذا كان من الممكن تحديد قاموس مثل هذا:

export interface IDictionary<K,V> {
  [index: key]: V;
}
then K could be a declare type of 'email' | 'required' for an email field and only 'required' for a text field.

أي أفكار؟

يبدو أن هذا نمط متكرر جدًا ، وسيكون من الجيد دعمه.

type keys = 'a' | 'b' | 'c'
let map: { [key: keys]: string } = {}

apetrushin يمكنك استخدام "in" لهذا الغرض

type keys = 'a' | 'b';
let anObject: { 
    [index in keys]: string;
}
anObject.a = "correct";
anObject.t = "error";

شكرًا ، لكنه لا يزال يسمح بإجراء anObject['non-existing-key'] = 'value'

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

يبدو أن هذا مكسور مرة أخرى اعتبارًا من TS 2.4 (2.x؟)

enum Things { ONE, TWO }
// Error: Type 'Things' is not assignable to type 'string'. 
type ThingMap = {[TKey in Things]: boolean};

يبدو أن هذا انحدار معروف مع إصلاح على خارطة الطريق: https://github.com/Microsoft/TypeScript/issues/13042

nevir أنا أستخدم 2.6 وهو يعمل بشكل جيد بالنسبة لي ولكن لأنني تطابق enum keys مع بعض string

enum Things { ONE = 'one', TWO = 'two' }

هل ينبغي أن يكون هذا هو السلوك الافتراضي؟ أو يجب أن يكون مجرد إجراء التعداد دون أي تعيين؟

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

القضايا ذات الصلة

jbondc picture jbondc  ·  3تعليقات

CyrusNajmabadi picture CyrusNajmabadi  ·  3تعليقات

Antony-Jones picture Antony-Jones  ·  3تعليقات

blendsdk picture blendsdk  ·  3تعليقات

wmaurer picture wmaurer  ·  3تعليقات