أحاول إنشاء مجموعة من وحدات 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.
يمكن لأي شخص هنا إلقاء أي ضوء على هذه القضية؟ هل ما أحاول فعله منطقي؟
أوه - إذا لم يكن هذا المكان المناسب لطرح هذا السؤال. واسمحوا لي أن أعرف وسيسعدني أن أنشرها على وسيلة أخرى.
ستحصل عادةً على إجابات أسرع على 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
لم يقم بتصديرها.
هذا يعني إما:
moduleC
إلى تبعية صارمة قدرها moduleA
واستيراد ABC
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
، ويسمح باستدلال النوع للواجهات العامة أيضًا ، حيثما أمكن ذلك.
التعليق الأكثر فائدة
ستحصل عادةً على إجابات أسرع على Stack Overflow ، لكننا نجري هنا أسئلة تمت صياغتها جيدًا.
تكمن المشكلة هنا في أنك تستخدم علامة
--declaration
، لكنك لم توفر طريقة للمترجم للقيام بعمله.عند محاولة إصدار
ModuleA.d.ts
، يحتاج المترجم إلى كتابة نوع كائن حرفي (على سبيل المثال{ moduleB: { classA: *mumble?* } }
) يمثل شكل الوحدة. ولكن لا يوجد اسم في النطاق يشير مباشرة إلىclassA
، لذا فهو النوع "لا يمكن تسميته" وهناك خطأ.إذا أضفت
import
منClassA
إلىModuleA.ts
، يجب أن يختفي الخطأ.