Neden Typescript?

Typescript’in nedenlerine başlamadan önce biraz Development sürecine değinmek istiyorum.

Kamil Bukum
Finartz
9 min readOct 2, 2017

--

Backend, Frontend Developer olmak

Sektörde Developer birkaç farklı kategoriye ayrılmış durumda. Backend Developer, Frontend Developer veya Fullstack Developer olmak üzere. Tabi bunların daha spesifik kategorileri olsa da genel anlamda bunları ele almanın yeterli olduğunu düşünüyorum. Tanımları kısmen belirlenmiş olsa da kapsamları hala net olabilmiş değil. Örneğin; Backend Developer bazen DevOps + Development bazı yerlerde birazcık DevOps + Development bazılarında ise sadece Development. Diğerleri için de benzer durumları söz konusu.

Fullstack Developer olarak çalıştığım için iki taraftan da olayı ele alabildiğimi düşünüyorum. Aslında Fullstack olarak çalışan birçok kişinin genel olarak Backend Developer’a yakın olduğunu Frontend’i de gereklilikten dolayı yaptığını söyleyebilirim.

Backend developer açısından baktığımda Backend yazarken genel olarak yapacağınız işe odaklanırken frontend tarafında bu bazen çığrından çıkıp kullanılan tarayıcı (Chrome, Firefox, IE, Opera, Safari) hatta ondan ziyade tarayıcının çalıştığı cihaza kadar hesaplamalar gerektirebiliyor. Tabii ki backend tarafında da bazen işletim sistemine göre bir şeyler yapmak gerekebilir; ancak bu üst seviyede yapılan bazı durumlar için söz konusu. Frontend tarafında ise bazen çok basit bir işlemde bile bunu düşünmeniz gerekir ki bundan dolayı Backend Developer’lar Frontend tarafını bir problem yumağı olarak görür.

Frontend’de Çözüm Arayışı

Ekip olarak Fullstack Developer olarak çalıştığımız için Frontend tarafında işin kolayına kaçmak istedik. Bir şekilde Frontend’i basitleştirmek (automatize) istedik. Bu yüzden Kendo UI alt yapısını kullanan UI kütüphanesi tasarladık; ancak yeni başlayan geliştiricilerin var olan koda adaptasyonunda büyük problemler yaşadık. Bunun üzerinde React ile tanıştık. Ve yeniden bir framework tasarlayarak UI tarafını daha basit hale getirmeye çalıştık. Tabi sadece React anlaşılırlık katmayacağından Javascript kısmında ES6, UI için react-bootstrap ve development ortamı için gulp, webpack , grunt, babel gibi bir çok tool’u öğrenip alt yapı sağlayarak UI kısmını en basit hale getirmeye çalıştık. Durum böyle olunca aslında problemlerinden kaçtığımız Frontend tarafının bir parçası olduk. :)

Neden Typescript ?

ES6 yazarken bir şeyler eskisine göre düzenliydi, anlaşılırdı. En azından koda yeni bir ekleme yaptığımda daha hatasız ve anlaşılır bir ürün çıkıyordu ama geliştirme sürecini biraz daha iyileştirmek istedim. Bu yüzden çözüm arayışlarına girdim. Peki neydi bu eksiklikler?

  • Çalıştırdığım metotta ne dönüyor ? Daha anlaşılır olması gerekmez mi?Özellikle kütüphane incelerken. Kullanmak istediğim kütüphaneyi incelerken dökümantasyonunu da incelemeliyim; çünkü tüm kütüphaneler detaylı dökümantasyona sahip olmayabilir. Aksi durumda javascript debugger’dan inceleme yaparak keşfe çıkmak gerekir ki bu da development sürecini uzatan zahmetli bir işlem.
  • Metodu private yaparken __ 'mi kullanmalayım. Bu şekilde kullanmakta ne demek?! Neden bir identifier yokki bunun için?
  • Compile işlemi için hangi babel transformer’in ihtiyacım var? state0 , stage1, stage2 mi bunlar ne ki ?
  • ES7'de static mi var? ES7 transformer daha çıkmadı mı ? Onun yerine babel’in ES7 static desteği ekleyen transformer’imi.

Bu şekilde sorunlar birikirken ben typescript ile tanıştım. Tamam da typescript Microsoft tarafından geliştirmiş bir compiler. Geliştiren Microsoft olunca eskiden de var olan bir önyargı ile görmezden geliyorum.

Typescript’in ürettiği çözümlerin bir kısmını ES6'da Flow ve Eslint kullanarak gidermeye çalıştım. Flow içinde farklı çözümler vardı; ancak bir tarafı düzeltiyordun, başka tarafta problemler oluyordu. Hiçbiri yeteri kadar kapsamlı düşünülmemişti. Bu yüzden problemleri tamamen çözemiyordum. Ya da bulduğum çözümler beni yeterince tatmin etmiyordu. Performanstan kayıp vs. derken bir gün typescript yazarken buldum kendimi. Ilk başlarda o da çok zor geliyordu. Ama daha önceki savaşlardan sonra bu savaşa da girmeye hazırdım ve küçük küçük bir çok deneme (kütüphane yazma çabaları) yaptım. Sonunda yani yaklaşık 1–2 ay sonra evet Typescript benim Frontend’e aradığım yazım şekli dedim. Peki neden bunu diyebildim? Aşağıdaki maddelerde bunu açıklayacağım.

  • Tek compiler ile tüm transform işlemleri yapabilme.
  • ES6 ile yazdığım her şeyi yapabilme, ayrıca artı birçok özellik.
  • Public, Private, Protected gibi daha önce aşina olduğum anlaşılırlığı yükselten yazım tarzları.
  • Java’ya benzer bir jenerik yapısı.
  • Abstract, Enum gibi daha da özelleşmiş yapılar.
  • Hiçbir runtime maliyeti bulunmayan interface’ler.(Frontend’de kod boyutu da maliyetten olduğundan)
  • Tek dosyada yapılan configurasyonlar ile tüm işlemlerin yapılabilmesi.
  • Hiçbir aracı araç kullanmadan build işlemlerininin yapılabilmesi.
  • Development için webpack ile entegrasyonu

En önemlisi ;

  • Yazdığım kodu çağırırken tekrar tekrar kodu açıp bakmama gerek kalmıyor.
  • Koda baktığımda anlaşılırlık seviyesi yüksek bir kod görebiliyorum.
  • Bir kodu yazarken (ki bazen 5–10 class’tan oluşan birşeyler yazıyordum tek seferde) kodum nerdeyse hatasız çalışıyordu. Yani ben javascript yazacağım ve ilk denememde çalışacak. Normalde yok böyle bir şey!
  • IDE Desteği ( Özellikle Webstrom ve Visual Studio Code ) kullandığınızda typescript kullanmanın marifetini görebilirsiniz. Çünkü Typed bir dil olduğundan IDE Asistant size yardımcı olabiliyor.
  • React ile entegre etme ve aynı süreci React Component’lerinde yapabilme. JSX kullandığınızda bir componentte bir attribute eklediğinizde Attribute var mı ? Opsiyonel mi ? Required mi ? gibi hataları Runtime’da anlayabilirsiniz; Ancak bu entegrasyonla tasarım aşamasında görebilmeniz mümkün. Yani probemlerleri tasarım aşamasında anlayabilirsiniz.

Peki , Hiç mi Dezavantajı yok

Tabiki dezavantajları mevcut. Örneğin ;

  • Debugging yapma
  • Typescript desteği olmayan kütüphaneleri kullanmak
  • Dinamik nesneler oluşturma (İçeriği belli olmayan dinamik nesneler)

Ancak bu dezavantajları da yok etmek mümkün tabii.

  • Debug kısmı tamamen configurasyonuna bağlı bir durum. Araştırarak çözülebilecek bir durum.
  • Eğer typescript desteği mevcut değilse birkaç farklı şekilde problemi çözebiliriz. Typescript desteği istemiyorsak, import yerine require kullanmak. Yani node require özelliği. Bu durumda typescript bunun için herhangi bir compile işlemi gerçekleştirmiyor. Yada eğer typescript destekli olmasını istiyorsanız kütüphane için tanım sınıfları oluşturma (Typescript definitions ).
  • Bir yerde dinamizm varsa typescript’te any demeniz yeterli olur. Bu durumda o tipi kullanırken javascript kullanmaktan farkı kalmaz.

Yani anlayacağınız aslında dezavantajlar hali hazırda var olan ES6 veya javascript’e göre zaten dezavantaj değil. Sadece beklentilerimize göre dezavantaj sayılabilir ancak şuan hatırlamadığım bir çok problemide aynı şekilde uğraşarak çözdüm diyebilirim. Ve sonuç olarak şu an bildiğim frontend dünyasında avantajlarından bahsedebileceğim bir dil kullanmaya başladım diyebilirim.

Bu kadar teorik anlattık durduk, şimdi tüm hikayeyi örnekleyelim değil mi .

Kütüphanelerin typescript tanımlamaları

Tanımlamalar birkaç farklı şekilde olabilir

  • Kütüphane içerisinde d.ts(typescript tanım dosya uzantısı)’leri tutarak
  • Kütüphanenin typescript tanım dosyalarını barındırması. Örneğin mobx kütüphanesi içerisinde typescript tanımlamalarını barındırır. O yüzden

demek dışında bir şeye ihtiyacınız olmaz.

Örnekte react dependency’lere eklerken typescript tanım kütüphanesini de dev-dependency olarak ekliyoruz.

  • Proje içerisinde .d.ts dosyalarını tutarak.

Export, Import işlemleri

ES6'dan gelen bir kaç özelliğin tamamını typescript içerisinde bulabilirsiniz.

Typescript bilgisine geçmeden önce birkaç tanımı bilmekte fayda var.

module.exports

nodejs’te mevcut olan module.exports commonjs yönteminde bir dosya başka bir yerden alındığında (import edildiğinde) kullanıma açılan nesneleri tutan bir referanstır diyebiliriz. Yani bir nesneyi bulunduğu tanım yeri dışında kullanılabilmesini istiyorsak module.exports’a bu nesnenin eklenmesi gerekir. Bir nevi nesneyi public yapmak diyebiliriz.

Örneğin;

// a.js

// b.js

Örnekte ex isminde bir değişken tanımladık ve buna bazı nesneler ekledik.

Bu nesneyi module.exports = ex şeklinde dış dünyaya açtık . Bunu yapmamış olsaydık bu dosya içerisinde exdeğişkeni kullanılabilirken require edildiği yerde kullanılamayacaktı.

Tabiki bunları dışarı vermenin başka yollarıda mevcut. UMD veya AMD yöntemlerini kullanarak. Ancak nodejstarafından varsayılan olarak kullanılan commonjs yöntemidir diyebiliriz.

default

ES6 ile gelen default sözcüğü aslında basit bir taktik diyebiliriz. module.exports işlemi yapılırken birden fazla export kullanılabilir. Bu durumda belirteç olmadan çağırım yapıldığında hangisinin geleceğini belirlemek için defaultkeyword’ü kullanılır.

Örneğin;

Biz eğer ES6 veya typescript kullanarak import a from "./a.js" şeklinde çağırırsak a değeri "Bu default exporttur." default değerini taşır.

export

export let key = object, export default object

Aslında module.exports işleminin yeni kullanım şeklidir diyebiliriz. Aşağıdaki örneklerden anlayacağınız gibi export aynı sayfada defalarca çağrılarak istenildiği kadar module export edilebilir. module.exports[key]=value şeklinde kullanmak diye düşünebiirsiniz.default export ise sadece default keywordune bir elemanın atanmasıdır. Burada dikkat etmeniz gereken her zaman sadece bir export default edebilirsiniz.

  • export interface

Interface’ler sadece typescript’te geçerli yapılardır. Sadece type referans olarak gösterilebilirler. Değer olarak kullanılamazlar.

  • export const object
  • export class
  • export in block

export işlemi yaparken farklı isimde export edebilirsiniz.

  • export as

export işlemi yaparken farklı isimde export edebilirsiniz.

  • export all

export edilecek nesnenin tüm içeriğini export edebilirsiniz.

  • export default

default olacak şekilde export işlemi yapabilirsiniz.

import

import işlemi module.exports ile çıkarılan yani export edilen tüm module'lerin import edilmesi sağlar. Ancak import ederek birkaç farklı yöntem ile import edebiliriz.

  • import default from “./dosya”;

Bu işlem ile default olarak belirtilmiş nesne import edilir.

// a.js

// b.js

  • import { Example, Example2 } from “./dosya”;

Bu işlem ile default dışında export edilmiş olan nesneleri alabiliriz.

// a.js

// b.js

import * as Hepsi from “./dosya”;

Bu işlem ile module.exports çıktısını import etmiş oluruz. Yani tüm export'lari bir obje içerisinde import etmiş oluruz.

Not: Bu özellik es6'da mevcut değil diyebiliriz. Bunun yerinde es6'da default mevcut değilse otomatik hepsini import etmiş oluruz.

// a.js

// b.js

  • class , abstract, enum

Class tanımı class keyword'u ile yapılır.

abstract tanımı ise class keyword'unden once yapılır

enum

String enum tanımı

  • public, private, protected

Public erişimcisi ile belirtilen class üyeleri (field, member) dışarıdan erişilebilir olur.

protected erişimcisi ile belirtilen class üyeleri (field, member) subclass’lar tarafından erişilebilir olur.

private erişimcisi ile belirtilen class üyeleri (field, member) sadece class içerisinden erişilebilir olur.

  • constructor

Sınıfın oluşturulması için gereken metottur.

  • static
  • Generic Tip tanımlamaları

Generic Tip tanımlamaları ile birden farklı tip için kullanılabilen sınıflar yazabilirsiniz. Örneğin aşağıdaki Iterator sınıfı herhangi bir tip için Array iterasyonu yapmamızı sağlar.

  • interface

Tipleri tanımlamak için kullanılan ve hiç bir runtime maliyeti bulunmayan sınıfları diyebiliriz. Yani bir interface ile tip belirtilmelirini yapabilirsiniz. Ancak javascript’e dönüştürülen kod da bu interface tanımını bulamazsınız. Yani interface tanımı kodun typescript sürecinde düzenli olmasını sağlar. Javascript’te dönüştürülen kod üzerinde Typescriptin herhangi bir hükmü kalmaz.

Örneğin;

gibi bir çok işlemi interface il yapmak mümkün. Burdaki kod compile olduğunda ise göreceğiz şeklindedir. Yani interface tanımlamaları compile işleminden sonra gereksiz olduğundan build’e eklenmez.

Daha fazlası için;

--

--