2012-10-22 19 views
6

Ho un numero di plug-in jQuery che vorrei caricare utilizzando il pattern AMD in TypeScript. Ad esempio, potrei avere questa struttura:Caricamento asincrono di dichiarazioni TypeScript senza esportazioni

/lib/jquery.myplugin.js 
/app.ts 

Il plugin si estende semplicemente jQuery. Non fornisce nuove funzioni o variabili di primo livello. Un esempio potrebbe essere:

// jquery.myplugin.js 
jQuery.fn.myExample = function() { ... } 

Il file jquery.myplugin.d.ts corrispondente assomiglia:

interface JQuery { 
    myExample(); 
} 

Così ora in app.ts posso chiamare qualcosa come $('#my-element').myExample(). Si noti che questo presuppone che io abbia già caricato le dichiarazioni jquery.d.ts di Microsoft.

La mia domanda è: come caricare questa libreria in modo asincrono e sfruttare la digitazione statica TypeScripts? Potrei usare in questo modo:

/// <reference path="lib/jquery.myplugin.d.ts"/> 

ma che mi richiede di aggiungere un tag <script> al mio HTML, e la biblioteca non è caricato in modo asincrono. Voglio dattiloscritto per generare questo codice:

define(["require", "exports", "lib/jquery.myplugin"], function (require, exports, __jquery.myplugin__) { 
    ... 
    // Use my plugin 
    $('#my-element').myExample(); 
} 

Tuttavia, poiché non ci sono esportazioni nei .d.ts il file non posso scrivere import myplugin = module('lib/jquery.myplugin').

Il più vicino che ho ottenuto è di creare un jquery.myplugin.d.ts che fa riferimento a un altro file ts con la dichiarazione dell'interfaccia e include almeno un'esportazione. Tuttavia non c'è nulla da esportare in questa libreria, e per ottenere l'output desiderato non devo solo aggiungere un'esportazione, ma devo chiamarlo.

Aggiornamento: Ho aperto un work item per questo su typescript.codeplex.com

+0

mia soluzione attuale è quella di chiamare manualmente 'require ([...],() => {...}) 'nel mio codice TypeScript, che genera una chiamata richiesta nidificata. Lontano dall'ideale, ma funziona. – dcstraw

risposta

3

Il dattiloscritto non importa i moduli a meno che non esportino qualcosa e a meno che non utilizzi direttamente ciò che ha esportato, ma queste cose non sono vere per cose come i plugin JQuery che aggiungono semplicemente nuovi metodi a $. La soluzione è usare il flag amd-dependency come documentato here.

Aggiungi una linea come questa nella parte superiore del file:

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

questo costringerà tipografico per elencare nel define invocazione nella Javascript compilato. Avrete anche bisogno di creare un percorso e lo spessore per il vostro plugin nella vostra require.config, in questo modo:

require.config({ 
    paths: { 
    jquery: "external/jquery-2.1.1", 
    jgrowl: "external/jquery.jgrowl-1.4.0.min", 
    }, 
    shim: { 
    'jgrowl': { deps: ['jquery'] }, 
    } 
}); 
+0

Eccellente, grazie molte. Non credo che questa caratteristica sia esistita quando ho posto la domanda. Questo sembra esattamente quello che stavo cercando. – dcstraw

4

una specie di hack, ma qui è l'unico modo che conosco attualmente.

myplugin.d.ts: estende l'interfaccia JQueryStatic per includere IntelliSense per la funzionalità di myplugin

/// <reference path="../dep/jquery/jquery.d.ts" /> 

interface JQueryStatic { 
    myFunc(): string; 
} 

myplugin.ts: un file fittizio il cui unico scopo è quello di avere dattiloscritto generare una definizione del modulo AMD .

var test: number = 1; 

consumer.ts:

/// <reference path="myplugin.d.ts" /> 

import myplugin = module('myplugin'); 

// without this typescript knows you aren't actually using the module 
// and won't create the define block including your plugin 
var workaround = myplugin.test; 

$.myFunc(); 

consumer.js: generati con tsc -c --module amd consumer.ts

define(["require", "exports", 'myplugin'], function(require, exports, __myplugin__) { 
    /// <reference path="myplugin.d.ts" /> 
    var myplugin = __myplugin__; 

    // without this typescript knows you aren't actually using the module 
    // and won't create the define block including your plugin 
    var workaround = myplugin.test; 
    $.myFunc(); 
}) 

Nota che myplugin.d.ts tirerà intellisense a entrambe le definizioni di jQuery e plugin. È stato necessario creare sia un file myplugin.d.ts che un file myplugin.ts perché non so come (se possibile) esportare qualcosa mentre estendo contemporaneamente un'interfaccia esistente nello stesso file senza errori.

+0

Sembra che dovresti anche definire un percorso nella configurazione requirejs (o qualunque caricatore AMD che stai usando) che associa 'myplugin' al percorso del plugin, corretto? Altrimenti, se metti myplugin.d.ts nella stessa posizione del plugin, il file js compilato sovrascriverà la tua libreria di plugin. – dcstraw

+0

Solo se è stato eseguito il compilatore con il flag di definizione e non è stata specificata una directory di output alternativa. Per impostazione predefinita, myplugin.js verrà visualizzato. – ryan

+0

Sto dicendo che myplugin.js è probabilmente il nome della tua libreria in questo caso. Nel mio esempio avrei importato "lib/jquery.myplugin". Quindi, senza aliasing del nome della dipendenza, il tuo file JavaScript generato sovrascriverà la tua libreria. – dcstraw

1

Nella parte inferiore del file che l'interfaccia è definita all'interno si può mettere:

export var JQuery: JQueryStatic; 

che renderà l'intellisense per JQuery visualizzato su qualsiasi file caricato utilizzando import module.

Se il file viene caricato in modo asincrono e si sta impostando JQuery ad un'altra variabile (cioè myJQuery) è possibile dichiarare che il file è già stato caricato da un certo punto, per esempio, se avete la file nel ///<reference path=...> si dovrebbe essere in grado di utilizzare:

declare var myJQuery: JQuery; 

per rendere il vostro myJQuery di tipo JQuery.

Un altro trucco è quello di inserire l'interfaccia direttamente nella zona in cui il codice viene caricata in modo asincrono:

interface JQueryStatic { 
    myFunc(): string; 
} 

Se non ti dispiace la modifica dei file tuoi JQuery.d.ts, è possibile aggiungere la funzione alle interfacce definite in là.

correlati al tuo esempio, si dovrebbe essere in grado di fare qualcosa di simile:

declare var __jquery : JQueryStatic; 

Nella parte superiore del vostro richiamata definire; e a condizione di aver esteso l'interfaccia per JQueryStatic e averlo incluso utilizzando ///<reference path=...> il markup dovrebbe funzionare come desiderato.

+0

Non ho usato AMD da solo, ma spero che questo aiuti! – Griffork

+0

La dichiarazione delle variabili globali funziona bene per le librerie che si caricano attraverso altri mezzi, es. un tag script nel tuo HTML. Il vantaggio del pattern AMD è che ti consente di dichiarare la tua dipendenza e di caricarla secondo necessità o in bundle al momento della compilazione, e il tuo spazio dei nomi globale non deve essere inquinato. In particolare, ciò che non è ben supportato in TypeScript per le librerie che non hanno esportazioni di livello superiore. – dcstraw

+0

Mi dispiace, ho pensato che il pattern AMD funzionasse con uno stile di callback? In tal caso, non sarebbe possibile dichiarare una variabile con l'interfaccia JQuery nel callback? Quindi si visualizzerebbe per intellisense solo all'interno del callback e non nel resto del file. – Griffork

Problemi correlati