İçeriğe geç

TS Hızlı Baslangıç

Burada TypeScript e hızlı bir başlangıç yapacagız. Aşagıdaki bilgiler bir anlamda daha kapsamlı bir dökümasyon için ilk notlar özelliğini taşıyor.

Daha sonra bu sayfa kaldırılacak ve daha kapsamlı TS notları eklenecektir.

Kisaca TS Nedir?

Cok kisaca buyuk projelerde JS’den yapisindan kaynaklanabilecek bazi hatalarin onune gecmeyi amaclamaktadir. En onemli ozelliligi verilerin tiplerini (types) belirterek bunlara yanlis degerler atanmasinin onune gecmek ve bu hatalari daha kodu yazarken alacagimiz TS hatalari ile onlemektir.

.ts uzantili dosya icine yazilir.

.tsx dosyalari TS ile JSX kullaniminda kullanilir.

Peki nedir bu hatalar yukarida bahsedilen ve TS bunlarin onune nasil geiciyor? Kisa ornek ile aciklayalim.

test.js
let message = "Merhaba, dünya!";
message = 42; // Bu JS'de geçerli, ancak mantıksal hata potansiyeli taşır
console.log(message); // Çıktı: 42
test.ts
let message: string = "Merhaba, dünya!";
// message = 42; // TypeScript hata verir: 'number' tipi 'string' tipine atanamaz.
console.log(message); // Çıktı: "Merhaba, dünya!"

Açıklama: TypeScript’te, message değişkeninin tipi string olarak belirlendi. Yani message sadece metinleri (string) tutabilir. JavaScript’te ise tip belirlemesi olmadığı için bu tür bir hata çalışma anında ortaya çıkabilir.

Yukaridaki ornekte de goruldugu gibi syntax’i su sekilde:

test.ts
let message: string = "Merhaba, dünya!";
// degisken isminden sonra : (iki nokta ust uste) ve tipi yaziyoruz.

Temel Tipler (Basic Types)

  • string
  • number
  • boolean
  • array
  • tuple
  • enum
  • any
  • void
  • null ve undefined
  • never

Önce en yaygın kullanılan birkaç temel tipi örneklerle görelim.

String, Number ve Boolean Tipleri

test.ts
let isim: string = "Özay";
let yas: number = 30;
let aktif: boolean = true;

Açıklama: TypeScript’te her değişkenin türünü string, number, boolean gibi belirterek, yanlış tür atanmasını engelleyebiliriz. Mesela isim değişkeni sadece bir string alabilir; farklı bir tür verilirse hata alırız.

Any kullanimi

Asagidaki ornekte gelen verinin string mi yoksa number mi oldugunu bilmiyoruz bu yuzden any kullandik.

test.ts
let userAge : any;
userAge = 25 //number kabul edildi
userAge = "45" //string kabul edildi
console.log(userAge)

Union kullanimi

//Union kullanimi. gelen verinin tipinden emin degilsek kullanmak icin Any benzeri ancak burada tipleri seciyoruz. Asagidaki ornekte oldugu gibi veri ya string ya da number olabilir. Baska bir deger atanamaz.

let age : string | number = "25";

Literal Type kullainimi

Biraz Union kullanimina benzeriyor ancak burada type belirlemek yerine kabul edilebilecek verileri ekliyoruz. Ornegin:

literal.ts
let statusResult : "pending" | "approved" | "rejected";
statusResult = "pending"; //kabul edildi
statusResult = "rejected"; //kabul edildi
//statusResult = "ozay"; kabul edilmedi, cunku bu deger onayli degerlerden degil.
console.log(statusResult)

Degiskenlerde (Array) Type kullainimi

Degiskenlerde type kullanimi yukaridaki orneklere benzer ancak atanan tipin bir array icin oldugununu belirtmek icin [] koseli parantezleri ekleniyor.

Örneklere bakalim:

array-types.ts
let myList : string[] = ["ozay", "Mete", "Yagmur"];
// alternatif kullanim, koseli parantez kullanmadan.
let myList2 : Array<string> = ["ozay", "Mete", "Yagmur"];
// Union kullanimini arraylerde de kullanabiliriz.
let otherList : (string | number) [] = ["ozay", "Mete", 34, 345];

Type ve Interface Kullanimi

Kisaca interface ve type ile kendi tiplerimizi veya tip ozel tip gruplarimizi (types) olusturup kullanabiliyoruz.

Orneklere bakalim;

type-test.ts
// asagida User adinda ozel bir tip grubu olusturuk ve
// bu grub icinde name ve age degerlerine tip atatdik.
type User = {
name : string,
age : number
}
// burada tetUser icine bir kullanici bilgisi ekledik.
//name ve age icin artik User altinda tipler belirlendigi icin
//tip kontrolu saglamis olduk. Ornegin age'e string eklenirse ts hatasi alacagiz
let testUser : User = {
name : "Ozay",
age : 45,
}
// veya bir array icine bu tipi atayabiliriz
let arrayUser : User [] = []
console.log(testUser);

Interface ile ozel type olusturulmasinda simdilik sadece syntax olarak farktan basedecegim. Sonra type ve interface arasindaki farki extend kullaniminda Link detayli gorecegiz.

interface-test.ts
// type kullanimina gore tek fark tip adindan sonra = koymamak.
interface User {
name: string,
age: number,
}

Optional type ?

Yukarida bahsettigimiz interface ve type kullaniminda soyle bir durum var. Eger siz ornegin User altinda name ve age degiskenlerine tip atamissaniz bunlari cagirdiginiz yerlerde sizden hem name hemde age degiskenleri istenecek. Eger bu degiskenlerden biri eksik ise ts hata verecektir.

Bunu asmak icin optional type dedigimiz bir yontem kullaniyoruz. Ornege bakalim;

optional-test.ts
type User = {
name: string,
age: number,
}
const testUser : User {
name: "ozay",
}
// bu durumda testUser hata verecektir cunku ayrica age olmasi gerekiyor.
// bu durumu asmak icin sadece degiskenden sonra soru isareti ? ekliyoruz.
type User = {
name: string,
age?: number,
}
// bu durumda artik age degeri opsiyonel bir deger haline geldi.

Fonksiyonlarda kullanim

TS’nin fonksiyonlarda kullanimi cok onemli bir konu. Bu konu daha detaylica islenecek. Simdilik sadece syntax kullaniminda odaklanalim.

Basit kullanim: herbir degiskenin tipini belirlemek.

function topla(a:number, b:number) {
console.log(a+b)
}
topla(5,5) // cikti 10 olacak
topla(5,"x") //ts hata verecek cunku b'nin tipi number olarak belirlendi.

Return icin tip belirleme: Bu ornekte a ve b degiskenine tip tanimlamasi yapiyoruz. Ancak ayrica bir de fonksiyonun geneline yani sonucunu (return) bir tip daha atiyoruz. Ornege bakalim;

function topla(a:number, b:number): number {
return a + b;
}
const sonuc = topla(2,2)
console.log(sonuc) // cikti 4 olacak
//birden fazla return degeri de atamak mumkum ornegin;
function topla(a:number, b:number): number | string {
return a + b;
}

Baska bir fonksiyon ornegi, burada hem funksiyona string atadik hemde array ile donen degerlere string atadik.

function test(myArray : string[]) {
myArray.forEach((value)=> console.log(value))
}
let myArray : string[] = ["Ali", "Veli", "Deli"]
test(myArray)

Generic fonksiyon kullanimi

Cikacak degerin farkli tiplerde olmasi durumunda bunu generic fonksiyon kullanarak yapabiliyoruz. Peki ama biz zaten Any ile bunu yapabiliyoruz neden generic kullanmamiz gerekiyor? Cunku any ile tipi kaciriyoruz, generic ile tipi yakalama sansimiz oluyor.

Asagidaki ornekte yazdiradinda bir fonksiyon olusturmak istiyoruz. Bu fonksiyon icindeki degeri console’a yazdiricak. Ancak bu fonksiyon herhangi bir tip ile kullanilabilir. Bu durumda;

yazdir.ts
function yazdir<T>(array : T[]) :void {
console.log(array)
}
yazdir(["ali", "veli", "deli"]) // ["ali", "veli", "deli"]
yazdir([true, false]) // [true, false]
yazdir([1, 2]) // [1, 2]

Yukaridaki yapiyi biraz aciklayalim;

function yazdir (array : T[]) : void burada diyorum ki sana T tipinde bir array gelecek, nasil bir sey gelecegini bilmiyorum sadece T tipinde gelecek. (Bu T disinda baska bir harf de olabilir)

void bana bir deger dondurme demek.

Simdi yazalim fonksiyonu;

function yazdir(array : T[]) :void {
console.log(array)
}

Bunu bu sekilde yazdigimizda T ile ilgili bir hata aliyoruz. Diyor ki bana T verdin ancak ben bunun ne oldugunu bilmiyorum.

Bu sorunu asmak icin bu fonksiyonun bir “Generic” fonksiyon oldugunu belirtmemiz gerekiyor. Bunu da fonksiyon isminden hemen sonra <T> ekleyerek cozuyoruz. Yani:

function yazdir<T>(array : T[]) :void {
console.log(array)
}
// <T> yerine herhangi bir harf veya kelime kullanabilriz;
function yazdir<Test>(array : Test[]) :void {
console.log(array)
}

Kullanimi daha iyi anlamak icin bir ornek daha yapalim;

interface GenericType<T> {
name: string,
age: number,
salary: T[] // salary generic olmali cunku ne gelecegini bilmiyoruz
}
const obj1 : GenericType<string> = {
name: "Ali",
age: 25,
salary: ["1000", "2000", "3000"]
}
const obj2 : GenericType<number> = {
name: "Veli",
age: 25,
salary: [1000, 2000, 3000]
}

Aciklama: Yukaridaki ornekte salary belirsiz yani bize number veya string olarak gelebilir. Bizde interface kullanarak GenericType adinda kendi type grubumuzu olusturuyouruz ve salary kismini generic olarak tanimliyoruz.

Gordugunuz gibi obj1 de string olan degerler obj2 de number oldu ve biz her iki durumda da salary icin bir type belirlemis olduk.

Video kaynak:

Extending Types

Tekraralanan alanlari azaltmaya yonelik bir yapidir. Tekrarlanan ve ayni alan ve tipe sahip tipleri ayri ayri yazmak yerine yazilmis olanlardan almaya (Extend etmeye) yarar.

Asagidaki ornekte Musteri ve Kurum datalarinin tipleri belirlenmis, dikkat ederseniz ortak alanlar var yani ìd, olustrumaTarihi ve olusturanKisi alanlari ayni. Buyuk projelerde tekrarlanan bu alanlar hem kod okunurlulugunu bozar hemde kod kalitesini dusurur.

interface-extend.ts
interface Musteri {
id: string,
olusturmaTarihi: string,
olusturanKisi: string,
musteriNo: string,
}
interface Kurum {
id: string,
olusturmaTarihi: string,
olusturanKisi: string,
kurumNo: string,
}
const musteri : Musteri = {
id: "1",
olusturmaTarihi: "09.06.2024",
olusturanKisi: "Veli",
musteriNo: "234234",
}
const kurum : Kurum = {
id: "14",
olusturmaTarihi: "09.06.2024",
olusturanKisi: "Ali",
kurumNo: "234566",
}

Peki boyle bir durumda ne yapacagiz?

Yukaridaki ornekten yola cikalim ve ortak alanlar icin bir OrtakAlanlar interface’i olusturalim. Musteri ve Kurum interface’lerinde artik tekrar eden tipler yok.

Peki Musteri ve Kurum interface’lerine nasil OrtakAlanlar daki tipleri ekleyecegiz? Bunun icin tip adindan sonra extends ve sonra ortak alandan alacagimiz tip adini bu ornekte OrtakAlanlar yaziyoruz.

Boylelikle Musteri icine OrtakAlanlari dahil etmis (extend etmis) oluyoruz.

interface-extend.ts
interface OrtakAlanlar {
id: string,
olusturmaTarihi: string,
olusturanKisi: string,
}
interface Musteri extends OrtakAlanlar {
musteriNo: string,
}
interface Kurum extends OrtakAlanlar {
kurumNo: string,
}
const musteri : Musteri = {
id: "1",
olusturmaTarihi: "09.06.2024",
olusturanKisi: "Veli",
musteriNo: "234234",
}
const kurum : Kurum = {
id: "14",
olusturmaTarihi: "09.06.2024",
olusturanKisi: "Ali",
kurumNo: "234566",
}

Partial, Required, ReadOnly, pick, omit kullanimi

Partial kullanimi;

Asagidaki ornekte user1 de User tipini cagirdigimda hata aliyorum. Cunku user1 icinde sadece name kullandim ve diger tipleri cagirmadim. Yukarida bahsetmistik boyle bir durumda tip icindeki degerin sonuna soru isareti koyarak age?: number bu deger optional yapabiliyorduk.

interface User {
name: string,
age: number,
lastname: string,
idno: number,
}
const user1 : User = {
name: "Veli",
}

Peki ama User tipindeki tum elemanlara ? isareti eklemek yerine baska bir cozum var mi? Evet Partial kullanmak;

interface User {
name: string,
age: number,
lastname: string,
idno: number,
}
const user1 : User = {
const user1 : Partial<User> = {
name: "Veli",
}

Required kullanimi;

Required ise Partial’in tam tersini yapar. Yani soru isareti ile optional yapilmis tum tipleri zorunlu hale getirir. Asagidaki ornegi inceleyelim;

interface User {
name?: string,
age?: number,
lastname?: string,
idno?: number,
}
// Required kullanarak tum User tiplerini eklemeyi zorunlu hale getiriyoruz.
// Optional ozelligini kaldirmis oluyoruz.
const user1 : Required<User> = {
name: "Veli",
age: 23,
lastname: "Metin",
idno: 234234,
}

Readonly kullanimi;

Bir veriyi sadece okunabilir hale getirir. Data tekrar degistirilemez.

interface User {
name?: string,
age?: number,
lastname?: string,
idno?: number,
}
const user1 : Readonly<User> = {
name: "Veli",
}
// user1.name = "Ali"
// artik name datasini degistirmek mumkun degil
console.log(user1.name);

Pick ve Omit kullanimi;

Pick sadece belirttigimiz degiskeni almak icin kullanilir Omit ise tam tersini yapar ve belirttigimiz tipin disindakileri alir.

pick.ts
interface User {
name: string,
age: number,
lastname: string,
idno: number,
}
// Pick sadece name aldik ve option olmamasina karsin yinede hata almadik
const user1 : Pick<User, "name"> = {
name: "Veli",
}
omit.ts
interface User {
name: string,
age: number,
lastname: string,
idno: number,
}
// Omit ile User'dan name disindakileri alabiliriz name artik tanimsiz
const user1 : Omit<User, "name"> = {
// name: "Veli", ts name adinda bir tip bulamiyor
age: 23,
lastname: "Veli",
idno: 12312,
}