Una guida completa al “Sistema dei moduli” in TypeScript (con esempi)
Il Ottobre 16, 2021 da adminStandard dei moduli
EcmaScript ha standardizzato come dovremmo importare i moduli in JavaScript e questo standard ruota intorno a due parole chiave, import
e export
. Siccome il sistema dei moduli in JavaScript sta diventando popolare, ci sono nuovi cambiamenti a questo standard ogni anno.
In questo tutorial, vedremo la semantica del sistema dei moduli in TypeScript (che per lo più assomiglia allo standard EcmaScript) e come funzionano le parole chiave import
e export
.
Esportazioni con nome
La parola chiave export
rende un valore (variabile) definito in un file disponibile per l’importazione in altri file modulo. Quando un modulo è importato in un altro file modulo usando la parola chiave import
, il file di importazione può specificare i valori a cui vuole accedere dal modulo importato.
// program.ts
import { A } from 'path/to/values';console.log( A ); // "Apple"
Nell’esempio precedente, stiamo importando values.ts
nel file program.ts
ed estraendo il membro esportato A
. Questo significa che values.ts
deve esportare il valore A
in qualche forma. Ci sono più modi per esporre A
.
// values.ts
var A = "Apple"; // can also use `let` or `const`
class B {}
function C(){}
enum D{}export { A, B, C, D };
È possibile esportare qualsiasi valore TypeScript accessibile con un identificatore valido (nome). Qui in questo esempio, stiamo esportando una variabile A
(potrebbe anche essere una costante), la classe B
e così via. Usando la sintassi export {}
, potete esportare tutti i valori che volete e chiunque può importarli usando la sintassi import { A, B }
. Non è necessario importare tutti i valori esportati.
C’è un altro modo per esportare un valore dove è stato dichiarato.
// values.ts
export const A = { name: "Apple" };
export class B {}
export function C(){}
export enum D{}
Nell’esempio precedente, abbiamo esportato tutti i valori dove sono stati dichiarati. Inoltre non c’è bisogno di inizializzare il valore, lo si può fare più avanti nel file. Questo è un modo molto più carino rispetto al precedente.
In entrambi i casi, tutti i tuoi membri esportati sono accessibili all’interno dello stesso file se hai bisogno di usarli. Avere la parola chiave export
su un valore non cambia il suo comportamento all’interno del file del modulo.
Default Export
Finora abbiamo esportato valori che possono essere importati solo fornendo il nome dei membri export come import { A } from 'path/to/values'
dove A
qui è un membro export di values.ts
. Queste sono chiamate esportazioni con nome.
Si può anche esportare un singolo valore che può essere importato senza specificare un nome. Questo valore dovrebbe essere identificato con la parola chiave default
insieme alla parola chiave export
.
// values.ts
var A = "Apple"; // can also use `let` or `const`
class A {}
function A(){}
enum A{}export default A;
Solo un singolo valore è permesso di essere esportato come esportazione predefinita, quindi non hai export default {...}
espressione con cui lavorare. A differenza delle esportazioni con nome, un valore non può essere esportato come predefinito con una dichiarazione di variabile (o costante), ad eccezione di una dichiarazione function
e class
.
// values.ts
export default var A = "Apple"; // ❌ invalid syntax
export default enum D{} // ❌ illegal: not a function or class
export default class B {} // ✅ legal
export default function C(){} // ✅ legal
Tuttavia, è possibile esportare un valore direttamente come esportazione predefinita. Questo significa che qualsiasi espressione JavaScript può essere esportata come valore di esportazione predefinito.
// values.ts
export default "Hello"; // string
export default {}; // object
export default () => undefined; // function
export default function(){}; // function
export default class{}; // class
Siccome l’esportazione predefinita manca di un nome di esportazione, possiamo fornire qualsiasi nome per essa durante l’importazione. È possibile avere esportazioni con nome e un’esportazione predefinita nello stesso file del modulo. Allo stesso modo, potete importare i valori di esportazione predefinita e di esportazione nominata in una singola dichiarazione import
come mostrato qui sotto.
import Apple, { B, C } from 'path/to/values';
Nell’esempio precedente, il Apple
è il nome che abbiamo usato per raccogliere l’esportazione predefinita dal values.ts
. Puoi eliminare l’espressione { B, C }
o il nome Apple
dalla dichiarazione import
se non hai intenzione di usarla.
💡 Come per le esportazioni con nome, non è obbligatorio importare il valore di esportazione predefinito quando si usa la dichiarazione
import
. Ma, ilApple
deve venire prima delle esportazioni nominate nella firma della dichiarazioneimport
.
Puoi anche usare la sintassi as default
nella firma export {}
per esportare un valore come default insieme ad altre esportazioni nominate. Questo si chiama aliasing ed è spiegato nella prossima sezione.
// values.ts
var A = "Apple"; // can also use `let` or `const`
class B {}
function C(){}
enum D{}export { A as default, B, C, D };
💡 La ragione per cui non uso e raccomando l’esportazione
default
ha a che fare con l’esperienza dello sviluppatore. Come abbiamo imparato, è possibile fornire qualsiasi nome per il memeber di esportazione predefinito di un modulo nella dichiarazioneimport
. Se questo valore è importato in più file, puoi riferirlo con qualsiasi nome di tua scelta e avere nomi diversi per lo stesso membro di esportazione dello stesso modulo è un cattivo DX.
Import And Export Alias
Nel caso dell’esportazione di default, puoi riferirti al valore con qualsiasi nome di tua scelta nella dichiarazione import
. Tuttavia, questo non è il caso delle esportazioni con nome. Tuttavia, puoi usare la parola chiave as
per fare riferimento a un valore di esportazione con nome con il nome che preferisci.
// program.ts
import A, { B as Ball } from 'path/to/values';console.log( B ); // ❌ Error: Cannot find name 'B'.
console.log( Ball ); // ✅ legal
Nell’esempio precedente, stiamo importando B
dal values.ts
ma è stato rinominato in Ball
. Quindi nel file program.ts
, userete Apple
invece di B
. Quando fai l’alias di un membro di esportazione, il nome originale non esiste più nell’ambito globale, quindi B
non esisterà più nel program.ts
.
💡 Non puoi fare l’alias del membro di esportazione predefinito poiché puoi già fornire qualsiasi nome di tua scelta ma puoi usare
import { default as defaultValue, }
.
Ti è anche permesso di dare un alias a un valore durante l’esportazione usando la parola chiave as
.
// values.ts
var A = "Apple"; // can also use `let` or `const`
class B {}
function C(){}
enum D{}export { A as default, B, C as Cat, D };
Nell’esempio precedente, abbiamo esportato la variabile A
come esportazione predefinita e la funzione C
come Cat
. Quindi chiunque importi questi valori dal file values.ts
deve usare la sintassi di importazione predefinita per A
e Cat
per il valore C
.
Importa tutte le esportazioni nominate
Puoi importare tutte le esportazioni nominate da un file usando la sintassi * as
.
// program.ts
import Apple, * as values from 'path/to/values';console.log( values.B );
console.log( values.C );
console.log( values.D );
Qui, tutte le esportazioni nominate da values.ts
saranno salvate sotto values
che sarà un oggetto dove keys
sarà il nome dei membri esportati e values
saranno i valori esportati dei membri esportati.
Riesporta
Un valore importato può essere riesportato in modo normale. Quando importi qualcosa, hai un riferimento al valore importato e puoi usare lo stesso valore nella sintassi export
. Non c’è niente di sbagliato in questo.
// lib.ts
import A, { B, C as Cat, D } from 'path/to/values';export { D as default, A, B, Cat as C, D };
Nell’esempio precedente, hai importato alcuni valori da values.ts
dentro lib.ts
ed esportato secondo le tue preferenze. Questo è ottimo se vuoi usare queste importazioni in lib.ts
così come esportarne alcune se un altro file ne ha bisogno quando importa da lib.ts
.
Tuttavia, abbiamo anche la dichiarazione export ... from
per esportare valori da un file senza doverli prima importare. Questo è ottimo quando vuoi mantenere un unico punto di ingresso per tutte le importazioni nel tuo modulo.
// lib.ts// re-exports
export { P as Paper, Q } from 'path/to/values-1';
export { N, O as Orange } from 'path/to/other/values-2';// default export
export default "hello";class B {}
function C(){}// named exports
export { B, C as Cat };
Nell’esempio precedente, stiamo esportando alcuni dei membri di esportazione di values-1.ts
e values-2.ts
dal file lib.ts
(tranne l’esportazione predefinita). Possiamo anche usare l’aliasing nella sintassi export ... from
.
La sintassi di riesportazione non influenza il file corrente, quindi puoi avere le tue esportazioni regolari nel file come mostrato sopra. A differenza della parola chiave export
, la sintassi export ... from
non permette l’accesso ai membri riesportati. Quindi non sarete in grado di accedere a P
o Orange
nel file lib.ts
.
// lib.ts
export { P as Paper, Q } from 'path/to/values-1';
export { N, O as Orange } from 'path/to/other/values-2';console.log( P ); // ❌ Error: Cannot find name 'P'.
console.log( Orange ); // ❌ Error: Cannot find name 'Orange'.
Potete esportare tutte le esportazioni nominate da un file usando la sintassi export * from
, poiché avete la possibilità di rinominarle durante l’esportazione usando export * as ... from
.
// lib.ts
export * from 'path/to/values-1';
export * as values2 from 'path/to/other/values-2';
Dall’esempio precedente, se values-1.ts
esporta P
e Q
, allora chiunque può importare P
e Q
da lib.ts
. Tuttavia, tutte le esportazioni nominate di values-2.ts
sono riesportate come values2
esportazione nominata di lib.ts
, quindi è necessario importarle usando la seguente sintassi.
// program.ts
import { P, Q, values2 } from 'path/to/lib';
Non è possibile accedere all’esportazione predefinita usando la sintassi export ... from
in modo normale. Ma puoi esportare l’esportazione predefinita usando la parola chiave default
.
// lib.ts
export { default } from 'path/to/values-1';
export { default as Apple } from 'path/to/values-2';
Nell’esempio precedente, l’esportazione predefinita di lib.ts
è il valore di esportazione predefinito di values-2.ts
. Il valore di esportazione predefinito di values-2
sarà esportato da lib.ts
come Apple
chiamato export.
Importa per effetto collaterale
Puoi immaginare di importare un file senza specificare i membri esportati?
import 'path/to/action';
Nell’esempio precedente, stiamo importando action.ts
ma abbiamo specificato tutti i membri esportati da action.ts
. Questa è una sintassi valida ma è usata per produrre un risultato molto diverso.
Quando si importa un file usando la parola chiave import
, viene prima eseguito e poi tutti i membri esportati sono disponibili per l’importazione. Quindi nell’esempio qui sotto, un file che importa PI
otterrebbe il 3.14
come numero floating-point
.
export const PI = parseFloat( "3.14" ); // 3.14
Seguendo la stessa logica, se volete creare un effetto collaterale importando un file, allora potete assolutamente farlo. Così, per esempio, se c’è un file che inizializza alcune variabili globali, potete importarlo senza specificare i membri esportati di quel file (potrebbe anche non esportarne nessuno).
Il compilatore TypeScript può creare un file bundle JavaScript (.js
) compilando insieme due o più file .ts
. Questo è normalmente fatto fornendo un file TypeScript di ingresso e poi passando attraverso il suo albero delle dipendenze.
Un albero delle dipendenze è costruito guardando tutte le import
dichiarazioni (dipendenze) del file di ingresso e seguendo le dipendenze di questi file importati. Se vuoi includere un file il cui codice potrebbe creare alcuni effetti collaterali in fase di esecuzione, allora dovresti importare quel file senza specificare i membri esportati nella sintassi import
. Questo può essere fatto nel file di ingresso o in qualsiasi file che si trova all’interno dell’albero delle dipendenze.
Lascia un commento