Typescript: استيراد القوة

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

لدي العديد من السيناريوهات حيث يمكنني القيام بذلك:

import myExternalModule = require("./myExternalModule");
// not using myExternalModule here

لا أستخدم myExternalModule في الكود الخاص بي ولكني ما زلت أريد أن يتم تضمينه باستخدام needjs. أنا فقط أحتاجه لأكون هناك.
إذا كان من الممكن وجود كلمة رئيسية forceimport فسيكون ذلك رائعًا جدًا!

Question

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

فلماذا لا تضيف فقط

import * as React from "react"; // get the types
import "react";  // just for side effect

في الإخراج ، الاستيراد الأخير: import "react" لن يتم حذفه.

ال 31 كومينتر

يجب أن يكون من الممكن إجبار الانبعاث عن طريق الكتابة

var myExternalModule = require("./myExternalModule");

لكن هذا لن يشتكي إذا كان "./myExternalModule" مسارًا غير صحيح.

النهج الصحيح هو تقديم مرجع وهمي ليس له آثار جانبية:

import myExternalModule = require("./myExternalModule"); 
myExternalModule;

على الرغم من أن هذا اختراق ، إلا أنه من غير المرجح أن يتم تقديم بناء جملة جديد لحالة الاستخدام الضيقة هذه. انظر إلى أهداف التصميم.

إذا كان TypeScript سيتحقق من المسار في var myExternalModule = require("./myExternalModule"); فإن ذلك سيسمح للمستخدمين بفرض الإرسال _ و _ الحصول على التحقق من وقت الترجمة ، دون الحاجة إلى اللجوء إلى الاختراق.

لا يستورد الأسلوب var الأنواع من الوحدة بالرغم من ذلك.

بالإضافة إلى ذلك ، يمكنك استخدام سمة التبعية amd إذا لزم الأمر.

لأي غرض تقوم باستيراد أشياء غير مستخدمة؟

على سبيل المثال ، في تطبيق angular ، لدي بعض التوجيهات في ملفات أخرى. أحتاج إلى استيراد هذه التوجيهات وإلا فلن يعمل ترميز html الخاص بي. لا أستخدمها في JavaScript بالرغم من ذلك.
عادةً ما يتم فصل معظم الوحدات النمطية في الزاوية وليس لها تبعيات على بعضها البعض ، ولكن يلزم استيرادها حتى يعمل التطبيق بأكمله.

: +1:
إنه يحيرني.
لماذا يقوم مترجم TypeScript بإزالته؟
الوحدة الخارجية ليست وحدة غير مسبوقة.
تتطلب له آثار جانبية.
يبدو أن شرط الاستيراد متوافق مع متطلبات AMD و CommonJS. لكنها ليست كذلك.

هذه المشكلة مزعجة أيضًا عند طلب وحدات () - ing التي لا تصدر فعليًا أي شيء ولكن بدلاً من ذلك وظائف الرقائق على الكائنات العالمية ، مثل es5-shim ، es6-shim والعديد من الآخرين.

إنه يحيرني.
لماذا يقوم مترجم TypeScript بإزالته؟

إنه تحسين لأننا في بعض الأحيان نريد استيراد معلومات النوع فقط من وحدة نمطية:

import foo = require('foo');

function bar(paramOne: foo.ParamOne, paramTwo: foo.ParamTwo){}

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

يمكنك استخدام العلم amd-dependency لهذا:

/// <amd-dependency path="foo" />

import x = require('foo');

بدلاً من <amd-dependency> الذي يبدو قليلاً من الاختراق ، كان من المثير للاهتمام استخدام <reference name="..."> IMO.

dquirk إنه أمر تعسفي وخطير أن يتحمل محرك TypeScript مسؤولية تحسين بيانات الاستيراد. هناك العديد من الأنماط التي لم يلتقطها TypeScript حتى الآن من JavaScript. أحد الأمثلة هو كيف أنه لا يعالج أن this يمكن أن يكون من النوع # 229.

يُستخدم الاستيراد لتحميل التبعيات قبل تحميل الكود الحالي وقد لا تتم الإشارة إليه مباشرةً. تعد التبعيات الزاويّة أحد الأمثلة ، بينما ملحقات jQuery هي مثال آخر. أي مكتبة تقوم بتوسيع كائن أساسي ولا يتم الرجوع إليها مباشرة تتأثر بـ "الميزة". من خلال اتخاذ قرار بعدم تضمين استيراد بشكل تعسفي بناءً على تحليل ثابت محلي ، فإنك تفرض نمط مترجم على نمط C على النية الصريحة للمطور الذي كتب بيان الاستيراد. توقع كتابة الاستيراد هو أنه سيتم تضمينه كتبعية ومتاح للنطاق المحلي للوحدة. أي إجراء آخر هو أحد الآثار الجانبية للتوقع الطبيعي لاختيار كتابة import داخل وحدة.

من المحتمل جدًا في هذه الحالة أن يقوم مترجم TypeScript بعمل أقل وإنجاز المزيد.

سوف يدعم الإصدار التالي من TypeScript وحدات نمط ES6 (التغيير حاليًا في المستوى الرئيسي). لذلك إذا كان كل ما تريده هو التصريح عن التبعية ، فيمكنك استخدام:

import "myLib";

لن يتجاهل المترجم هذا الاستيراد.

هل سيتم معالجة السلوك غير المتسق الحالي ، أم سيبقى شيئًا ممتعًا يكتشفه الناس؟ هل يجب أن يضاف إلى الوثائق أن الحالة الخاصة بهم حيث لا يقوم import بإضافة الملف كعنصر تابع؟ عند إنشاء وحدات TypeScript AMD النمطية ، سيتم اعتبار ///<reference... خطأ الآن؟

الطريقة التي يعمل بها import حاليًا هي تصميم سيء. يخلق التصميم السيئ الغموض. إذا لم يتم تحديد السلوك الإضافي بوضوح ، فسيتم اكتشافه على الأرجح على الرغم من أنه من الآثار الجانبية. ومن هنا جاء OP ، وأنا ، والتعليقات والأخطاء الأخرى المتعلقة به في هذا المنتدى.

توجد مجموعة ممارسات موجودة بالفعل عند استخدام أسلوب إدارة تبعية النمط العام أو المطلوب. تنفيذ import يظهر أنه تم تجاهله.

فيما يتعلق بالوثائق ، يرجى الرجوع إلى قسم المواصفات والقسم 11.2.6 :

يتم تمثيل تصريح الاستيراد الخارجي في جافا سكريبت المُنشأ كمتغير تمت تهيئته بواسطة استدعاء وظيفة "تتطلب" التي يوفرها مضيف نظام الوحدة النمطية. يتم إصدار إعلان متغير واستدعاء "مطلوب" لوحدة نمطية مستوردة معينة فقط إذا كانت الوحدة النمطية المستوردة ، أو الاسم المستعار المحلي (القسم 10.3) الذي يشير إلى الوحدة النمطية المستوردة ، يشار إليه على أنه تعبير أساسي في مكان ما في جسم الوحدة النمطية للاستيراد. إذا تمت الإشارة إلى وحدة نمطية مستوردة فقط على أنها ModuleName أو TypeQueryExpression ، فلن يتم إصدار أي شيء.

المراجع /// ليست مثل الواردات. /// المراجع تجلب إعلانات إضافية إلى نطاقك العالمي ، على سبيل المثال dom APIs. إنه بيان للمترجم ليثق في وجود هذه الكيانات ، وليس له تأثير على الكود الذي تم إنشاؤه.

من ناحية أخرى ، يجب إرسال الواردات على أنها بيانات تتطلب. في حالة ما إذا كنت تستخدم استيرادًا في موضع كتابة فقط ، فإن الهدف غير واضح ، إما أنك تريد فقط الأنواع (وهي بنيات وقت التصميم غير الموجودة في وقت التشغيل) ، وفي هذه الحالة تريد إلغاء الاستيراد ، وإذا لم يكن الأمر كذلك ، فمن المحتمل أن تقوم باستيراد وحدة نمطية غير موجودة. أو تريد الآثار الجانبية أيضًا. بالنسبة لهذا الأخير ، يبدو أن بناء الجملة import "mod"; هو بناء جملة أوضح لإعلان النية.

mhegazy لا أريد فتح إصدار جديد ، لكن هذه مشكلة صغيرة في عالم React.
ضع في اعتبارك الكود أدناه ، عند التحويل البرمجي إلى js ، تتم إزالة المرجع React لأنه لا يظهر في الكود وسيفشل الرمز لأن ReactRouter يعتمد عليه. الإصلاح ... غبي حقًا أقل من الشفرة. هل هناك طريقة أذكى للتخلص من ذلك؟ شكرا.

import * as React from "react"; var temp = React.DOM;
....

// mf("route.schedules", "") // this is to register a translation
anonymousRoutes.route("/schedules", {
  name: "schedules",
  subscriptions: function() {
    this.register("schedules", subscriptions.subscribe("schedules"));
  },
  action: () => {
    ReactLayout.render(ClearLayout, {content: <Book />});
  }
});

FIX ؛) - EHM

import * as React from "react"; var temp = React.DOM;
...

ستفشل الكود لأن ReactRouter يعتمد عليه.

هل يحتاج إلى var "React" أو بعض الآثار الجانبية من الاستيراد؟

تحتاج إلى التأثير الجانبي من الاستيراد. تمت إضافة var فقط لعدم إزالة الاستيراد في الشفرة المترجمة.

فلماذا لا تضيف فقط

import * as React from "react"; // get the types
import "react";  // just for side effect

في الإخراج ، الاستيراد الأخير: import "react" لن يتم حذفه.

لسوء الحظ ، لا يعمل هذا المداس وما زلت أحصل على:

ReferenceError: React is not defined
    at action [as _action] (schedule_router.jsx:15)
    at Route.callAction (kadira_flow-router.js?f961d732ed2b89a53d490af5979b899800aa1a5d:2306)
    at kadira_flow-router.js?f961d732ed2b89a53d490af5979b899800aa1a5d:2025
    at Object.Tracker.nonreactive (tracker.js:560)
    at kadira_flow-router.js?f961d732ed2b89a53d490af5979b899800aa1a5d:2016
    at Tracker.Computation._compute (tracker.js:294)
    at Tracker.Computation._recompute (tracker.js:313)
    at Object.Tracker._runFlush (tracker.js:452)
    at Object.Tracker.flush (tracker.js:412)
    at Router._invalidateTracker (kadira_flow-router.js?f961d732ed2b89a53d490af5979b899800aa1a5d:2065)

أعتقد أن السبب هنا هو "التبعيات الضعيفة" في Meteor ، والتي تعتمد على _callee_ لتوفير كل المراجع اللازمة لها.

لقد بدأت في تعلم الكتابة المطبوعة مؤخرًا لـ Angular 2. وقد لفت ذلك انتباهي عدة مرات كما أنا متأكد من أنه سيكون كذلك بالنسبة للقادمين الجدد الآخرين. أدرك أن هذا تحسين ولكنه في الواقع محير للغاية. إذا قمت بكتابة شيء ما في ملف ts الخاص بي ، فأنا أتوقع أنه سينتج أو يُخرج أو لا يتجاهله ببساطة. أدرك أنني أستطيع أن أجبر بيان الطلب على أن يتم إنتاجه ولكن هذا يبدو قليلاً من الاختراق. يبدو أن هذا سبب حيث يجب أن أكون كمستخدم قادرًا على اتخاذ قراراتي الخاصة دون أن يقرر المترجم ما هو الأفضل.

يقوم TypeScript بتراكب إعلان النوع أعلى القيم ، لذا فإن بنية الاستيراد نفسها تحصل على الأنواع أو القيم أو كليهما. هذا يجعل العمل مع الوحدة أمرًا مريحًا وبديهيًا ؛ إذا كنت بحاجة إلى نوع من وحدة نمطية أخرى ، فما عليك سوى استيراده أثناء استيراد متغير ، أو مجرد استيراد الفئة ، واستخدامها كنوع ومنشئ مع new.

على الجانب الآخر من هذا ، يمكن أن يكون لديك واردات إلى وحدات نمطية غير موجودة ، لأنها مجرد حاويات من النوع. إذا أرسل المترجم إشارات إلى هذه الوحدات ، فسوف يفشل في وقت التشغيل. الحل المطبق لدينا هو اكتشاف _كيف_ تم استخدام الاستيراد ، و _ جميع المراجع إليه تستخدم كأنواع ، ثم لا تكون هناك حاجة إليها في وقت التشغيل ويتم إلغاؤها.

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

الحل:
في حالة استخدام الدقة التقليدية (لم يتم تعيين moduleResolution على node ) ، فلن يتم تجنب بيان الاستيراد الذي يحتوي على ! في معرفه. أعتقد أن هذا له علاقة بمحاولتنا دعم سلوك بعض systemjs بشكل أفضل ، ولكن يمكن استخدامه لفرض الاستيراد. إذا كنت تستخدم systemjs ، أو needjs ، أو أي أداة تحميل تسمح بإعادة تعيين معرفات الوحدة ، فيمكنك إنهاء الاستيراد القسري في !js أو علامة مشابهة وتعيينها بعيدًا مع محمل الوحدة. سينبعث TS حرف الاستيراد (ولا يحاول فحصه أو حله) ، ويمكن تعليم أداة التحميل الخاصة بك كيفية فهم الاستيراد.

يبدو أن الفريق يضطر بالفعل إلى إنشاء رمز حالة خاصة لهذه الأنواع من عمليات الاستيراد مثل في checker.ts:

// If we're compiling under --jsx react, the symbol 'React' should
// be marked as 'used' so we don't incorrectly elide its import. And if there
// is no 'React' symbol in scope, we should issue an error.
if (compilerOptions.jsx === JsxEmit.React) {
    let reactSym = resolveName(node.tagName, "React", SymbolFlags.Value, Diagnostics.Cannot_find_name_0, "React");
    if (reactSym) {
        getSymbolLinks(reactSym).referenced = true;
    }
}

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

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

في بقية الحالات ، يبدو أنه من التافه جدًا أن يكتشف المترجم أن الوحدة النمطية المستوردة لن يكون لها ناتج وقت تشغيل وتتجاهل تلك الواردات فقط.

من منظور DRY ، تركني هذا الاقتراح أتمنى أن يكون لديّ ناقل للترجمة لكتابة هذا الرمز المكرر من أجلي.

import * as React from "react"; // get the types
import "react";  // just for side effect

بالطريقة التي أراها ، يجب أن يكون اختيار الملف _imported_ ما إذا كان يحتاج إلى التحميل في وقت التشغيل (لأنه يعلم أن له آثارًا جانبية). لا ينبغي أن يقرر هذا الملف _loading_ (أي ، الملف الذي يحتوي على بيان الاستيراد) ، نظرًا لأنه ليس من شأن معرفة تفاصيل تنفيذ الملفات / الوحدات النمطية الأخرى.

على الأقل هذا سيعمل بشكل جيد من منظور angularjs ، حيث "يعرف" الملف الذي يحدد التوجيهات والخدمات أنه يجب تحميله في وقت التشغيل إذا تمت الإشارة إليه ، لذلك يجب على المترجم ألا يتجاهله. نوع من التلميح في ملف إلى المترجم المنسوخ إلى "not elide" قد يصلح هذا IMO. لكن ربما أغفل بعض حالات الاستخدام هنا.

-JM

xmodule.ts:

console.log('ive been imported');
export class X {
}
import {X} from "xmodule"; // get the types
import "xmodule";  // just for side effect

إذا كان xmodule يحتوي على عبارات ، .eg عبارة console.log ، فهي بحكم التعريف ليست مجرد كومة من الإعلانات. لا ينبغي أن تكون مسؤولية وحدة الاستيراد هي إصدار بيانات تستخدم xmodule لكي يتم اعتبار xmodule أكثر من مجرد سلسلة من إعلانات النوع.

تضمين التغريدة

لقد ذكرت استخدام ضجة لفرض الاستيراد. هذا هو المفضل لسيناريو بلدي. كيف يمكنني استخدامه بالرغم من ذلك؟ جربت كل ما يلي:

!import {Service} from './service';
import! {Service} from './service';
import {!Service} from './service';
import {Service!} from './service';
import {Service} from '!./service';
import {Service} from './service!';
import {Service} from !'./service';
import {Service} from './service'!;

كان في السلسلة - لكنني أعتقد أنه تمت إزالة السلوك مؤخرًا عندما تم تقديم تعيينات المسار.

أنا أستخدم مكتبة ، مثل رد فعل ، لاستيراد غلاف العقدة - h (في رد فعل يتفاعل () إذا لم أكن مخطئًا) ، لذلك أستورد مثل هذا:

import { h, Component } from "preact";

ثم ، بالطبع ، ليس لدي h في وقت التشغيل. لأنه لماذا سيكون هناك؟ أيضًا ، باستخدام مع الاحتفاظ بـ jsx ، لذلك فإن TypeScript لا يتعلق بـ h حقًا ، ولكن بابل يعرف ذلك.

إذن ، ما تبقى ، باستخدام مرجع مثل h ؛ بعد الاستيراد ، نعم؟

بالنسبة إلى h (أو أي مصنع jsx مخصص آخر) ، استخدم --jsxFactory للسماح للمجمع بمعرفة أن هذا هو المصنع الذي تستخدمه في وقت التشغيل. على سبيل المثال ، --jsxFactory h .

لا يتطلب هذا typescript@next في الوقت الحالي ، يجب أن يكون متاحًا في TypeScript 2.1.2.

mhegazy بالنسبة للمشاريع التي لديها نوعان من مستهلكي JSX (مثل رد فعل و snabbdom) فهذا غير مقبول.

أنا أعمل على مشروع يستخدم رد فعل لعرض واجهة مستخدم الويب و Dom الظاهري المخصص الذي نفذه بأنفسنا لتقديم كائنات webgl. وهي تصل إلى حالة الزاوية ، حيث نحتاج إلى نوعين مختلفين من التعليقات التوضيحية @jsx لنفس المشروع.

الآن أنا مضطر لتصدير h كمتغير عالمي ... إنه قبيح.

قم بتضميني في قائمة المطورين الذين يحتاجون / يريدون استيراد بطانة واحدة تقوم بذلك. سطرين من المصدر لإنجازه هو ما نحاول إزالته ، خاصة عندما نريد استيراد العديد من الوحدات على التوالي. أعتقد أن أفضل ما بدا لي حتى الآن هو كلمة أساسية / بناء جملة لفرض الاستيراد. شكرا مرة أخرى يا شباب!

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