ريأكت جي إس - تايب سكريبت: إزالة المفتاح من النوع/نوع الطرح
أريد تعريف نوع عام ExcludeCart<T> يكون في الأساس T ولكن مع إزالة مفتاح محدد (في حالتي، cart). لذا، على سبيل المثال، ExcludeCart<{foo: number, bar: string, cart: number}> سيكون {foo: number, bar: string}. هل هناك طريقة للقيام بذلك في TypeScript؟
إليك سبب رغبتي في القيام بهذا، في حال كنت أسير في الطريق الخطأ: أنا أقوم بتحويل قاعدة كود جافا سكريبت موجودة إلى تايب سكريبت، والتي تحتوي على دالة مزخرفة تسمى cartify التي تأخذ فئة عنصر React Inner وتعيد فئة عنصر أخرى Wrapper.
Inner يجب أن يأخذ خاصية cart، وصفر أو أكثر من الخصائص الأخرى. Wrapper يقبل خاصية cartClient (والتي تُستخدم لتوليد خاصية cart لتمريرها إلى Inner)، وأي خاصية يقبلها Inner، باستثناء cart.
بعبارة أخرى، بمجرد أن أتمكن من معرفة كيفية تعريف ExcludeCart، أريد أن أفعل هذا به:
function cartify<P extends {cart: any}>(Inner: ComponentClass<P>) : ComponentClass<ExcludeCart<P> & {cartClient: any}>
الإجابة رقم 1
تحديث لـ TypeScript 3.5: نوع المساعدة Omit<Type, Keys> متاح الآن. يرجى مراجعة إجابة ماتياس للحصول على مثال للاستخدام.
الإجابة القديمة: منذ TypeScript 2.8 ومع تقديم Exclude، أصبح من الممكن الآن كتابة هذا على النحو التالي:
type Without<T, K> = {
[L in Exclude<keyof T, K>]: T[L]
};
أو بدلاً من ذلك، وبشكل أكثر إيجازًا، كالتالي:
type Without<T, K> = Pick<T, Exclude<keyof T, K>>;
لاستخدامك، يمكنك الآن كتابة ما يلي:
type ExcludeCart<T> = Without<T, "cart">;
الإجابة رقم 2
بينما تم الإجابة على هذا بشكل صحيح، أردت أن أشير إلى أن TypeScript 3.5 قد أضاف نوع Omit<T, E>.
type NoCart = Omit<{foo: string, bar: string, cart: number}, "cart">;
ينتج عن هذا نوع {foo: string, bar: string}.
الإجابة رقم 3
بينما لا يوجد نوع طرح مدمج، يمكنك حاليًا تحايله على النحو التالي:
type Sub0<
O extends string,
D extends string,
> = {[K in O]: (Record<D, never> & Record<string, K>)[K]}
type Sub<
O extends string,
D extends string,
// issue 16018
Foo extends Sub0<O, D> = Sub0<O, D>
> = Foo[O]
type Omit<
O,
D extends string,
// issue 16018
Foo extends Sub0<keyof O, D> = Sub0<keyof O, D>
> = Pick<O, Foo[keyof O]>
في حالة السؤال، ستقوم بما يلي:
type ExcludeCart<T> = Omit<T, 'cart'>
مع TypeScript الإصدار 2.6 أو أحدث، يمكنك تبسيطه إلى:
/**
* for literal unions
* @example Sub<'Y' | 'X', 'X'> // === 'Y'
*/
export type Sub<
O extends string,
D extends string
> = {[K in O]: (Record<D, never> & Record<string, K>)[K]}[O]
/**
* Remove the keys represented by the string union type D from the object type O.
*
* @example Omit<{a: number, b: string}, 'a'> // === {b: string}
* @example Omit<{a: number, b: string}, keyof {a: number}> // === {b: string}
*/
export type Omit<O, D extends string> = Pick<O, Sub<keyof O, D>>
اختبره في الملعب
