A TypeScript programozási nyelv

Alprogramok, modulok

Alprogramok

Alprogramok szintaxisa hasonló az ActionScript-beli alprogramokéval. Minden alprogram függvényként van deklarálva. Ha eljárást szeretnénk, akkor a függvény visszatérési értékének void-nak kell lennie.
Minden alprogrambeli formális paraméternek van valamilyen típusa. Ha nem adjuk meg explicite, akkor azok automatikusan any típusúak lesznek. Formális paraméterek neve után kettősponttal elválasztva kell megadni a típust. A 9.0-s verziótól az alprogramok végén nem megengedett a pontosvessző használata.

function f(a): void { } //(a: any) => void típusú f függvény

Függvényparamétereknek alapértelmezett értékeket is lehet adni. Ezek az értékek futásidőben értékelődnek ki, ennek hatására bármilyen kifejezést értékül lehet adni.

function sqr(x: number = Math.sin(Math.PI)) { return x * x; }

Továbbá lehetőség van változó paraméterszámú függvények deklarálására is. Ekkor az függvény törzsében a paraméterekre, mint tömbökre lehet hivatkozni és a formális paraméternek kötelezően tömb típusúnak kell lennie.

function printf(...str: string[]) { // ... } printf(); //paraméter nélkül hívjuk. Ilyenkor str === [] printf("Hello"); //egy paraméterrel hívjuk printf("Hello", "World", "!");

Nincs lehetőség a nyelvben a függvények túlterhelésére.

A 9.0-s verziótól az index függvényeknek meg kell adni a típusát.

interface a1 { [n: number]; //<-- működött 0.8.x-s verzióban, 0.9-től hiba } interface a1 { [n: number]: string; //<-- helyesen specifikálja a típust, minden verzióban jól működik }

Modulok

Javascript-től eltérően a nyelv támogatja a modulok (module használatát is, amik lényegében objektumok. Lényegében a modulok deklarációk és programokódokat összefoglaló singleton példányoknak felelnek meg. Bármit tárolhatunk bennük (függvények, osztályok, interfészek, változók stb.). A modulok (úgymint a névterek más nyelvekben) egymásba ágyazhatóak, de osztályokba, illetve interfészekbe nem helyezhetjük őket.
A modulban tárolt objektumok (függvények, osztályok, stb.) alapértelmezetten rejtve vannak a külső használók elől, ezért ha kívülről is használni szeretnénk őket, akkor mindet export kulcsszóval kell megjelölni.
TypeScript két csoportba foglalja modulokat: internal modules és external modules. Az előbbi lokális vagy exportált tagja egy másik modulnak (ami lehet globális vagy egy external modul). Az utóbbinál az egész fájlt egy modulnak tekinthetjük.
A 9.0-s verziótól nem hozható létre típus a module kulcsszóval, csak névterek és változók.

module A.B.C { //egymásba ágyazott modulok //ekvivalens azzal, mintha az írnánk, hogy: //module A { // export module B { // export module C { // } // } //} function greeting() { //a modulon kívülről nem lehet elérni return "Hello World"; } export function sayHello() { //mivel megjelöltük export kulcsszóval, ezért a modulon kívülről is lehet használni console.log(greeting()); } export var PI = 3.14; //nemcsak függvényeket, hanem változókat is lehet tárolni a modulokban. }

Belső modulok

A belső modul deklarációk és kifejezések nevesített tárolója. Egy belső modul egyben reprezentál egy névteret és egy singleton modul példányt. A névtér tartalmazhat nevesített típusokat és más névtereket, a singleton modul példány pedig tulajdonságokat tartalmaz a module exportált tagjai számára. A belső modul törzse egy olyan függvénynek felel meg, ami egyszer fut le.

Modul deklaráció

Egy belső modul deklaráció deklarál egy névtér nevet, és abban az esetben, ha ez egy példányosítható modul, akkor az adattag nevét a tartalmazó modulban.

ModuleDeclaration: module IdentifierPath { ModuleBody } IdentifierPath: Identifier IdentifierPath . Identifier

A belső modulok lehetnek példányosíthatóak és nem-példányosíthatóak. A nem-példányosítható belső modulok csak interface típusokat é más nem példányosítható típusokat tartalmaznak. A példányosítható modul minden más olyan belső modul, ami nem felel meg ennek a definíciónak. Intuitív szempontból, egy példányosítható modul az, amelyre egy modul objektum példány jön létre, míg a nem-példányosítható modul az, amelyre nem generálódik kód. Ha egy modul azonosítóra, mint modul névre hivatkozunk, akkor az a tároló modult és a típus neveket jelenti, ha pedig egy elsődleges kifejezésként hivatkozunk rá, akkor az egy singleton modulpéldány lesz. Mint például:

module M { export interface P { x: number; y: number; } export var a = 1; } var p: M.P; // modul névként használva var m = M; // elsődleges kifejezésként használva var x1 = M.a; // elsődleges kifejezésként használva var x2 = m.a; // ugyan az, mint az M.a var q: m.P; // hiba

Ha fent elsődleges kifejezésként használjuk az „M”-et, akkor az egy objektum példány egyetlen „a” taggal, ha viszont modul névként használjuk, akkor egy tároló lesz egyetlen típus taggal, a „P”-vel. A példa utolsó sora hibás, hiszen az „m” egy változó, ami nem hivatkozhat egy típusnévre. Ha az „M” deklarációjából kihagyjuk az exportált „a” változót, akkor az „M” egy nem-példányosítható modul és hibát eredményez, ha elsődleges kifejezésként szeretnénk rá hivatkozni. Egy belső modul, ami meghatároz egy azonosító útvonalat egynél több azonosítóval megegyezik egy sor beágyazott egyetlen azonosítójú belső modullal, ahol a legkülső kivételével az összes automatikusan exportálásra kerül. Mint például:

module A.B.C { export var x = 1; } module A { export module B { export module C { export var x = 1; } } }
Export deklarációk

Az export deklaráció egy kívülről elérhető modul tagot deklarál. Az export deklaráció egy szokásos deklaráció, amely elé az „export” kulcsszót írjuk. Az exportált osztály, interface és felsoroló típusok típus névként elérhetők M.N alakban, ahol az M egy hivatkozás a tartalmazó modulra, az N pedig az exportált típus neve.

Az exportált osztályok elérhetőek modul névként is, M.N formában, ahol az „M” a tartalmazó modulra történő hivatkozás, az „N” pedig az exportált modul.

Az exportált változó, osztály függvény, felsoroló és modul deklarációk tulajdonságokká vállnak a modul példányra nézve és közösen határozzák meg a modul példánytípusát. Ennek a névtelen típusnak a következő tagjai vannak:

Egy exportált típus függ nevesített típusok esetlegesen üres halmazától. Ezeknek a nevesített típusoknak legalább annyira elérhetőnek kell lenniük, mint az exportált tagnak, máskülönben hiba történik. A nevesített típusok, amelyektől egy tag függ, azok a nevesített típusok, amelyek előfordulnak a kapcsolattól közvetlenül függő tranzitív lezártban, a következőképpen definiálva:

Azt mondjuk, hogy egy „T” nevesített típus, amely rendelkezik egy „R” gyökér modullal, legalább annyira elérhető, mint az „M” tag, ha

Például: interface A { x: string; } module M { export interface B { x: A; } export interface C { x: B; } export function foo(c: C) { … } }

A „foo” függvény függ az „A”, „B”, „C” nevesített típusoktól. Annak érdekében, hogy a „foo”-t tudjuk exportálni, a „B”-t és a „C”-t is exportálni kell, mert különben nem lennének annyira elérhetőek, mint a „foo”. Az „A” interface már legalább annyira elérhető, mint a „foo”, mivel az a „foo” moduljának szülő moduljában deklarálásra került.

Import deklarációk

Az import deklarációkat arra használjuk, hogy aliasokat hozzunk létre, amelyekre a belső modulok hivatkozhatnak.

ImportDeclaration: import Identifier = ModuleName ;

Egy import deklaráció bevezet egy lokális azonosítót, ami egy adott modulra hivatkozik. A lokális azonosító maga is modulnak minősül, és ennek megfelelően is viselkedik. Egy import modulban deklarált modul azonosítót nem lehet exportálni.

Deklarációk egyesítése

A belső modulok nyílt végűek és egy belső modul deklaráció a közös gyökérre nézve ugyanúgy képzett névvel hozzáadódik egy egyszerű modulhoz. Mint például a következő két deklarációja egy modulnak, melyek különböző forrásfájlban találhatóak:

Fájl a.ts: module outer { var local = 1; // nem exportált lokális változó export var a = local; // outer.a export module inner { export var x = 10; // outer.inner.x } } Fájl b.ts: module outer { var local = 2; // nem exportált lokális változó export var b = local; // outer.b export module inner { export var y = 20; // outer.inner.y } }

Feltételezve, hogy a két forrásfájl ugyanannak a programnak a része, a két deklaráció globális modul lesz, mint a közös gyökerük és ez által hozzájárul a megegyező modul példányhoz, amely így néz ki:

{ a: number; b: number; inner: { x: number; y: number; }; }