Un ghid cuprinzător pentru „Module System” în TypeScript (cu exemple)
On octombrie 16, 2021 by adminModule Standard
EcmaScript a standardizat modul în care ar trebui să importăm modulele în JavaScript și acest standard se învârte în jurul a două cuvinte cheie, import
și export
. Pe măsură ce sistemul de module din JavaScript devine popular, în fiecare an apar noi modificări la acest standard.
În acest tutorial, vom analiza semantica sistemului de module din TypeScript (care seamănă în mare parte cu standardul EcmaScript) și modul în care funcționează cuvintele cheie import
și export
.
Exporturi cu nume
Cuvântul cheie export
face ca o valoare (variabilă) definită într-un fișier să fie disponibilă pentru a fi importată în alte fișiere de module. Atunci când un modul este importat într-un alt fișier de module utilizând cuvântul cheie import
, fișierul importator poate specifica valorile pe care dorește să le acceseze din modulul importat.
// program.ts
import { A } from 'path/to/values';console.log( A ); // "Apple"
În exemplul de mai sus, importăm values.ts
în fișierul program.ts
și extragem membrul A
exportat. Aceasta înseamnă că values.ts
trebuie să exporte valoarea A
sub o anumită formă. Există mai multe moduri de a expune A
.
// values.ts
var A = "Apple"; // can also use `let` or `const`
class B {}
function C(){}
enum D{}export { A, B, C, D };
Puteți exporta orice valoare TypeScript accesibilă cu un identificator (nume) valid. Aici, în acest exemplu, exportăm o variabilă A
(ar putea fi și o constantă), clasa B
, și așa mai departe. Folosind sintaxa export {}
, puteți exporta oricâte valori doriți și oricine le poate importa folosind sintaxa import { A, B }
. Nu este necesar să importați toate valorile exportate.
Există un alt mod de a exporta o valoare acolo unde a fost declarată.
// values.ts
export const A = { name: "Apple" };
export class B {}
export function C(){}
export enum D{}
În exemplul de mai sus, am exportat toate valorile acolo unde au fost declarate. De asemenea, nu este nevoie să inițializați valoarea, puteți face acest lucru mai târziu în josul fișierului. Acesta este un mod mult mai frumos în comparație cu cel anterior.
În ambele cazuri, toți membrii exportați sunt accesibili în cadrul aceluiași fișier, dacă aveți nevoie să îi folosiți. Faptul de a avea cuvântul cheie export
pe o valoare nu schimbă comportamentul acesteia în cadrul fișierului modulului.
Default Export
Până acum am exportat valori care pot fi importate doar prin furnizarea numelui membrilor de export, cum ar fi import { A } from 'path/to/values'
unde A
aici este un membru de export al lui values.ts
. Acestea se numesc exporturi cu nume.
De asemenea, vi se permite să exportați o singură valoare care poate fi importată fără a preciza un nume. Această valoare trebuie să fie identificată cu cuvântul cheie default
împreună cu cuvântul cheie export
.
// values.ts
var A = "Apple"; // can also use `let` or `const`
class A {}
function A(){}
enum A{}export default A;
Se permite exportarea unei singure valori ca export implicit, prin urmare nu aveți expresia export default {...}
cu care să lucrați. Spre deosebire de exporturile cu nume, o valoare nu poate fi exportată ca valoare implicită cu o declarație de variabilă (sau constantă), cu excepția unei declarații function
și 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
Cu toate acestea, puteți exporta o valoare direct ca export implicit. Aceasta înseamnă că orice expresie JavaScript poate fi exportată ca valoare de export implicită.
// values.ts
export default "Hello"; // string
export default {}; // object
export default () => undefined; // function
export default function(){}; // function
export default class{}; // class
Din moment ce exportului implicit îi lipsește un nume de export, putem furniza orice nume pentru acesta în timpul importului. Puteți avea exporturi cu nume și un export implicit în același fișier de modul. În mod similar, puteți importa valorile exportului implicit și ale exportului numit într-o singură declarație import
, așa cum se arată mai jos.
import Apple, { B, C } from 'path/to/values';
În exemplul de mai sus, Apple
este numele pe care l-am folosit pentru a colecta exportul implicit din values.ts
. Puteți renunța la expresia { B, C }
sau la numele Apple
din declarația import
dacă nu aveți de gând să o utilizați.
💡 Ca și în cazul exporturilor cu nume, nu este obligatoriu să importați valoarea exportului implicit atunci când se utilizează declarația
import
. Dar,Apple
trebuie să vină înaintea exporturilor numite în semnătura declarațieiimport
.
Puteți utiliza, de asemenea, sintaxa as default
în semnătura export {}
pentru a exporta o valoare ca valoare implicită împreună cu alte exporturi numite. Acest lucru se numește aliasing și este explicat în secțiunea următoare.
// values.ts
var A = "Apple"; // can also use `let` or `const`
class B {}
function C(){}
enum D{}export { A as default, B, C, D };
💡 Motivul pentru care nu folosesc și nu recomand exportul
default
are de-a face cu experiența dezvoltatorului. După cum am învățat, puteți furniza orice nume pentru memebrul de export implicit al unui modul în declarațiaimport
. Dacă această valoare este importată în mai multe fișiere, o puteți referi cu orice nume la alegere, iar a avea nume diferite pentru același membru de export al aceluiași modul este un DX rău.
Import And Export Alias
În cazul exportului implicit, puteți referi valoarea cu orice nume la alegere în declarația import
. Cu toate acestea, nu este cazul exporturilor cu nume. Cu toate acestea, puteți utiliza cuvântul cheie as
pentru a face referire la o valoare de export numit cu numele ales de dumneavoastră.
// program.ts
import A, { B as Ball } from 'path/to/values';console.log( B ); // ❌ Error: Cannot find name 'B'.
console.log( Ball ); // ✅ legal
În exemplul de mai sus, importăm B
din values.ts
, dar aceasta a fost redenumită în Ball
. Prin urmare, în fișierul program.ts
, veți folosi Apple
în loc de B
. Atunci când se schimbă aliasul unui membru de export, numele original nu mai există în domeniul global, prin urmare B
nu va mai exista în fișierul program.ts
.
💡 Nu puteți schimba aliasul membrului de export implicit, deoarece puteți furniza deja orice nume la alegere, dar puteți folosi
import { default as defaultValue, }
.
De asemenea, vi se permite să apelați o valoare în timp ce exportați folosind cuvântul cheie 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 };
În exemplul de mai sus, am exportat variabila A
ca export implicit și funcția C
ca Cat
. Prin urmare, oricine importă aceste valori din fișierul values.ts
trebuie să utilizeze sintaxa de import implicit pentru A
și Cat
pentru valoarea C
.
Import All Named Exports
Puteți importa toate exporturile numite dintr-un fișier utilizând sintaxa * as
.
// program.ts
import Apple, * as values from 'path/to/values';console.log( values.B );
console.log( values.C );
console.log( values.D );
În acest caz, toate exporturile numite din values.ts
vor fi salvate sub values
care va fi un obiect în care keys
va fi numele membrilor de export, iar values
vor fi valorile exportate ale membrilor de export.
Reexporturi
O valoare importată poate fi reexportată în mod normal. Atunci când importați ceva, aveți o referință la valoarea de import și puteți utiliza aceeași valoare în sintaxa export
. Nu este nimic în neregulă cu acest lucru.
// lib.ts
import A, { B, C as Cat, D } from 'path/to/values';export { D as default, A, B, Cat as C, D };
În exemplul de mai sus, ați importat câteva valori din values.ts
în interiorul lib.ts
și le-ați exportat în funcție de preferințele dumneavoastră. Acest lucru este grozav dacă doriți să folosiți aceste importuri în lib.ts
, precum și să exportați unele dintre ele dacă un alt fișier are nevoie de ele atunci când le importă din lib.ts
.
Cu toate acestea, avem, de asemenea, instrucțiunea export ... from
pentru a exporta valori dintr-un fișier fără a fi nevoie să le importați mai întâi. Acest lucru este excelent atunci când doriți să păstrați un singur punct de intrare pentru toate importurile din modulul dumneavoastră.
// 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 };
În exemplul de mai sus, exportăm o parte din membrii de export din values-1.ts
și values-2.ts
din fișierul lib.ts
(cu excepția exportului implicit). Putem, de asemenea, să folosim aliasing în sintaxa export ... from
.
Sintaxa de reexport nu afectează fișierul curent, prin urmare, puteți avea exporturile obișnuite în fișier, la fel ca în exemplul de mai sus. Spre deosebire de cuvântul cheie export
, sintaxa export ... from
nu permite accesul la membrii reexportați. Prin urmare, nu veți putea accesa P
sau Orange
în fișierul 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'.
Puteți exporta toate exporturile numite dintr-un fișier utilizând sintaxa export * from
, deoarece aveți posibilitatea de a le redenumi în timpul exportului utilizând export * as ... from
.
// lib.ts
export * from 'path/to/values-1';
export * as values2 from 'path/to/other/values-2';
Din exemplul de mai sus, dacă values-1.ts
exportă P
și Q
, atunci oricine poate importa P
și Q
din lib.ts
. Cu toate acestea, toate exporturile cu nume din values-2.ts
sunt reexportate ca values2
export cu nume din lib.ts
, prin urmare, trebuie să le importați folosind următoarea sintaxă:
// program.ts
import { P, Q, values2 } from 'path/to/lib';
Nu puteți accesa exportul implicit folosind sintaxa export ... from
în mod normal. Dar puteți exporta exportul implicit utilizând cuvântul cheie default
.
// lib.ts
export { default } from 'path/to/values-1';
export { default as Apple } from 'path/to/values-2';
În exemplul de mai sus, exportul implicit al lui lib.ts
este valoarea de export implicită a lui values-2.ts
. Valoarea de export implicită a lui values-2
va fi exportată din lib.ts
ca Apple
numit export.
Import pentru efect secundar
Vă imaginați că importați un fișier fără să specificați membrii exportați?
import 'path/to/action';
În exemplul de mai sus, importăm action.ts
, dar am specificat toți membrii exportați de action.ts
. Aceasta este o sintaxă validă, dar este utilizată pentru a produce un rezultat foarte diferit.
Când importați un fișier utilizând cuvântul cheie import
, acesta este mai întâi executat și apoi toți membrii exportați sunt disponibili pentru import. Prin urmare, în exemplul de mai jos, un fișier care importă PI
ar obține 3.14
ca număr floating-point
.
export const PI = parseFloat( "3.14" ); // 3.14
Să urmați aceeași logică, dacă doriți să creați un efect secundar prin importarea unui fișier, atunci puteți face acest lucru în totalitate. Astfel, de exemplu, dacă există un fișier care inițializează unele variabile globale, îl puteți importa fără să specificați membrii exportați ai acelui fișier (de asemenea, ar putea să nu exporte niciunul în primul rând).
Compilatorul TypeScript poate crea un fișier pachet JavaScript (.js
) prin compilarea a două sau mai multe fișiere .ts
împreună. Acest lucru se face în mod normal prin furnizarea unui fișier TypeScript de intrare și apoi prin parcurgerea arborelui de dependențe al acestuia.
Un arbore de dependențe se construiește prin examinarea tuturor declarațiilor import
(dependențe) ale fișierului de intrare și urmărind dependențele acestor fișiere importate. Dacă doriți să includeți un fișier al cărui cod ar putea crea unele efecte secundare în timpul execuției, atunci ar trebui să importați fișierul respectiv fără a specifica membrii exportați în sintaxa import
. Acest lucru se poate face în fișierul de intrare sau în interiorul oricărui fișier care se află în interiorul arborelui de dependențe.
.
Lasă un răspuns