Typescript: إصلاح سريع لـ "لا يمكن استخدام الاتحادات في توقيعات الفهرس ، استخدم نوع كائن معين بدلاً من ذلك"

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

الكود التالي:

type K = "foo" | "bar";

interface SomeType {
    [prop: K]: any;
}

يعطي رسالة الخطأ هذه:

An index signature parameter type cannot be a union type. Consider using a mapped object type instead.

لا أحد يعرف أنواع الكائنات المعيّنة ، لذلك دعونا نعطيهم إصلاحًا سريعًا لذلك

  • يبدل توقيع الفهرس إلى نوع معين
  • ينقل الأعضاء الآخرين إلى نوع كائن منفصل يتم دمجه مع نوع تقاطع
  • يغير نوع الكائن المحتوي إلى اسم مستعار للنوع إذا كان نوع الكائن المحتوي عبارة عن واجهة
  • يتقاطع مع كل عبارات extends إذا كان نوع العنصر المحتوي هو واجهة ولديه أي عبارات extends
Error Messages Quick Fixes Moderate Fixed Suggestion help wanted

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

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

type Foo = 'a' | 'b';
type Bar = {[key in Foo]: any};

على الرغم من أن Bar ليس لديه توقيع فهرس (على سبيل المثال ، لا يمكنك عمل (obj as Bar)[value as Foo] ).

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

ال 37 كومينتر

لا أحد يعرف أنواع الكائنات المعيّنة ، لذلك دعونا نعطيهم إصلاحًا سريعًا لذلك

+1 ، لقد أتيت للتو إلى هنا لأنني كنت أتوقع 2.9 لدعم النقابات كتوقيعات فهرس لكل رمز المثال الخاص بك. أعتقد أن هذه كانت ميزة مرغوبة منذ فترة طويلة: # 5683 ، # 16760 ، إلخ.

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

type Foo = 'a' | 'b';
type Bar = {[key in Foo]: any};

على الرغم من أن Bar ليس لديه توقيع فهرس (على سبيل المثال ، لا يمكنك عمل (obj as Bar)[value as Foo] ).

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

أود العمل على هذا: الضحك:

ينقل الأعضاء الآخرين إلى نوع كائن منفصل يتم دمجه مع نوع تقاطع

ماذا نفعل إذا كان احتواء نوع الكائن فئة؟
لا أستطيع إلا أن أتخيل أنها واجهة

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

type K = "1" | "2"

class SomeType {
    a = 1;
    [prop: K]: any;
}

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

أود أن أقول إن هذا لا ينبغي أن يكون قابلاً للإصلاح ..

mhegazy أنا أستخدم 3.0.0-rc وما زلت أتلقى نفس الخطأ كما تم نشره في الأصل. هل هذا متوقع؟

أنا أستخدم 3.0.0-rc وما زلت أتلقى نفس الخطأ كما تم نشره في الأصل. هل هذا متوقع؟

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

لا توجد إجراءات رمز متاحة مع 2.9.1 و vscode

ThaJay لن نقوم إعداد إصدار أحدث.

بوضوح. أنا آسف لعدم التحقق من الجدول الزمني أولاً ، فقط افترضت أنه سيكون جديدًا بما يكفي. جديد في ts. سوف نتحقق من الإصدار 3.

كيف أصف هذا:

function createRequestTypes(base){
  return ['REQUEST', 'SUCCESS', 'FAILURE'].reduce((acc, type) => {
    acc[type] = `${base}_${type}`
    return acc
  }, {})
}

const user = createRequestTypes('USER')
console.log(user.REQUEST) // error
// just string? like:
interface IRequestType: {[key: string]: string}

حاولت أدناه ، فشلت جميعها:

type requestStatus = 'REQUEST' | 'SUCCESS' | 'FAILURE'
type requestTypes = {
  [key in requestStatus]: string
}
// or
interface IRequestTypes {[key: keyType]: string}
// or even
type requestTypes = {
  FAILURE: string,
  SUCCESS: string,
  REQUEST: string
}

maicWorkGithub هنا تذهب:

const user = createRequestTypes('USER')
console.log(user.REQUEST) 

function createRequestTypes(base:string):requestTypes {
  const result : requestTypes    = {}
  const arr    : requestStatus[] = ['REQUEST', 'SUCCESS', 'FAILURE']  

  return arr.reduce((acc, type) => {
    acc[type] = `${base}_${type}`
    return acc
  }, result)
}


type requestStatus = 'REQUEST' | 'SUCCESS' | 'FAILURE'
type requestTypes = { [key in requestStatus]?: string }

ihorskyi شكرا !!

مجرد فضول لماذا type يعمل ، لكن interface لا يعمل. هل يمكن لأحد أن يشرح ، من فضلك؟ ما سبب هذا التحديد (أو الميزة؟) لـ interface .

type Foo = 'a' | 'b';
type Bar = {[key in Foo]: any}; // ok
interface Baz {[key in Foo]: any} // =>

// A computed property name in an interface must refer to an expression whose type is a literal type or a 'unique symbol' type.ts(1169)
// A computed property name must be of type 'string', 'number', 'symbol', or 'any'.ts(2464)
// 'Foo' only refers to a type, but is being used as a value here.ts(2693)

كان هذا إصلاحًا تلقائيًا مذهلاً لاكتشافه. شكرا لك على تنفيذها! :)

نفس الشيء بالنسبة للفصول.

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

type Foo = 'a' | 'b';
type Bar = {[key in Foo]: any};

على الرغم من أن Bar ليس لديه توقيع فهرس (على سبيل المثال ، لا يمكنك عمل (obj as Bar)[value as Foo] ).

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

استخدم Record بدلاً من ذلك!

type Foo = 'a' | 'b'
type Bar = Record<Foo, any>

لإضافة مثال آخر على هذا باستخدام فئة ...

class Foo {
   a: string;
   b: string;
}

type Bar = {[key in keyof Foo]: any};

بل إنه أفضل عند استخدام Partial

type A = 'x' | 'y' | 'z';
type M = Partial<{
    [key in A]: boolean
}>;

لا أحد يعرف أنواع الكائنات المعيّنة ، لذلك دعونا نعطيهم إصلاحًا سريعًا لذلك

تضمين التغريدة
لماذا لا تقترح رسالة الخطأ الإجابة ، على سبيل المثال ، اعرض مثالًا سريعًا باستخدام النوع المعين - سيكون ذلك عبارة عن سطرين فقط من التعليمات البرمجية التي ستكون متسقة مع متوسط ​​طول رسائل خطأ Typescript:

هل يعرف أي شخص ما إذا كان من الممكن القول إن الواجهة التي تستخدم النوع أو التعداد كمفتاح يمكنها قبول خاصية واحدة فقط؟

على سبيل المثال توقيع مثل هذا: { <field>: { <and|or|xor>: <int> } } مأخوذ من

export enum BitwiseOperator {
    and = "and",
    or = "or",
    xor = "xor",
}

export type BitwiseCondition = {
    [key in BitwiseOperator]?: number;
}

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

const query: BitwiseCondition = {
  and: 5,
  or: 6  // raise a ts error
};

@ b4dnewz لا يمكنك القيام بذلك في الأنواع. الحل: https://github.com/Microsoft/TypeScript/issues/10575

@ b4dnewz ، إذا كنت تريد ملكية واحدة فقط ، فلماذا لا تفعلها على هذا النحو ؟

export enum BitwiseOperator {
  and = "and",
  or = "or",
  xor = "xor",
}

export type BitwiseCondition = {
  operator: BitwiseOperator;
  value: number;
}

benwinding للأسف الشكل الذي تم إرجاعه يختلف عما يتوقعه mongodb

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

أحاول أن أبقي تعريفات المشغلين المغتربين بسيطة قدر الإمكان لتجنب الصداع ، وربما يتم إضافة دعم مناسب في المستقبل

@ b4dnewz عادل بما فيه الكفاية ،

ربما يكون الخيار الأبسط الذي يمكنك استخدامه هو:

export type BitwiseCondition =
  | { or: number }
  | { xor: number }
  | { and: number }

هذا هو أقرب ما ستحصل عليه دون الكثير من الازدواجية

@ b4dnewz عادل بما فيه الكفاية ،

ربما يكون الخيار الأبسط الذي يمكنك استخدامه هو:

export type BitwiseCondition =
  | { or: number }
  | { xor: number }
  | { and: number }

هذا هو أقرب ما ستحصل عليه دون الكثير من الازدواجية

لن ينتج عن هذا خطأ في هذا المثال:

const query: BitwiseCondition = {
  and: 5,
  or: 6  // raise a ts error
};

اعتقدت أن هذا هو بيت القصيد

apieceofbart ،

لن ينتج عن هذا خطأ في هذا المثال:

export type BitwiseCondition =
  | { or: number }
  | { xor: number }
  | { and: number }

const query: BitwiseCondition = {
  and: 5,
  or: 6  // doesn't raise a ts error!
};

واو! هذا غريب: open_mouth: لم أكن أعرف ذلك!

يبدو أن Typescript لا تدعم الأنواع الحصرية المتبادلة للكائنات. كان أيضًا اقتراحًا للغة هنا: https://github.com/microsoft/TypeScript/issues/14094

لا يزال من الممكن تقنيًا على الرغم من ...

من هذا الجواب الأنواع الشرطية (أصعب الأنواع) ، لكنها ليست جميلة ....

/*
 XOR boiler plate
*/
type Without<T, U> = { [P in Exclude<keyof T, keyof U>]?: never };
type XOR<T, U> = T | U extends object
  ? (Without<T, U> & U) | (Without<U, T> & T)
  : T | U;
type XOR3<S, T, U> = XOR<S, XOR<T, U>>;

// Code start
export type BitwiseCondition = XOR3<
  { or: number },
  { xor: number },
  { and: number }
>;

const query1: BitwiseCondition = {
  and: 5
};

const query: BitwiseCondition = {
  and: 5,
  or: 6 // raise a ts error
};

إذا كان بإمكان أي شخص جعل هذا أجمل أو أفضل ، من فضلك افعل

mvasin FWIW ، يبدو أن هذا _ يظهر لتحقيق نفس النتيجة ، لكنني أوافق تمامًا على أنه يجب أن يكون ميزة للواجهات تمامًا كما هو الحال في الأنواع.

type Foo = 'a' | 'b';

type Bar = {
  [key in Foo]: any
}

interface A extends Bar { }

class Wol implements A{
  a: any;
  b: any;
}

بالنسبة إلى النسخة المطبوعة 3.5 ، يبدو أنه يتعين علي القيام بذلك:

export interface DataTableState {
  columnStats: {[key in keyof DataTable]?:{}}
}

هل هذه هي أفضل طريقة للقيام بذلك؟

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

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

type MyType = {
  [Key: 'foo' | 'bar' | 'zip']: number;
};

يجب أن يرضي هذا:

const x: MyType = {
  foo: 1,
  zip: 2
};

بينما يمكنني فقط تعيين المفاتيح الأخرى غير معرَّفة لنوع معين ، أفضل أن أجعل المفاتيح اختيارية ، ولكن إذا كانت موجودة ، فلا يمكن إلغاء تحديد القيمة. إذا جعلت قيم الكتابة المعينة اختيارية ، فستعمل الكود ولكن الأنواع أقل قوة.

بل إنه أفضل عند استخدام Partial

type A = 'x' | 'y' | 'z';
type M = Partial<{
    [key in A]: boolean
}>;

شكر!
مفيد عندما تحتاج إلى تحديد نوع يتطابق جزئيًا مع القاموس

يمكن استخدام "جزئي" في السجلات أيضًا:

type Foo = 'a' | 'b';
let foo1: Record<Foo, number> = { a: 1, b: 2 };
let foo2: Partial<Record<Foo, number>> = { a: 1 };

أجد نفسي أزور صفحة GitHub هذه عن غير قصد كل شهر أو نحو ذلك.

آخر ما لدي هو واحد بسيط حقيقي:

interface ObjectLiteral {
    [key: string | number]: any
}
export const mapToObjectLiteral = (map: Map<string|number, any>) =>
    Array.from(map).reduce((objLit, [key, value]) => {
        objLit[key] = value
        return objLit
    }, {} as ObjectLiteral)

image

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

هنا مثال:

type MapKey = string | number;
type ObjectLiteral<T extends MapKey, V = any> = {
  [P in T extends number ? string : T]: V;
};

export const mapToObjectLiteral = <T extends MapKey, V>(map: Map<T, V>) =>
  Array.from(map).reduce((objLit, [key, value]) => {
    objLit[key as keyof ObjectLiteral<T>] = value;
    return objLit;
  }, {} as ObjectLiteral<T, V>);

// how to make a better type of map ?
const m = new Map<1 | "foo", "a" | "b">();
m.set(1, "a");
m.set("foo", "b");

const o = mapToObjectLiteral(new Map(m));

console.log(o[1], o.foo); // just got an union type of every member of 'o'

https://github.com/microsoft/TypeScript/issues/24220#issuecomment -504285702

لإضافة مثال آخر على هذا باستخدام فئة ...

class Foo {
   a: string;
   b: string;
}

type Bar = {[key in keyof Foo]: any};

مفيد جدا. شكر! 🚀

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