Typescript: TS4023: المتغير الذي تم تصديره 'X' له أو يستخدم اسم 'Y' من الوحدة النمطية الخارجية 'a / file / path' ولكن لا يمكن تسميته

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

أحاول إنشاء مجموعة من وحدات TypeScript النمطية الخارجية على النحو التالي:

// ClassA.ts
export default class ClassA {
  public method() { return true; } 
}

// ModuleB.ts
import ClassA from './ClassA';
var moduleB = {
  ClassA: ClassA
};
export default moduleB;

// ModuleA.ts
import moduleB from './ModuleB';
var moduleA = {
  moduleB: moduleB
}
export default moduleA;

الفكرة هي أن يتم تجميعها وتوفيرها كمكتبة. تتمثل الخطة في أن مستهلك المكتبة سيقوم بإنشاء مثيل لـ ClassA على النحو التالي:

import moduleA from './ModuleA';
var anInstance = moduleA.moduleB.ClassA();

يبدو هذا كما لو أنه يتم تجميعه وصولاً إلى JS المتوقع ، لكنني أتلقى خطأ في برنامج التحويل البرمجي الذي أواجه صعوبة في العثور على مزيد من المعلومات عنه.

Using tsc v1.6.2
.../src/ModuleA.ts(3,5): error TS4023: Exported variable 'moduleA' has or is using name 'ClassA' from external module ".../src/ClassA" but cannot be named.

يمكن لأي شخص هنا إلقاء أي ضوء على هذه القضية؟ هل ما أحاول فعله منطقي؟

Question

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

ستحصل عادةً على إجابات أسرع على Stack Overflow ، لكننا نجري هنا أسئلة تمت صياغتها جيدًا.

تكمن المشكلة هنا في أنك تستخدم علامة --declaration ، لكنك لم توفر طريقة للمترجم للقيام بعمله.

عند محاولة إصدار ModuleA.d.ts ، يحتاج المترجم إلى كتابة نوع كائن حرفي (على سبيل المثال { moduleB: { classA: *mumble?* } } ) يمثل شكل الوحدة. ولكن لا يوجد اسم في النطاق يشير مباشرة إلى classA ، لذا فهو النوع "لا يمكن تسميته" وهناك خطأ.

إذا أضفت import من ClassA إلى ModuleA.ts ، يجب أن يختفي الخطأ.

ال 24 كومينتر

أوه - إذا لم يكن هذا المكان المناسب لطرح هذا السؤال. واسمحوا لي أن أعرف وسيسعدني أن أنشرها على وسيلة أخرى.

ستحصل عادةً على إجابات أسرع على Stack Overflow ، لكننا نجري هنا أسئلة تمت صياغتها جيدًا.

تكمن المشكلة هنا في أنك تستخدم علامة --declaration ، لكنك لم توفر طريقة للمترجم للقيام بعمله.

عند محاولة إصدار ModuleA.d.ts ، يحتاج المترجم إلى كتابة نوع كائن حرفي (على سبيل المثال { moduleB: { classA: *mumble?* } } ) يمثل شكل الوحدة. ولكن لا يوجد اسم في النطاق يشير مباشرة إلى classA ، لذا فهو النوع "لا يمكن تسميته" وهناك خطأ.

إذا أضفت import من ClassA إلى ModuleA.ts ، يجب أن يختفي الخطأ.

مرحبًا رايان - شكرًا على النصيحة بشأن تجاوز مكدس RE والنصيحة - أدت إضافة الاستيراد إلى ModuleA إلى تجميع الأشياء كما هو متوقع.

سياق صغير هنا - هدفي هنا هو في الواقع إنشاء إعلانات لوحداتي الخارجية. (شيء أعتقد أنه لم يعمل بعد؟ # 5039؟) قد يكون هذا الاستيراد ضروريًا تمامًا ولكن يبدو الأمر غريبًا بعض الشيء بالنسبة إلى ModuleA لاستيراد الرموز التي تصدرها moduleB بالفعل. والنتيجة هي أنه في كل مرة أضيف فيها إلى تصدير كائن ModuleB ، سأحتاج إلى إضافة الاستيراد إلى ModuleA - إما مباشرة:

import {moduleB} from './moduleB';
import {ClassA} from './ClassA';

أو عبر ModuleB (في محاولة لتقليل تحديد المسارات مقابل ClassA في كلا المكانين):

import {moduleB, ClassA} from './moduleB';

أعرف القليل جدًا عن مترجم TS - لذلك ربما يكون ما أقوله غير واقعي تمامًا ، لكن في البداية اعتقدت أنه يمكن للمجمع أن يستنتج أن ModuleB يقوم بتصدير كائن به رموز N ، لذا ModuleA بحاجة إلى تلك الرموز؟ معلومات الاستيراد لـ ModuleB موجودة بالفعل - هل يمكن أن يستخدمها ModuleA ؟ أو هل سيكون ذلك مستحيلًا لأن استيراد ClassA داخلي تمامًا لـ ModuleB ، لذلك لا توجد طريقة يمكن للمجمع من خلالها استنتاج النوع لـ ClassA عند إنشاء تعريفات لـ ModuleA ؟

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

لست متأكدًا تمامًا مما تقوله. كيف يجب أن يبدو ModuleA.d.ts في هذا الاقتراح؟

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

في كلتا الحالتين ، يتمثل عملك في إضافة تعليق توضيحي صريح من النوع ، إذا أضفت أي نوع من التعليقات التوضيحية ، فسيتم إرساله حرفيًا في الإخراج ؛ الخيار الآخر هو التأكد من إمكانية الوصول إلى الاسم ، أي أن لديك استيرادًا إلى الوحدة ، وأنت تفهم ما يعنيه ذلك للمستخدمين الذين يقومون باستيراد الوحدة الخاصة بك.

mhegazy قال:

لن يضيف المترجم التبعيات (أي عبارات الاستيراد) التي لم تكن موجودة في كود المستخدم عندما يصدر الإقرارات.

تكمن المشكلة في أنني لا أحتاج دائمًا إلى بيانات الاستيراد في الكود (من الواضح ، نظرًا لأنه يعمل بدون --declarations ) ، وإدراجها أمر مزعج ، مما يتسبب في حدوث أشياء مثل tslint للشكوى من "استيراد غير مستخدم". يمكنني معرفة سبب عدم رغبتك في أن يضيف المترجم تبعيات إلى جافا سكريبت المنبعثة ، ولكن ما هي المشكلة في إضافتها إلى الإعلانات المنبعثة؟

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

قد يكون لهذا عواقب أعمق.

ضع في اعتبارك moduleA -> moduleB -> moduleC -> moduleD .

moduleB هو الشخص الذي يحتاج إلى عمل import { ABC } from 'moduleA' للتغلب على هذه المشكلة.

عندما يستخدم moduleC moduleB ويقوم بتصدير توقيعه ، يفشل التجميع مرة أخرى لأن moduleB يحتاج ABC من moduleA ولكن هذه المرة moduleB لم يقم بتصديرها.

هذا يعني إما:

  1. يحتاج moduleC إلى تبعية صارمة قدرها moduleA واستيراد ABC
  2. لا يحتاج moduleB فقط إلى الاستيراد ولكن أيضًا إعادة تصدير ABC ثم استيراده بعد ذلك moduleC .

إذا قام moduleD بأشياء مماثلة ، فأنت بحاجة إلى معرفة سلسلة التبعيات بأكملها.

لم أتمكن من اختبار هذا لإثبات أن الأمر كذلك لأنني أستخدم typings وهناك مشكلة تمنعني من ذلك: https://github.com/typings/typings/issues/625 ~~

تحرير: أنا قادر على إعادة إنتاجه وبالفعل يحتاج moduleD للإشارة إلى moduleA للقيام بالاستيراد.
في المثال الخاص بي:

  • moduleA => redux
  • moduleB => redux-thunk
  • moduleC => رمز مخصص أعلى redux-thunk
  • moduleD => بعض المكتبات
  • ABC => Dispatch الواجهة بـ redux

لدي نفس المشكلة التي وصفها unional

يرجى إعادة فتح هذه المشكلة ، فالمشكلات التي حددتها

قم بإصدار https://github.com/Microsoft/TypeScript/issues/9944 مسارات إضافة الاستيراد في مرحلة إصدار الإعلان.

شكرا!

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

class Whatever {
  fetch(uri: string): Promise<void> { }
  ensureFetched = MemoizedFunction<(uri: string) => Promise<void>> = memoize((uri: string) => this.fetch(uri))
}

أود حذف نوع التعليق التوضيحي لـ ensureFetched

لقد وجدت حلاً لهذا:
في tsconfig: include: [ ..., "node_modules/@your_scope/your_library" ]
حظا سعيدا واستمتع بوقتك: مبتسم:

@ salim7 يؤدي هذا إلى إبطاء أوقات بإعادة تجميع مكتبة كان يجب أن تكون قد تم تجميعها بالفعل)

mhegazy تكررت المشكلة في السيناريو التالي:

import * as Foo from "./Foo";

export class Bar {
    baz = new Foo.Baz(); // Compiler forgot "Foo." prefix in the type, and throws this error, because "Baz" without perfix is not imported.
    getBaz() { // All the same
       return new Foo.Baz();
    }
}

الحل هو تحديد نوع صريح:

import * as Foo from "./Foo";

export class Bar {
    baz: Foo.Baz = new Foo.Baz(); // ok
    getBaz(): Foo.Baz { // ok
       return new Foo.Baz();
    }
}

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

PFight شكرا لك! وكان ذلك بالنسبة لي!

لقد واجهت للتو هذه المشكلة عند استخدام:

export { IMyInterface } from './file'
````

The solution was to do this:
```ts
import { IMyInterface } from './file'
export { IMyInterface }

لكن هذا لا ينبغي أن يكون ضروريًا حقًا.

هل اكتشف أي شخص كيفية التعامل مع noUnusedLocals ؟

yordis // @ts-ignore

pelotom نعم هذا خطأي بالكامل ،

كنت أفكر في شيء واحد وكتبت شيئًا آخر.

هل أصلحت شركة Typescript المشكلة بين noUnusedLocals والإعلانات؟

الحل الحالي الذي أجريته ، والذي أشعر بألم كامل بالنسبة لي ،

import {SomeInterface} from "./SomeFile";

const _dummySomeInterface : undefined|SomeInterface = undefined;
_dummySomeInterface;

//Code that implicitly uses SomeInterface

يتجنب noUnusedLocals ، ويسمح باستدلال النوع للواجهات العامة أيضًا ، حيثما أمكن ذلك.

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