Typescript: فشل الوصول إلى الخاصية في اتحاد أنواع الكائنات للخصائص غير المحددة في جميع أعضاء الاتحاد

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

إصدار TypeScript: 2.1.1

الشفرة

type A = { a: string; } 
type B = { b: string; }
type AorB = A | B;

declare const AorB: AorB;

if (AorB.a) {
    // use AorB.a
}

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

السلوك الفعلي:
يشكو Typescript: "الخاصية a غير موجودة في النوع AorB ... الخاصية a غير موجودة في النوع B."

Question

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

أجد حلاً في الكتاب:

interface A { x:  number;} 
interface B { y:  string;}
function doStuff ( q: A | B ) {
  if ( 'x'  in q) {
    //  if type A...
  }
  else {
    // if type B...
  }
}

مقتطف من: بصرات علي سيد. "الغوص العميق في TypeScript." كتب آبل.

خاصية على كائن ويمكن استخدامها كحارس نوع ، ويمكن لـ TypeScript معرفة النوع الذي استخدمته.

ال 12 كومينتر

يقول الطبيب:

لتشغيل نفس الشفرة ، سنحتاج إلى استخدام تأكيد النوع:

let pet = getSmallPet();

if ((<Fish>pet).swim) {
    (<Fish>pet).swim();
}
else {
    (<Bird>pet).fly();
}

http://www.typescriptlang.org/docs/handbook/advanced-types.html

ثم في عينتك:

if ((<A>AorB).a) {
    // use AorB.a
}

تكمن المشكلة هنا في أنه نظرًا لأن B لا يعلن عن خاصية a ، فقد يكون له في وقت التشغيل خاصية a من أي نوع محتمل (لأنه يمكنك تعيين مع أي مجموعة من الخصائص إلى B طالما أنه يحتوي على خاصية b من سلسلة النوع). يمكنك جعله يعمل بشكل صريح للإعلان عن خاصية a: undefined في B (وبالتالي ضمان أن B لن يحتوي على خاصية a عشوائية):

type A = { a: string; } 
type B = { b: string; a: undefined }
type AorB = A | B;

declare const AorB: AorB;

if (AorB.a) {
    // Ok
}

يجعل الشعور بالكمال. ضرطة الدماغ.

إذا قمت بتحديد a: undefined على النوع B ، فسيتعين عليك تعيينه على undefined عند إنشاء / تمرير متغير.
للتغلب على ذلك ، يمكنك إعلان a كـ a?: undefined ، وستكون الكتابة المطبوعة سعيدة إذا حذفتها.

إذا فهمت التعليقات بشكل صحيح ، فيجب أن يعمل هذا (لكن رميات ؛ تم اختباره في الملعب): هل هذا خطأ أم لا؟ 🤔

type LinkProps = {
    to: string;
    onClick?: undefined;
    // Link specific props:
    target: string;
}

type ButtonProps = {
    to?: undefined;
    onClick: Function;
    // Button specific props:
    disabled: boolean;
}

type ActionProps = LinkProps | ButtonProps;

const Action = (props: ActionProps) =>
    props.to ?
        'Link with target: ' + props.target // Error not on ButtonProps
    :
        'Button with disabled: ' + props.disabled; // Error: not on LinkProps

Action({
  to: 'dssd',
  target: '_blank'
});

أنا لا أفهم هذا على الإطلاق. أليس if ((<A>AorB).a) هو نفسه استخدام (A.a) لأنك تجبره على إعادة كتابة A ؟

إذا قمت بتحديد a: undefined على النوع B ، فسيتعين عليك تعيينه على undefined عند إنشاء / تمرير متغير.
للتغلب على ذلك ، يمكنك إعلان a كـ a?: undefined ، وستكون الكتابة المطبوعة سعيدة إذا حذفتها.

قد يكون أفضل a?: never ، الآن لا يمكنك تعيين undefined عن طريق الخطأ

ماذا لو لم تعطِ اسمًا لكل عضو من أعضاء الاتحاد؟ (لا يمكن إجراء تأكيد نوع على النحو الوارد أعلاه بدون اسم للنوع المؤكد ، هل يمكنني ذلك؟)

type u = "str" | {prop:"val"};
function f(arg:u){return arg.prop} // TypeScript: Property 'prop' does not exist on type 'u'

اي حل؟

أجد حلاً في الكتاب:

interface A { x:  number;} 
interface B { y:  string;}
function doStuff ( q: A | B ) {
  if ( 'x'  in q) {
    //  if type A...
  }
  else {
    // if type B...
  }
}

مقتطف من: بصرات علي سيد. "الغوص العميق في TypeScript." كتب آبل.

خاصية على كائن ويمكن استخدامها كحارس نوع ، ويمكن لـ TypeScript معرفة النوع الذي استخدمته.

type ColorItemType = {
    colorId: number,
    colorName: string,
}

type NumItemType = {
    numId: number,
    numName: string
}

type ResType = {
    itemId: number,
    // 0 color 1 num
    type: number,
    itemInfo: {
        colorList: Array<ColorItemType>
        numList: Array<NumItemType>
    }
}

const request = () => {
    return [{
        itemId: 1,
        type: 0,
        itemInfo: {
            colorList: [{
                colorId: 1,
                colorName: 'blue'
            }],
            numList: []
        }
    }];
};

const dataSource: Array<ResType> = request();

const formatData = dataSource.map(dataItem => {
    const list: Array<ColorItemType | NumItemType> = dataItem.type === 1 ? dataItem.itemInfo.numList : dataItem.itemInfo.colorList;
    return list.map(listItem => {
        return {
            // An error will be reported here
            value: listItem.numId || listItem.colorId,
            label: listItem.numName || listItem.colorName
        };
    });
});

تكمن المشكلة هنا في أنه نظرًا لأن B لا يعلن عن خاصية a ، فقد يكون له في وقت التشغيل خاصية a من أي نوع محتمل (لأنه يمكنك تعيين مع أي مجموعة من الخصائص إلى B طالما أنه يحتوي على خاصية b من سلسلة النوع). يمكنك جعله يعمل بشكل صريح للإعلان عن خاصية a: undefined في B (وبالتالي ضمان أن B لن يحتوي على خاصية a عشوائية):

type A = { a: string; } 
type B = { b: string; a: undefined }
type AorB = A | B;

declare const AorB: AorB;

if (AorB.a) {
    // Ok
}

لا يعمل معي 07.10.2020

وأعتقد أن سلوك TS هذا ليس جيدًا لأنه لا يساعد المطور كثيرًا ...

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

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

kyasbal-1994 picture kyasbal-1994  ·  3تعليقات

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

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

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

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