Kattava opas TypeScriptin ”moduulijärjestelmästä” (esimerkkien kera)
On 16 lokakuun, 2021 by adminModuulistandardi
EcmaScript on standardoinut, miten moduuleja pitäisi tuoda JavaScriptissä, ja tämä standardi pyörii kahden avainsanan, import
ja export
, ympärillä. Koska JavaScriptin moduulijärjestelmä on yleistymässä, tähän standardiin tulee joka vuosi uusia muutoksia.
Tässä opetusohjelmassa tarkastelemme TypeScriptin moduulijärjestelmän semantiikkaa (joka muistuttaa suurimmaksi osaksi EcmaScript-standardia) ja sitä, miten import
ja export
-avainsanat toimivat.
Nimetty vienti
Avainsana export
tekee tiedostossa määritellystä arvosta (muuttujasta) importoitavissa olevan tiedoston muihin moduulitiedostoihin. Kun moduuli tuodaan toiseen moduulitiedostoon import
-avainsanalla, tuova tiedosto voi määritellä ne arvot, joita se haluaa käyttää tuodusta moduulista.
// program.ts
import { A } from 'path/to/values';console.log( A ); // "Apple"
Yllä olevassa esimerkissä tuodaan values.ts
tiedostossa program.ts
ja poimitaan A
viety jäsen A
. Tämä tarkoittaa, että values.ts
:n on vietävä arvo A
jossakin muodossa. On olemassa useita tapoja paljastaa A
.
// values.ts
var A = "Apple"; // can also use `let` or `const`
class B {}
function C(){}
enum D{}export { A, B, C, D };
Voit viedä minkä tahansa käytettävissä olevan TypeScript-arvon, jolla on kelvollinen tunniste (nimi). Tässä esimerkissä viemme muuttujan A
(voisi olla myös vakio), luokan B
ja niin edelleen. Käyttämällä export {}
-syntaksia voit viedä niin monta arvoa kuin haluat ja kuka tahansa voi tuoda ne käyttämällä import { A, B }
-syntaksia. Kaikkia vietyjä arvoja ei tarvitse tuoda.
On olemassa toinenkin tapa viedä arvo sinne, missä se on ilmoitettu.
// values.ts
export const A = { name: "Apple" };
export class B {}
export function C(){}
export enum D{}
Yllä olevassa esimerkissä olemme vieneet kaikki arvot sinne, missä ne on ilmoitettu. Arvoa ei myöskään tarvitse alustaa, se voidaan tehdä myöhemmin tiedostossa. Tämä on paljon mukavampi tapa verrattuna edelliseen.
Kummassakin tapauksessa kaikki vientijäsenet ovat käytettävissä samassa tiedostossa, jos niitä tarvitsee käyttää. Se, että arvossa on export
-avainsana, ei muuta sen käyttäytymistä moduulitiedoston sisällä.
Default Export
Tähän mennessä olemme vieneet arvoja, jotka voidaan tuoda vain antamalla vientijäsenten nimet, kuten import { A } from 'path/to/values'
, jossa A
tässä on vientijäsen values.ts
. Näitä kutsutaan nimetyiksi vienteiksi.
Saat viedä myös yksittäisen arvon, joka voidaan tuoda ilman nimen antamista. Tämä arvo tulee yksilöidä default
-avainsanalla yhdessä export
-avainsanan kanssa.
// values.ts
var A = "Apple"; // can also use `let` or `const`
class A {}
function A(){}
enum A{}export default A;
Esimerkkisenä vientinä saa viedä vain yhden arvon, joten sinulla ei ole export default {...}
-lauseketta käytettäväksi. Toisin kuin nimettyä vientiä, arvoa ei voi viedä oletusvientinä muuttujan (tai vakion) ilmoituksella, paitsi function
– ja class
-ilmoituksella.
// 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
Voidaan kuitenkin viedä arvo suoraan oletusvientinä. Tämä tarkoittaa, että mikä tahansa JavaScript-lauseke voidaan viedä oletusvientiarvona.
// values.ts
export default "Hello"; // string
export default {}; // object
export default () => undefined; // function
export default function(){}; // function
export default class{}; // class
Koska oletusvientiarvolla ei ole vientinimeä, voimme antaa sille minkä tahansa nimen tuonnin yhteydessä. Samassa moduulitiedostossa voi olla nimetty vienti ja oletusvienti. Vastaavasti voit tuoda oletusvienti- ja nimetyn viennin arvot yhdellä import
-ilmoituksella, kuten alla on esitetty.
import Apple, { B, C } from 'path/to/values';
Yllä olevassa esimerkissä Apple
on nimi, jolla keräsimme oletusvientiä values.ts
:stä. Voit poistaa { B, C }
-lausekkeen tai Apple
-nimen import
-ilmoituksesta, jos et aio käyttää sitä.
💡 Nimettyjen vientien tapaan oletusvientiarvoa ei ole pakko tuoda, kun käytetään
import
-ilmoitusta. MuttaApple
:n on tultava ennen nimettyjä vientejäimport
-julistuksen allekirjoituksessa.
Voit myös käyttää as default
-syntaksia export {}
-allekirjoituksessa viedä arvon oletusarvona muiden nimettyjen vientien ohella. Tätä kutsutaan aliasiksi ja se selitetään seuraavassa kappaleessa.
// values.ts
var A = "Apple"; // can also use `let` or `const`
class B {}
function C(){}
enum D{}export { A as default, B, C, D };
💡 Syy, miksi en käytä ja suosittele
default
-vientiä, liittyy kehittäjien kokemukseen. Kuten opimme, voit antaaimport
-deklaraatiossa minkä tahansa nimen moduulin oletuksena olevalle export-jäsenelle. Jos tämä arvo tuodaan useisiin tiedostoihin, voit viitata siihen millä tahansa haluamallasi nimellä, ja eri nimien käyttäminen saman moduulin samalle export-jäsenelle on huono DX.
Import And Export Alias
Esimerkkiviennin tapauksessa voit viitata arvoon millä tahansa haluamallasi nimellä import
-julistuksessa. Näin ei kuitenkaan ole nimettyjen vientien kohdalla. Voit kuitenkin käyttää as
-avainsanaa viitata nimettyyn vientiarvoon haluamallasi nimellä.
// program.ts
import A, { B as Ball } from 'path/to/values';console.log( B ); // ❌ Error: Cannot find name 'B'.
console.log( Ball ); // ✅ legal
Yllä olevassa esimerkissä tuomme B
:n values.ts
:stä, mutta se on nimetty uudelleen Ball
:ksi. Näin ollen program.ts
-tiedostossa käytettäisiin B
:n sijasta Apple
. Kun aliasaat vientijäsenen, alkuperäistä nimeä ei enää ole globaalissa laajuudessa, joten B
ei ole enää program.ts
-tiedostossa.
💡 Et voi aliasata oletuksena olevaa vientijäsentä, koska voit jo antaa minkä tahansa haluamasi nimen, mutta voit käyttää
import { default as defaultValue, }
.
Vietäessäsi arvoa voit myös käyttää alias-nimeä käyttämällä as
-avainsanaa.
// 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 };
Yllä olevassa esimerkissä olemme vieneet muuttujan A
oletusvientinä ja funktion C
Cat
:nä. Näin ollen kaikkien, jotka tuovat nämä arvot values.ts
-tiedostosta, on käytettävä oletustuonti-syntaksia A
:lle ja :tä C
-arvolle.
Tuo kaikki nimetyt viennit
Voit tuoda kaikki nimetyt viennit tiedostosta käyttämällä * as
-syntaksia.
// program.ts
import Apple, * as values from 'path/to/values';console.log( values.B );
console.log( values.C );
console.log( values.D );
Tässä kaikki nimetyt viennit tiedostosta values.ts
tallennetaan alle values
, joka on objekti, jossa keys
on vientijäsenten nimi ja values
vientijäsenten vietyjä arvoja.
Uusiovienti
Tuodut arvot voidaan viedä uudelleen normaaliin tapaan. Kun tuot jotain, sinulla on viittaus tuontiarvoon ja voit käyttää samaa arvoa export
-syntaksissa. Siinä ei ole mitään väärää.
// lib.ts
import A, { B, C as Cat, D } from 'path/to/values';export { D as default, A, B, Cat as C, D };
Yllä olevassa esimerkissä olet tuonut muutamia arvoja values.ts
:sta lib.ts
:n sisälle ja vienyt ne haluamallasi tavalla. Tämä on hienoa, jos haluat käyttää näitä tuontitietoja lib.ts
:ssä sekä viedä osan niistä, jos jokin toinen tiedosto tarvitsee niitä tuodessaan niitä lib.ts
:stä.
Mutta meillä on myös export ... from
-lauseke, jolla voit viedä arvoja tiedostosta ilman, että niitä tarvitsee ensin tuoda. Tämä on hienoa silloin, kun haluat pitää moduulisi kaikki tuonnit yhdessä pisteessä.
// 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 };
Yllä olevassa esimerkissä viemme joitain values-1.ts
:n ja values-2.ts
:n export-jäseniä tiedostosta lib.ts
(lukuun ottamatta oletusvientiä). Voimme myös käyttää aliasingia export ... from
-syntaksissa.
Uusioviennin syntaksi ei vaikuta nykyiseen tiedostoon, joten voit pitää tavalliset vientitiedostot tiedostossa samoin kuin edellä on esitetty. Toisin kuin export
-avainsana, export ... from
-syntaksi ei salli pääsyä uudelleenvietyihin jäseniin. Näin ollen et voi käyttää P
– tai Orange
-jäseniä lib.ts
-tiedostossa.
// 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'.
Voit viedä kaikki nimetyt vientitiedostot tiedostosta käyttämällä export * from
-syntaksia, kunhan voit nimetä ne uudelleen viennin aikana käyttämällä export * as ... from
.
// lib.ts
export * from 'path/to/values-1';
export * as values2 from 'path/to/other/values-2';
Yllä olevasta esimerkistä, jos values-1.ts
vie P
ja Q
, kuka tahansa voi tuoda P
ja Q
lib.ts
:stä. Kaikki values-2.ts
:n nimetyt vientituotteet viedään kuitenkin uudelleen lib.ts
:n values2
nimettyinä vientituotteina, joten ne on tuotava seuraavalla syntaksilla:
// program.ts
import { P, Q, values2 } from 'path/to/lib';
Esimerkkivientiin ei pääse käsiksi käyttämällä export ... from
-syntaksia tavalliseen tapaan. Mutta voit viedä oletusvientiä käyttämällä default
-avainsanaa.
// lib.ts
export { default } from 'path/to/values-1';
export { default as Apple } from 'path/to/values-2';
Yllä olevassa esimerkissä lib.ts
:n oletusvienti on values-2.ts
:n oletusvientiarvo. Oletusvientiarvo values-2
viedään lib.ts
:stä Apple
-nimisenä vientinä.
Tuonti sivuvaikutuksen vuoksi
Voitko kuvitella tuovasi tiedoston määrittelemättä vietyjä jäseniä?
import 'path/to/action';
Ylläolevassa esimerkissä tuomme action.ts
:n, mutta olemme määritelleet kaikki action.ts
:n viemät jäsenet. Tämä on kelvollinen syntaksi, mutta sillä saadaan aikaan hyvin erilainen tulos.
Kun tuot tiedoston import
-avainsanalla, se suoritetaan ensin ja sen jälkeen kaikki vientijäsenet ovat käytettävissä tuontia varten. Näin ollen alla olevassa esimerkissä tiedosto, joka tuo PI
, saisi 3.14
:n floating-point
-numerona.
export const PI = parseFloat( "3.14" ); // 3.14
Saman logiikan mukaan, jos haluat luoda sivuvaikutuksen tuomalla tiedoston, voit täysin tehdä sen. Jos siis esimerkiksi on olemassa tiedosto, joka alustaa joitakin globaaleja muuttujia, voit tuoda sen määrittelemättä kyseisen tiedoston vietyjä jäseniä (se ei myöskään voisi alunperin viedä yhtään).
TypeScript-kääntäjä voi luoda JavaScript-pakettitiedoston (.js
) kääntämällä kaksi tai useampia .ts
-tiedostoja yhteen. Tämä tehdään yleensä antamalla TypeScript-sisääntulotiedosto ja käymällä sitten läpi sen riippuvuuspuu.
Riippuvuuspuu rakennetaan tarkastelemalla kaikkia import
sisääntulotiedoston import
-ilmoituksia (riippuvuuksia) ja seuraamalla näiden tuotujen tiedostojen riippuvuuksia. Jos haluat sisällyttää tiedoston, jonka koodi saattaa aiheuttaa joitain sivuvaikutuksia ajonaikana, tuo kyseinen tiedosto määrittelemättä vietäviä jäseniä import
-syntaksissa. Tämä voidaan tehdä sisääntulotiedostossa tai minkä tahansa tiedoston sisällä, joka on riippuvuuspuun sisällä.
Vastaa