Contents TypeScript ...... 2 Type Annotations ...... 4 Primitive Types ...... 5 Arrays ...... 5 Enumerations ...... 6 Bit Flag ...... 6 Type Assertions ...... 7 Operators ...... 7 Binary plus operator ...... 8 Not Operator ...... 8 And Operatörü ...... 9 Or operatörü ...... 9 Functions ...... 9 Optional Parameter ...... 10 Default Parameter ...... 10 Rest Parameter ...... 10 Overloads ...... 11 Specialized Overload Signarutes ...... 11 Arrow Functions ...... 12 Interfaces ...... 12 Classes ...... 13 Access Modifiers ...... 14 Properties and Methods ...... 14 Class Heritage ...... 15 Scope ...... 16 EcmaScript 5 Bind Function ...... 17 Type Information ...... 17 Modules...... 19 Internal Modules ...... 19 External Modules ...... 20 Learning the basics of ...... 20 03.Object oriented Concepts in TypeScript...... 21 Classes ...... 21 Inheritance SubClassing ...... 21 Implementing Interfaces ...... 23 Functions and overloads ...... 23 Generics ...... 24 04. Other Features of TypeScript ...... 25 Modules...... 25 Declaration Merging ...... 27 Mixins ...... 27

TypeScript https://www.apress.com/us/book/9781430267904 kitabından referans alınmıştır.

Typescript tarafından üretilmiş Apache 2.0 Lisansı altında yayınlanmış açık kaynak kodlu bir dildir. Javascript ile yazılmış kodları daha iyi bir şekilde yönetimini sağlar.

Visual Studio tarafından desteklendiği gibi, WebStorm, Eclipse, SublimeText, Intellij ve Ecmacs ve başka diğer geliştirici araçları tarafından desteklenmektedir. Bu kadar yaygın olmasının en büyük nedenlerinden biri de open source linsanslı olmasındandır.

Typescript javascriptin süperset’i olarak tanımlanır. Bu da ’in tüm özelliklerine ek olarak, kullanışlı özelliklerin eklendiği anlamına gelir. Kendi dilini javascript kodlarına çevirir. Javascript olduğu için hemen hemen her makinede çalışabilir (web browserlarında,web serverlerlarında, javascript api çalıştıran tüm uygulamalarda (örneğin de winjs veya firefox OS da Web API)

Typescript javascript ilişkilendirmelerine dayanılarak 3 kategoriye ayrılmıştır. İlk iki set javascripti standartlaştıran “Ecma-262 ECMAScript Specification” ile ilişkilidir.

Typescript EcmaScript 5 standartlarını temel alır ve ek olarak ECMAScript 6 daki kod organizasyonları için modülleri,class temelli nesne yönelimli yapıyı içerir. Bu yapıyı içeren Typescript 2012 Ekim ayında release olmuştur. 3. Kategori olarak ecmascript standartlarında olmayan generic ve tip notasyonları(annotation) gibi özellikler içerir. Tüm typescript özellikleri geçerli EcmaScript5’ e çevrilebilir.

Typescript language feature sources

Typescriptin javascript ile yakın ilişkisinden dolayı javascript ile yazılmış sayısız kütüphane ile çalışabilinir. Angular,Backbone,Durandal,jQuery,Knockout,Modernizr,PhoneGap,Prorotype,Raphael,Underscore... Javascript ile karşılaşılan genel problemler aşağıdaki gibidir

Prototypal inheritance

Equality and type juggling

Management of modules

Scope

Lack of types

Prototypal Inheritance

Prototype temelli programlama dili bir tür dinamik nesne yönelimli dildir. İlk olarak 1986 da Self adlı bir dilde kullanılmıştır. Prototype temellli programlama zor olduğu için typescript bunu class,module ve interface ekleyerek çözmüştür.

Equality and type juggling

Listing 1. Type juggling var num = 1; var str = ‘0’;

// result is ‘10’ not 1 var strTen = num + str;

// result is 20 var result = strTen * 2;

Management of Modules

Javascriptle çalışırken karşımıza gelen muhtemel problemler aşağıdaki gibi olabilir

-web sayfasına scripti eklemeyi unutmak

-scriptleri sayfaya yanlış sırada eklemek

-kullanılmayacak olan scripti fazladan eklemek

Bununla birlikte javascript dosyalarını minimize(minify) etmek için aşağıdaki problemlerle karşılaşabiliriz

-scriptleri birleştirirken yanlış sırada birleştirme

-tek satırlık yorumları çözümleyemeyen tool’lar

-birleştirilmiş ve minimize edilmiş kodları debug etme

Scope

C gibi dillerde süslü parantezler yeni bir context oluşturmak için kullanılır. Ancak javascriptte süslü parantez içerisinde tanımlanan bir değişkene dışardan erişmek mümkündür. Bunun için javascriptte let keyword’u kullanılır. Var yerine bu keyword ile tanımlanan değişken sadece scope içerinde düzenlenebilir olacaktır. function letTest() { let x = 1; if (true) { let x = 2; // different variable console.log(x); // 2 } console.log(x); // 1 }

Typescript scope sorunlarını derlemeden önce uyararak bizlere bildirir.

Lack of Types

Javascriptin bir diğer sorunu ise tiplerdir. Bir değişkene bir değeri atadıkdan sonra başka tipteki bir değeri atayabilirsiniz. String olarak atanmış bir değişkeni integer’a ,objeye hatta metoda bile atayabilirsiniz.

Javascript is valid typescript

Birkaç istisna dışında tüm javascript typescriptte geçerlidir. Javascript kodunuzu typescript dosyanın içerisine ekleyebilirsiniz. Ancak type script içerisinde geeçerli kod ile error-free kod arasında ince bir farklılık vardır, typescript kendisine uyuşmayan kısımlarda kullanıcıyı uyararak bilgilendirecektir.

Transfer edilen tüm javascript kodları geçerli bile olsa kullanıcıya hata veya uyarı şeklinde bilgilendirme gelebilir. Genel olarak bu sorun javascriptin dinamik tipte olmasından kaynaklıdır eğer bir değişkene atama yapıldıktan sonra başka bir tipe atama yapılırsa hata verecektir, ancak kodu derleyecektir.

Aşağıdaki kod örneği hata verecektir, ancak derlenebilir olacaktır. Derlemeye izin verilse bile bu uyarı veya hatalar kod sağlığı açısından göz ardı edilmemelidir. var radius = 4; var area = Math.PI * radius * radius; area=”Hi!”; Type Annotations Tip tanımlamaları genel olarak aşağıdaki gibidir. İleriki konularda detaylara girilecektir.

// primitive type annotation var name: string = 'Steve'; var heightInCentimeters: number = 182.88; var isActive: boolean = true;

// array type annotation var names: string[] = ['James', 'Nick', 'Rebecca', 'Lily'];

// function annotation with parameter type annotation and return type annotation var sayHello: (name: string) => string; // implementation of sayHello function sayHello = function (name: string) { return 'Hello ' + name; }; // object type annotation var person: { name: string; heightInCentimeters: number; }; // Implementation of a person object person = { name: 'Mark', heightInCentimeters: 183 };

interface Person { name: string; heightInCentimeters: number; } var person: Person = { name: 'Mark', heightInCentimeters: 183 } var b: any;//undefined b = "Hi";

enum ModalTypes { warning, danger, info } Primitive Types Eğer bir değişkene herhangi bir değer atanmamışsa değeri undefined olacaktır null değeri kasıtlı olarak değişkene verilen bir değerdir. Örneğin dizi içerisinde aranan bir öğenin bulunmaması durumunda null döndürülmesi gibi. void metodu ise metodun herhangi bir değer döndürmediği durumlar içindir. Arrays interface Monument { name: string; heightInMeters: number; }

// The array is typed using the Monument interface var monuments: Monument[] = []; // Each item added to the array is checked for type compatibility monuments.push({ name: 'Statue of Liberty', heightInMeters: 46 }); monuments.push({ name: 'Peter the Great', heightInMeters: 96 }); monuments.push({ name: 'Angel of the North', heightInMeters: 20 }); function compareMonumentHeights(a: Monument, b: Monument) { if (a.heightInMeters > b.heightInMeters) { return -1; } if (a.heightInMeters < b.heightInMeters) { return 1; } return 0; }

// The array.sort method expects a comparer that accepts two Monuments var monumentsOrderedByHeight = monuments.sort(compareMonumentHeights); // Get the first element from the array, which is the tallest var tallestMonument = monumentsOrderedByHeight[0]; console.log(tallestMonument.name); // Peter the Great

//çoklu sıralama comparer(a: PersonWord, b: PersonWord) { if (a.wordInfos.length == b.wordInfos.length) { if (a.word.key == b.word.key) { return 0; } return a.word.key > b.word.key ? 1 : -1; } return a.wordInfos.length > b.wordInfos.length ? 1 : -1; }

Monument her iki şekilde tanımlanabilir

// The array is typed using the Monument interface var monuments: Monument[] = []; var momuments :Array;

Enumerations enum VehicleType { PedalCycle, MotorCycle, Car, Van, Bus, Lorry } var type = VehicleType.Lorry; var typeName = VehicleType[type]; // 'Lorry' enum BoxSize { Small, Medium } //... enum BoxSize { Large = 2, XLarge, XXLarge } var boxSize: BoxSize = BoxSize.XXLarge; Bit Flag Birden fazla enum değerini içerebilir. Enum değerleri 2 ve üstü şeklinde değer alır. Bir değişkenin içerisinde igili enum değerlerinin bulunup bulunmadığı aşağıdaki gibi pratik bir şekilde çözülebilir. enum DiscFlags { None = 0, Drive = 1, Influence = 2, Steadiness = 4, Conscientiousness = 8 } // Using flags var personality = DiscFlags.Drive | DiscFlags.Conscientiousness; // Testing flags // true var hasD = (personality & DiscFlags.Drive) == DiscFlags.Drive; // false var hasI = (personality & DiscFlags.Influence) == DiscFlags.Influence; // false var hasS = (personality & DiscFlags.Steadiness) == DiscFlags.Steadiness; // true var hasC = (personality & DiscFlags.Conscientiousness) == DiscFlags.Conscientiousness; Type Assertions interface House { bedrooms: number; bathrooms: number; } interface Mansion { bedrooms: number; bathrooms: number; butlers: number; } var avenueRoad: House = { bedrooms: 11, bathrooms: 10 }; //Errors: Cannot convert House to Mansion var mansion: Mansion = avenueRoad; //Works var mansion: Mansion = avenueRoad; var mansion2: Mansion = { bedrooms: 1, bathrooms: 5, butlers: 10 }; var house: House = mansion2;

Forced type assertions var name: string = 'Avenue Road'; // Error: Cannot convert 'string' to 'number' var bedrooms: number = name; // Works var bedrooms: number = name; typeof (bedrooms);//string

Operators var counter = 0; do { ++counter; } while (counter < 10); alert(counter); // 10 enum Size { S, M, L, XL } var size = Size.S; ++size; console.log(Size[size]); // M var size = Size.XL; --size; console.log(Size[size]); // L var size = Size.XL; ++size; console.log(Size[size]); // undefined

Binary plus operator // 6: number var num = 5 + 1; // '51': string var str = 5 + '1';

Unary plus and minus operatör var str: string = '5'; // 5: number var num = +str; // -5: number var negative = -str; Not Operator var truthyString = 'Truthy string'; var falseyString: string; // False, it checks the string but inverts the truth var invertedTest = !truthyString; // True, the string is not undefined or empty var truthyTest = !!truthyString; // False, the string is empty var falseyTest = !!falseyString;

!! operatörü her türü boolean değere çebirebilir. Aşağıdaki durumlar dışında her türlü true döndürecektir.

-undefined

-null

-false:boolean

-‘’:string(empty string)

-0:number

-Nan(javascript not a number değeri)

-‘False’:string var myProperty; if (myProperty) {

// Reaching this location means that...

// myProperty is not null

// myProperty is not undefined

// myProperty is not boolean false

// myProperty is not an empty string // myProperty is not the number 0

// myProperty is not NaN

} And Operatörü // longhand if (console) { console.log('Console Available'); } // shorthand console && console.log('Console Available'); var player1 = 'Martin'; // player2 is only defined if player1 is defined var player2 = player1 && 'Dan'; // 'Dan' alert(player2); Or operatörü

// Empty strings are falsey var errorMessages = ''; // result is 'Saved OK' var result = errorMessages || 'Saved OK'; // Filled strings are truthy errorMessages = 'Error Detected'; // result is 'Error Detected' result = errorMessages || 'Saved OK'; var undefinedLogger; // if the logger isn't initialized, substitute it for the result of the right-hand expression var logger = undefinedLogger || { log: function (msg: string) { alert(msg); } }; // alerts 'Message' logger.log('Message');

//null referans hatası almayacaktır. interface Caravan { rooms: number; } var caravan: Caravan; if (caravan && caravan.rooms > 5) { //... } Functions function getAverage(a: number, b: number, c: number): string { var total = a + b + c; var average = total / 3; return 'The average is ' + average; } var result = getAverage(4, 3, 8); // 'The average is 5' var addNumbers = (a: number, b: number) => a + b; var addNumbers = (a: number, b: number) => { return a + b; } var addNumbers = function (a: number, b: number) { return a + b; }

Optional Parameter

function getAverage(a: number, b: number, c?: number): string { var total = a; var count = 1; total += b; count++; if (typeof c !== 'undefined') { total += c; count++; } var average = total / count; return 'The average is ' + average; } var result = getAverage(4, 6); // 'The average is 5'

Default Parameter Default değer olarak c#’ tan farklı olarak metot çağrılabilir. function concatenate(items: string[], separator = ',', beginAt = 0, endAt = items.length) { var result = ''; for (var i = beginAt; i < endAt; i++) { result += items[i]; if (i < (endAt - 1)) { result += separator; } } return result; } var items = ['A', 'B', 'C']; // 'A,B,C' var result = concatenate(items); // 'B-C' var partialResult = concatenate(items, '-', 1); Rest Parameter Rest parametresi metoda 0 veya daha fazla parametre vermeye izin verir. Bunun için gerekli kurallar aşağıdaki gibidir

-Bir metotda Sadece bir tane rest parametresi kullanılabilir

-Diğer parametlerin sonunda yer almalıdır.

-Dizi tipinde olmalıdır function getAverage(...a: number[]): string { var total = 0; var count = 0; for (var i = 0; i < a.length; i++) { total += a[i]; count++; } var average = total / count; return 'The average is ' + average; } var result = getAverage(2, 4, 6, 8, 10); // 'The average is 6' Overloads function getAverage(a: string, b: string, c: string): string; function getAverage(a: number, b: number, c: number): string; // implementation signature function getAverage(a: any, b: any, c: any): string { var total = parseInt(a, 10) + parseInt(b, 10) + parseInt(c, 10); var average = total / 3; return 'The average is ' + average; } var result = getAverage(4, 3, 8); // 5 Specialized Overload Signarutes Farklı tipte parametre vermek yerine string sabitleri ile overload oluşturmak için kullanılır.

Bunun için kurallar aşağıdaki gibidir

-en az bir tane nonspecialized signature olmalıdır.

-özel imza nonspecialized imzanın subtype’ını döndürmelidir

-implementation imza tüm imzalar ile uyumlu olmalıdır. class RandomHandler { }; class ReversedHandler { }; class Handler { }; class HandlerFactory { getHandler(type: 'Random'): RandomHandler; getHandler(type: 'Reversed'): ReversedHandler; getHandler(type: string): Handler; // non-specialized signature-bu satır olmadan kod çalışmaz getHandler(type: string): Handler { // implementation signature switch (type) { case 'Random': return new RandomHandler(); case 'Reversed': return new ReversedHandler(); default: return new Handler(); } } }

Özelleştirilmiş imzaların en çok kullanıldığı alan özelleştirilmemiş imzanın superclass’ları döndürdüğü durumlarda kullanılmaktadır. Document Object Model deki getElementsByTagName in nasıl tanımlandığı aşağıda gösterilmiştir.

// This example does not list all variations... getElementsByTagName(name: "a"): NodeListOf; getElementsByTagName(name: "blockquote"): NodeListOf; getElementsByTagName(name: "body"): NodeListOf; getElementsByTagName(name: "button"): NodeListOf; getElementsByTagName(name: "form"): NodeListOf; getElementsByTagName(name: "h1"): NodeListOf; getElementsByTagName(name: string): NodeList; // Non-specialized signature getElementsByTagName(name: string): NodeList { // implementation signature return document.getElementsByTagName(name); } Arrow Functions Typescriptte fonksiyonları tanımlamanın kısa yolları da mevcuttur. Arrow fonksiyonları function keywordu kullanılmadan kısaltılarak yazılır. var addNumbers = (a: number, b: number) => a + b; var addNumbers = (a: number, b: number) => { return a + b; } var addNumbers = function (a: number, b: number) { return a + b; } var makeName = (f: string, l: string) => ({ first: f, last: l });

Arrow syntaxı ile lexical scope’a ait değişkenlerin değeri çekilebilir. Normal fonksiyonda bu mümkün değildir. var ScopeLosingExample = { text: "Property from lexical scope", run: function () { setTimeout(function () { alert(this.text); }, 1000); } }; // alerts undefined ScopeLosingExample.run(); var ScopePreservingExample = { text: "Property from lexical scope", run: function () { setTimeout(() => { alert(this.text); }, 1000); } }; // alerts "Property from lexical scope" ScopePreservingExample.run();

Interfaces interface Point { // Properties x: number; y: number; } interface Passenger { // Properties name: string; } interface Vehicle { // Constructor new (): Vehicle; // Properties currentLocation: Point; // Methods travelTo(point: Point); addPassenger(passenger: Passenger); removePassenger(passenger: Passenger); } Interface sadece özet olarak tanımlama ve fonksiyon içerme aracı olarak değil, mevcut nesneleri de extend etmek için kullanılabilir.

Mevcut getElementsByTagName metoduna F12 ile gidildiğinde built-in NodeList interface’i aşağıdaki gibidir. interface NodeList { length: number; item(index: number): Node; [index: number]: Node; }

Mevcut interface’e aşağıdaki gibi ekleme yaparak ek özellikler sağlayabiliriz. interface NodeList { onclick: (event: MouseEvent) => any; } var nodeList = document.getElementsByTagName('div'); nodeList.onclick = function (event: MouseEvent) { alert('Clicked'); }; Classes Constructors

Tüm typescript classları siz tanımlamasanız dahi, bir constructor’a sahiptir.

Compiler bunu otomatik olarak yapacaktır. Eğer bir class başkasını kalıtım olarak almıyorsa parametresiz constructor otomatik olarak eklenir. Eğer kalıtım alıyorsa eklenecek olan constructor kalıtım alınan(superclass) class’ın constructor’ı ile aynı imzaya sahip olacaktır.

Örnekteki gibi constructor’a private gibi erişim belirteci eklendiğinde otomatik olarak map edilecektir. class Song { constructor(private artist: string, private title: string) { } play() { console.log('Playing ' + this.title + ' by ' + this.artist); } } class Jukebox { constructor(private songs: Song[]) { } play() { var song = this.getRandomSong(); song.play(); } private getRandomSong() { var songCount = this.songs.length; var songIndex = Math.floor(Math.random() * songCount); return this.songs[songIndex]; } } var songs = [ new Song('Bushbaby', 'Megaphone'), new Song('Delays', 'One More Lie In'), new Song('Goober Gun', 'Stereo'), new Song('Sohnee', 'Shatter'), new Song('Get Amped', 'Celebrity') ]; var jukebox = new Jukebox(songs); jukebox.play();

Elle parametre tanımlansaydı aşağıdaki gibi olacaktır. class Song { private artist: string; private title: string; constructor(artist: string, title: string) { this.artist = artist; this.title = title; } play() { console.log('Playing ' + this.title + ' by ' + this.artist); } } Access Modifiers Erişim belirteçleri property ve metotlar için class’ın içerisindeki görünürlüğünü değiştirmek için kullanılır. Default olarak metotlar ve property’ler public‘dir. Constructor’da tanımlanan parametre public olarak tanımlandığından ilgili parametre de public olacaktır. Properties and Methods class Playlist { private songs: Song[] = []; static maxSongCount: number = 30; constructor(public name: string) { } addSong(song: Song) { if (this.songs.length >= Playlist.maxSongCount) { throw new Error('Playlist is full'); } this.songs.push(song); } }

// Creating a new instance var playlist = new Playlist('My Playlist'); // Accessing a public instance property var name = playlist.name; // Calling a public instance method playlist.addSong(new Song('Therapy?', 'Crooked Timber')); // Accessing a public static property var maxSongs = Playlist.maxSongCount;

Burada dikkat edileceği gibi metotlar functionlar gibi tanımlanmıştır, yani function keyword’u eksiktir. Metotları statik yapmak için metot önüne static keyword’ü eklenilir. Statik öğeler class’a ait herhangi bir instance olmasa bile çağrılabilir.

Typescript property, get ve set metotlarını destekler. class Song { private artist: string; private title: string; constructor(artist: string, title: string) { this.artist = artist; this.title = title; } play() { console.log('Playing ' + this.title + ' by ' + this.artist); } } interface StockItem { description: string; asin: string; } class WarehouseLocation { private _stockItem; constructor(public aisle: number, public slot: string) { } get stockItem() { return this._stockItem; } set stockItem(item: StockItem) { this._stockItem = item; } } var figure = { asin: 'B001TEQ2PI', description: 'Figure' }; var warehouseSlot = new WarehouseLocation(15, 'A6'); warehouseSlot.stockItem = figure; Class Heritage Typescript’te 2 tip kalıtım vardır. Interface implemente(implement) etme ve class’ı extend(extends) etme. Class interface’i implemente ettiğinde içerisindeki metot ve değişkenleri içermek zorundadır. Class’a birden fazla interface implemente edilebilir. interface Audio { play(): any; } class Song implements Audio { constructor(private artist: string, private title: string) { } play(): void { console.log('Playing ' + this.title + ' by ' + this.artist); } static Comparer(a: Song, b: Song) { if (a.title === b.title) { return 0; } return a.title > b.title ? 1 : -1; } } class Playlist { constructor(public songs: Audio[]) { } play() { var song = this.songs.pop(); song.play(); } sort() { this.songs.sort(Song.Comparer); } } class RepeatingPlaylist extends Playlist { private songIndex = 0; constructor(songs: Song[]) { super(songs); } play() { this.songs[this.songIndex].play; this.songIndex++; if (this.songIndex >= this.songs.length) { this.songIndex = 0; } } }

Extend işlemine maruz kalan class’a derived class(yukarıdaki örnekte RepeatingPlayList) denir. Extend işlemi yapılan class’a ise base class(yukarıdaki örnekte PlayList) denilir. Derived class base class’a ait metot ve property leri kalıtım alır. Derived class’ı base class’ın metotlarını override edebilir. Derived class’daki constructor eğer ek bir kod yazılmayacaksa, örnekteki gibi bir kullanım söz konusu ise kaldırılabilir. Çünkü base class’daki constructor otomatik olarak çalışmış olacaktır. Eğer constructor tanımlanmışsa ve super çağrılmamışsa kod hata verecektir. Bunun yanında super metodu ile subclass’ı çağırma kodu constructordaki ilk satırda yazılmalıdır ve erişim belirteci(access modifier) base class’da kullanılmışsa derived class da erişim belirteci kullanılamaz.

-Bir class sadece bir defa kalıtım alabilir

-Bir class kendisini veya kendisini kalıtım almış bir class’ı kalıtım alamaz.

-Bir class interface gibi implemente edilebilir ve bu aşağıdaki koda uygulandığında hataya neden olmayacaktır. class Playlist extends RepeatingPlaylist {

} class RepeatingPlaylist extends Playlist {

}

Bir class’ın başka bir class’ı kalıtım alması ve birden fazla interface’i implemente etmesi mümkündür. Scope Bir class referans alınıp içerisindeki bir metot ile değişken değeri aşağıdaki gibi getirilmek isteniyorsa NaN veya undefined şeklinde hata verecektir. Mevcut scope‘dan çıktığı için count değeri herhangi bir yerde tutulmayacaktır. class ClickCounter { private count = 0; registerClick () { this.count++; alert(this.count);//nan } } var clickCounter = new ClickCounter(); document.getElementById('content').onclick = clickCounter.registerClick; Bu sorun için daha önceden de yapıldığı gibi arrow fonksiyonunu kullanan property çözecektir. class ClickCounter { private count = 0; registerClick = () => { this.count++; alert(this.count); } }

Bununla birlikte class’da arrow fonsiyonu kullanmamak için aşağıdaki gibi bir çözüm de yapılabilir var clickCounter = new ClickCounter(); document.getElementById('content').onclick = function () { clickCounter.registerClick() };

Bu şekilde kod arrow fonksiyonu kullanılmadan da çalışır olacaktır. EcmaScript 5 Bind Function Bir önceki class’daki arrow fonksiyonunu yazmamak için kullanılan yönteme ek olarak javascript’in bind fonksiyonunu kullanabiliriz. Bind fonksiyonu context’i metod için kalıcı olarak set eder. Daha çok context’i kalıcı olarak değiştirmek için kullanılabilir. class ClickCounter { private count = 0; registerClick () { this.count++; alert(this.count);//nan } } var clickCounter = new ClickCounter(); var clickHandler = clickCounter.registerClick.bind(clickCounter); document.getElementById('target').onclick = clickHandler;

Eski browserlar için bind fonksiyonu önerilmez. Type Information Runtime’da tip bilgilerine ulaşmak istediğimiz zaman olabilir. Class instance’ın tipini test etmek için instanceof operatörü kullanılır. Operatör instance ile test edilmek istenilen tip arasında olmalıdır. Eğer test true dönerse belirtilen class tipinde bir instance veya alt classlarında bir instance var anlamına gelmektedir. class Display { name: string = ''; } class Television extends Display { } class HiFi { } var display = new Display(); var television = new Television(); var hiFi = new HiFi(); var isDisplay; // true isDisplay = display instanceof Display; // true (inherits from Display) isDisplay = television instanceof Display; // false isDisplay = hiFi instanceof Display;

Buna benzer olarak herhangi bir property değerini içerip içermediğini öğrenmek için “in” keyword’u kullanılır. var hasName; // true hasName = 'name' in display; // false hasName = 'name' in television; // true hasName = 'name' in hiFi;

Eğer property initialize olmamışsa property bilgisi çekilemez. Burada bu kısımların runtime’da çalıştığını unutmamak gereklidir. Derlenmiş Javascript kodu içerisinde property bilgileri görülmeyecektir.

Eğer name property’ye bir değer verilirse hasName true dönecektir. class Display { name: string = ''; } class Television extends Display { } class HiFi { } var display = new Display(); var television = new Television(); var hiFi = new HiFi(); var hasName; // true hasName = 'name' in display; // true hasName = 'name' in television; // false hasName = 'name' in hiFi;

Burada property’e herhangi bir değer atanmadığı için false dönecektir. class Display { name: string; } var display = new Display(); // false var hasName = 'name' in display;

Çalışma anında tip adını geitmek için typeof operatörü kullanılmaz. Typeof tüm class’lar için object yanıtını dönecektir. Bunun için aşağıdaki gibi bir metot kullanılabilir.

class Display { name: string = ''; } class Television extends Display { } class HiFi { } class Describer { static getName(inputClass) { // RegEx to get the class name var funcNameRegex = /function (.{1,})\(/; var results = (funcNameRegex).exec((inputClass).constructor.toString()); return (results && results.length > 1) ? results[1] : ''; } } var tv = new Television(); var radio = new HiFi(); var tvType = Describer.getName(tv); // Television var radioType = Describer.getName(radio); // HiFi Modules Dosya organizasyonu ve dinamik olarak load etme gibi işlemler için moduller kullanılır. Typescript Name scpace’den ziyade daha çok modülleri load etmek için bu yapıyı kullanır. Runtime da modülleri load etmek için iki popüler standart vardır. CommonJs ve AMD(Asynchronous Module Definition) . CommonJS javascript için oluşturulmuş bir class kütüphanesidir ve modülleri load etmek için pattern’leri vardır. Server ve browserlar için birçok implementation vardır. Amd ise modülleri tanımlamak için geliştirilmiş basit bir api’dir ve asenkron pattern’e sahip olduğu için ’larda daha çok tercih edilir.

Internal Modüller: İçerisindeki öğeleri function içerisine alarak scope’lar ile limitlendirir. Internal modül adı global scope içerisine yazılır. Export edilen üyeler ise global scope module tanımlayıcısı tarafından çağrılabilinir.

External Modüller: Global scope’a bir şey eklenilmez. External modüldeki üyeler CommonJs kullanımında veya callback fonksiyonu kullanan AMD ile alias aracılığı ile erişilebilirdir Internal Modules Class üyeleri default olarak public olmasına rağmen module tarafından erişilemezdir. Erişilebilir olması için export keyword’u kullanılmalıdır. module Shipping { // Available as Shipping.Ship export interface Ship { name: string; port: string; displacement: number; } // Available as Shipping.Ferry export class Ferry implements Ship { constructor( public name: string, public port: string, public displacement: number) { } } // Only available inside of the Shipping module var defaultDisplacement = 4000; class PrivateShip implements Ship { constructor( public name: string, public port: string, public displacement: number = defaultDisplacement) { } } } var ferry = new Shipping.Ferry('Assurance', 'London', 3220);

Export keyword’u modül üyelerini dışarıya açmasına rağmen başka bir modül içerisinde import keywordu ile tanımlanan bir alias tarafından erişilebilir olacaktır. module Docking { import Ship = Shipping.Ship; export class Dock { private dockedShips: Ship[] = []; arrival(ship: Ship) { this.dockedShips.push(ship); } } } var dock = new Docking.Dock();

Visual studio’da bu koda gereksinim yoktur

/// External Modules Büyük programları ölçeklendirmek için önemlidir. Büyük programlar için external modülleri ve modül loading vazgeçilmez tool’lardır.

External modüllerin source file ile eşleşen (file extension olmayan) bir ismi vardır.

Learning the basics of typescript interface Point { x: number; y: number; } interface ThreeDPoint extends Point{ z: number; } var point1 = { x: 2, y: 1 }; var point2 = { x: 3,//property değerleri a ve b olduğunda hata verecektir. y: 32 } var threeDPoint= { x: 20, y: 11, z: 50 }; //function addPoints(p1: { x: number; y: number; }, p2: { x: number; y: number; }) { function addPoints(p1: Point, p2: Point) {

return { x: p1.x + p2.x, y: p1.y + p2.y

}; } addPoints(point1, point2); addPoints(point1, threeDPoint);//threedpoint x ve y property değerlerini içerdiği için hata vermeyecektir. Object oriented Concepts in TypeScript Classes class Point { static origin = new Point(0, 0);

static add(p1: Point, p2: Point) { return p1.add(p2); }

//private x: number;//javascriptte private yok. //private y: number; constructor(private xValue: number, private yValue: number) {//x ve y private olarak verilmediği sürece property olarak görülmeyecektir } get x() { return this.xValue; } //set x(value: number) { readonly hale getirilir // this.xValue = value; //}

get y() { return this.yValue; }

add(point: Point) { return new Point(point.x + this.x, point.y + this.y); }

} var p1 = new Point(2, 1); //p1. yazıldığında private propertyler gelmeyecektir //p1.x = 10;//setter olmadığı halde hata vermeyecektir. var p2 = new Point(5, 2); var p3 = p1.add(p2); p3 = Point.add(p1, p2); Point.origin; Inheritance SubClassing Shape.ts class Polygon { height: number; constructor(height: number) { this.height = height; } computeArea(): number { return 0; } } class Triangle extends Polygon { base: number; constructor(height: number, base: number) { super(height);//bu metot çağrılmak zorundadır aksi halde hata verecektir. this.base = base; } computeArea() { return .5 * this.base * this.height; } } class Rectangle extends Polygon { width: number; constructor(height: number, width: number) { super(height); this.width = width; } computeArea() { return this.height * this.width; } } class Square extends Rectangle { constructor(lenght: number) { super(length, length); } }

Point.ts class Point { static origin = new Point(0, 0); static add(p1: Point, p2: Point) { return p1.add(p2); }

//private x: number;//javascriptte private yok. //private y: number; constructor(private xValue: number, private yValue: number) {//x ve y private olarak verilmediği sürece property olarak görülmeyecektir } get x() { return this.xValue; } //set x(value: number) { readonly hale getirilir // this.xValue = value; //}

get y() { return this.yValue; }

add(point: Point) { return new Point(point.x + this.x, point.y + this.y); } }

class ThreeDPoint extends Point { //constructor(private xValue: number, private yValue: number, private zValue: number)//olduğunda hata verecektir. constructor(xValue: number, yValue: number, private zValue: number) { super(xValue, yValue); } //get y() { // return this.yValue;//private olduğu için ulaşılamaz //} get z() { return this.zValue;//private olduğu için ulaşılamaz } add(point: ThreeDPoint) { return new ThreeDPoint(point.x + this.x, point.y + this.y, point.z + this.z); } } var p1 = new ThreeDPoint(1, 2, 3); var p2 = new ThreeDPoint(3, 2, 1); var p3 = p1.add(p2); Implementing Interfaces Shape.ts interface Shape { //computeArea(): number; computeArea:()=> number;//şeklinde de yazılabilir } class Polygon implements Shape { height: number; computeArea(): number { return 0; } }

//class Triangle implements Polygon {//class'a class implement edilebilir. Kalıtım almak anlamına gelmez. // height: number;

// computeArea(): number { // return 0; // } //} class Elipse implements Shape { a: number; b: number; constructor(a: number, b: number) { this.a = a; this.b = b; } computeArea() { return Math.PI * this.a * this.b; } } var elipse = new Elipse(4, 4); function doSomethingWithShape(shape: Shape) { alert(shape.computeArea()); } doSomethingWithShape(elipse);//eğer shape interface'inden implemente eden kod satırını kaldırırsak çalışmaya devam edecektir.Çünkü ilgili metodu class içermektedir

HTMLElement Functions and overloads Functions.ts function sum(a: number, b: number) { return a + b; } var sum2 = function (a: number, b: number) { return a + b; }; var sum3 = (a: number, b: number) => { return a + b; }; var sum4 = (a: number, b: number) => a + b; function sayHello(firstName: string, lastName?: string) {//optional parameter ? ile belirlenir. c# daki optional parameterdan sonraki parametreler de optional olmalıdır. var greeting = "Hello " + firstName; if (lastName) { greeting += " " + lastName; } return greeting; } sayHello("John"); sayHello("John", "Doe"); function sayHello2(firstName: string, lastName = "") {//default parameter value.optional parameterde olduğu gibi diğerleri de default parameter değerine sahip olmalıdır. return "Hello " + firstName + " " + lastName; } sayHello2("John"); sayHello2("John", "Doe"); function sum5(a: number, b: number, ...c: number[]) { var total = a + b; c.forEach((value) => { total += value; }); return total; } var total = sum5(1, 2, 5, 9, 4);

//function foo(a, b): any { // return a+ b; //} function foo (a: number, b: number): number; function foo(a: string, b: string): number; function foo(a, b): any { if (typeof a == "string" && typeof b == "string") { return a + " " + b; } return a + b; }

var a = foo(1, 2); var b = foo("john", "doe"); //var c = foo("john", 1);//overload'ı olmaduğu için hata verecektir.

Generics Generics.ts function foo(a:T) { return a; } var bar = foo("hello world"); var bar2 = foo(10); var bar3 = foo(document.createElement("div"));

var baz = new Array(); var json = '{"firstName":"John","lastName":"Doe"}'; interface Person { firstName: string; lastName: string; } var myJSON = { parse: function (data: string) :T{ return JSON.parse(data); } }; var obj = myJSON.parse(json);

class Foo { foo: T; bar(data: T) { } baz(): T { return this.foo; } }

interface Person2 { firstName: string; lastName: string; } var obj2 = new Foo(); obj2.bar

Other Features of TypeScript Modules Shapes.ts

//module Shapes {//internal module için geçerlidir export interface Shape {//shape hata vermemesi için proje properties kısmından Typescript build kısmına gelinir ve amd seçilir. computeArea: () => number; } //}

Polygon.ts

/// //module Shapes {//internal module için geçerlidir import shapes = require("shapes");//kullanılacak file adı verilir. export class Polygon implements shapes.Shape { height: number; constructor(height: number) { this.height = height; }

computeArea(): number { return 0; } }

export class Triangle extends Polygon { base: number; constructor(height: number, base: number) { super(height); this.base = base; } computeArea(): number { return .5 * this.base * this.height; } }

export class Rectangle extends Polygon { width: number; constructor(height: number, width: number) { super(height); this.width = width; } computeArea() { return this.height * this.width; } }

export class Square extends Rectangle { constructor(length: number) { super(length, length); } } //}

Ellipses.ts

/// //module Shapes { import shapes = require("shapes");//kullanılacak file adı verilir. export class Ellipse implements shapes.Shape { a: number; b: number; constructor(a: number, b: number) { this.a = a; this.b = b; } computeArea() { return Math.PI * this.a * this.b; } }

export class Circle extends Ellipse { radius: number; constructor(radius: number) { super(radius, radius); this.radius = radius; } } //}

App.ts import polygons = require("polygons");//kullanılacak file adı verilir. import ellipses = require("ellipses"); /// ///

//Shapes.//hiçbir şey gelmeyecektir. bunun için class lara export yazmak gerekecektir. var triangle = new polygons.Triangle(4, 4); var square = new polygons.Square(4); var circle = new ellipses.Circle(4); alert(triangle.base);

Html

Declaration Merging Merging.ts interface Box { height: number; width: number; recycle(): void; } interface Box { depth: number; recycle(tearDown: boolean): void; }

//var box: Box = {//interface ler birleştirilmiş olarak gelecektir. // height: 10, depth: 15 //} module Foo { var foo = "hello module merging"; export function bar() { return foo; } } module Foo { export function baz() { //return foo;//typescript her iki modülü birleştirse dahi her modülün kendine air privacy'leri korur. Diğer tarafta export edilmedi çünkü } } function sayHello(name: string) { return sayHello.prefix + name; } module sayHello { export var prefix = "Hello, "; } sayHello("John Doe");//Hello, John Doe

Mixins Birden fazla class’ı implemente etmede kullanılır. Mixin.ts class Walker { name: string; walk() { return this.name + " is walking"; } } class Speaker { name: string; speak() { return this.name + " is speaking"; }

} class Person { name: string; constructor(name: string) { this.name = name; } walk: () => string; speak: () => string;

} function mix(derivedType: any, ...baseTypes: any[]) { baseTypes.forEach(baseType=> { Object.getOwnPropertyNames(baseType.prototype).forEach(name=> { derivedType.prototype[name] = baseType.prototype[name]; }); }) } mix(Person, Walker, Speaker); var person = new Person("John Doe"); alert(person.speak()); alert(person.walk());