Typescript bir uzantı dilidir. Kavram olarak Javascript Superseti olarak geçer. Yani var olan javascript koduna ek özellikler ve avantajlar ekler.Typescript, js e statik tür tanımları ekler.
Basitçe TypeScript kodun daha anlaşılır olması ve hataların engellenmesi için öncesinden değişkenlere verdiğimiz tip değerlerine göre kodun denetlenmesi ve kullanıcının uyarılmasını sağlayan mekanizmadır.
JavaScript, geliştiricilere büyük bir esneklik sağlar. Tamsayı olarak başlatılan bir değişkene, çalışma zamanında bir function değeri atanabilir. JavaScript’te değişken türleri tahmin edilemez. TypeScript, JavaScript dilinde yeni özellikler ve faydalı iyileştirmeler sunan bir JavaScript üst kümesidir. Kod tabanınızda TypeScript kullanarak, hataları erkenden kolayca tespit edebilir veya önleyebilir ve oldukça harika olan derleme zamanında hatalardan kurtulabilirsiniz. İlk bakışta TypeScript zor ve korkutucu görünebilir, ancak onunla biraz zaman geçirdikten sonra bence gerçekten seveceksiniz.
Büyük ekipler ile çalışırken, Backend ve API üzerinden veriler ile çalışırken Dinamik Tip (Dynamic Typing) bir dil geliştirmeler sırasında esnekliğinden dolayı birçok hataya yol açabilir. Bu nedenle çok dikkatli kullanılması gerekir.
Büyük projelerde herkesin bu dikkati göstermemesi, projeye sonradan dahil olan, veya JS konularına hakim olmayan geliştiricilerin projede oluşturabilecekleri hataları minimize etmek için TypeScript gibi Type güvenliği sağlayan diller kullanılır.
Örneğin; basit bir toplama kodumuz olsun. Bu değerleri ekrandan, bir Rest API’sinden alıyor olabiliriz. Biz sum fonskiyonun da 2 sayıyı toplamak isteyen bir kod yazmak isterken JS Dynamic Type bir dil olmasından dolayı String + Number toplamamıza izin veriyor. Bu izin hatalara yol açabiliyor. Ve biz bunu run time aşamasında farkedebiliyoruz.
let a = 5;
a = "Dynamic typing";
const a = 5;
a = "Dynamic typing";
//a değişkenini const ile tanınmladığımız için burada hata fırlatması lazım.
//Ama bu hatayı runtime da veriyor.
let a: number = 5;
a = "Dynamic typing";
// burada bize ts den ötürü hata fırlatıyor.
//Type ı number olan bir değişkene sen string atayamazsın şeklinde daha compile aşamasında bana hata veriyor.
Note: Tarayıcılar Typescript kodunu anlayamazlar. Bu yüzden bir derleyici yardımı ile TS kodu Js koduna dönüştürülür. (
tsc
=> typescript compiler)
Static type ihtiyacınız varsa.
//ts kodu
const a = "anthony";
const myName = `Name: ${a}`;
// js kodu
var a = "anthony";
var myName = "Name: ".concat(a);
// es5 te const olmadığı için var olarak compile etti.
//yine template string olmadığı için de diğer bir yöntem olan concat ı kullandı.
Pure typescript de targetı es5 olarak ayarlayıp Spread operatörünü deneyebilirsiniz:).
let x;
x="merhaba";
burada x in type ını ts any olarak atıyor.
Eğer değişkeni declare edip değerini sonra atayacaksak ve any tipinde olmasını istemiyorsak tanımladığımız yerde @typeannotations :type
kullanarak tipini de declare edebiliriz:
let x:string;
x="merhaba";
burada x in type ını string olarak belirlemiş olduk.
Ama değişkene değerini declare ederken değerinide vereceksek @typeannotations kullanmamıza gerek yok. Typescript değerin tipine göre değişkenimizin typeını belirliyor. TYPE INFERENCE
let x: string = "merhaba"; //yani buradaki işleme gerek yok
let y = "dünya";
//x vey yi ts string olarak belirliyor
let x: string = "merhaba";
let y = "dünya"; //Type Inference
// x ve y değişkenlerine artık sadece string veri tipinde bir değer ataması yapabiliriz.
let x: number = 67;
let y = 60.5; //Type Inference
// x ve y değişkenlerine artık sadece number veri tipinde bir değer ataması yapabiliriz.
let x: boolean = false;
let y = true; //Type Inference
// x ve y değişkenlerine artık sadece boolean veri tipinde bir değer ataması yapabiliriz.
let myArr: string[] = ["a","b","c"] //bu arraye atayacağınız elemanların hepsi string tipli olmalıdır.
let myArr1:number[] = [1,2,3] //bu arraye atayacağınız elemanların hepsi number tipli olmalıdır.
et myArr1:Array<number> = [1,2,3] //bu şekilde de arraylerde type tanımlaması yapabiliyoruz. Ama en yaygın kullanım diğer örneklerdeki gibi olan kullanım.
let myAnyArr : any[] = ["a",1,true] //bu arraye atayacağınız elemanlar farklı tiplerde olabilir. any diyerek aslında javascript arraye dönüştürmüş olduk.
let myArr: [string, number] = ["error", 25];
myArr = [285, 285]; // error
myArr = [34, "istanbul"]; // error
myArr = ["istanbul", 34]; // doğru kullanım
let a = "anthony";
let myName = `Name: ${a}`;
let x: any = 5;
a = x;
let y: unknown = 5;
myName = y; // Type 'unknown' is not assignable to type 'string'.
let todo = {
task: "deneme 1",
description: "deneme 1 deneme 1",
is_done: "false",
};
//bu şekilde tanımlama yaptığımzıda ts typeları belirliyor. ama diyelim değerlerimiz belli değil sadece değişkeni declare edeceğiz o zaman da:
let todo: {
task: string;
description: string;
is_done: boolean;
};
todo = {
task: "deneme 1",
description: "deneme 1 deneme 1",
is_done: "false",
}; // todo objesi sadece belirlediğimiz keyleri alabilir. Ve onlarında typeı yine sadece belirlenen tiplerde olur.
// Şimdilik bu şekilde objeyi declare edip tipini obje şeklinde verebiliriz. Ilerleyen aşamalarda obje tanımlamada en çok kullandığımız interfaceleri göreceğiz. Tabi ki type aliases ile de tanımlama yapabiliriz.
count:string | number
bu değişken string değer de alabilir, number değer de alabilir ikisinide kabul et. Örneğin; id bilgisi backendden number olarakta gelebilir veya string olarak da gelebilir. Kesin olarak bilmiyorsak union type kullanabiliriz.let todo: {
task: string;
description: string;
is_done: boolean;
count: string | number;
};
todo = {
task: "deneme 1",
description: "deneme 1 deneme 1",
is_done: "false",
count: 5,
};
todo.count = "5"; // hem number hem string değer atayabildik. Union type kullanarak `|` hata vermesinin önüne geçebildik.
let todo: {
task: string;
description: string;
is_done: boolean;
category: "work" | "travel";
};
todo.category = "enjoy"; // hata atar
todo.category = "work"; //kabul eder
todo.category = "travel"; //kabul eder
type Todo = {
task: string;
description: string;
is_done: boolean;
};
let todo: Todo = {
task: "deneme 1",
description: "deneme 1 deneme 1",
is_done: "false",
};
// custom typelı array
let todos: Todo[] = [
{
task: "deneme 1",
description: "deneme 1 deneme 1",
is_done: "false",
},
{
task: "deneme 2",
description: "deneme 2 deneme 2",
is_done: "false",
},
];
Custom typelar compile edildiğinde js dosyadında yer almazlar. Typescripte özeldirler.
void : Bir şeyi yapmasını istediğimiz methodlara void operasyon denir. Örneğin veritabanına veri ekle gibi. Emir kipi gibi düşünülebilir.Herhangi bir veri döndürmezler.
const myfunc = (num1: number, num2: number): number => {
return num1 + num2;
};
//void
const myfuncs = (num1: number, num2: number): void => {
console.log(num1 + num2);
};
//Type Inference
const myfunc = (num1: number, num2: number) => {
return num1 + num2;
};
//void
const myfunc = (num1: number, num2: number) => {
console.log(num1 + num2);
};
?
kullanabiliriz:type Todo = {
task: string;
description?: string; //description olsa da olur olmasada olur diyoruz.
is_done: boolean;
};
let todo: Todo = {
task: "deneme 1",
description: "deneme 1 deneme 1",
is_done: "false",
};
let todo2: Todo = {
task: "deneme 1",
is_done: "false",
};
// iki tanımlamada başarılı bir şekilde gerçekleşir.
interface Course {
title: string;
description: string;
createdAt: Date;
updatedAt: Date;
price: number;
currency: string;
isActive: boolean;
}
const webCourse: Course = {
title: "Typescript Basics",
description: "A course about Typescript",
createdAt: new Date(),
updatedAt: new Date(),
price: 1500,
currency: "USD",
isActive: true,
};
?
kullanarak değerin kullanımını isteğe bağlı olduğunu belirtebilirsiniz veya undefined
ekleyerek de bu özelliği kullanabiliriz.interface Course {
title: string;
description: string;
createdAt: Date;
updatedAt: Date;
price?: number; //Optional
currency: string | undefined; //Optional
isActive: boolean;
}
const webCourse: Course = {
title: "Typescript Basics",
description: "A course about Typescript",
createdAt: new Date(),
updatedAt: new Date(),
isActive: true,
};
interface Course {
title: string;
description: string;
createdAt: Date;
updatedAt: Date;
price?: number; //Optional
currency: string | undefined; //Optional
isActive: boolean;
}
interface NewCourse extend Course {
instructor:string
}
let mycourse: NewCourse = {
title: "Typescript Plus",
description: "A course about Typescript",
createdAt: new Date(),
updatedAt: new Date(),
price: 2000,
currency: "USD",
isActive: true,
instructor: "anthony",
};
//Burada görebileceğiniz gibi, bir NewCourse ve Course tanımladık. NewCourse, Course interface’ini kullanmamıza izin verir.
Interfaces, JavaScript nesnelerinin alabileceği çok çeşitli şekilleri tanımlayabilir. Interface, bir object’i özelliklerle tanımlamanın yanı sıra, function türlerini de tanımlama yeteneğine sahiptir.
TypeScript’de interface kavramı, Javascript’deki, genişletilebilirliği sağlayan en esnek yapı. Normalde Javascript’de interface kavramı bildiğiniz üzere yok. Dolayısıyla type-safe bir yapı oluşturmak, doğası gereği zor. TypeScript’de ki interface’ler temel olarak bu zorluğu ortadan kaldırmak için geliştirilmiş diyebiliriz.
TypeScript’deki interface, temelinde bir tip tanımından başka birşey değildir. class ve function‘lar nesnelerin davranışlarını tanımlarken, interface‘ler nesnelerin tiplerini tanımlar şeklinde düşünebiliriz. Javascript’de interface kavramı olmadığı için TypeScript’de bir interface tanımladığınız ve compile ettiğiniz zaman, onun bir Javascript kodu üretmediğini görürsünüz. Bu noktada interface’lerin compile zamanında tipleri tanımladığını ve geliştirme aşamasında da kolaylık sağladığını belirtmek isterim.
readonly: Bir object oluşturdunuz diyelim ve daha sonra bir özelliğinin değerinin değiştiilmesini istemiyorsunuz o zaman o özelliğ readonly tanımlası yaparak bunu sağlayabilirsiniz.Bunu tanımladıktan sonra değeri değiştirmeye çalışırsanız, readonly sayesinde derleyici bir hata verecektir:
interface Course {
readonly title: string; //Read only
description: string;
createdAt: Date;
updatedAt: Date;
price?: number; //Optional
currency: string | undefined; //Optional
isActive: boolean;
}
interface FootballCourse extends Course {
coach: string;
}
Aşağıdaki kullanım hata verecektir:
const webCourse: FootballCourse = {
title: "Typescript Basics",
description: "A course about Typescript",
createdAt: new Date(),
updatedAt: new Date(),
isActive: true,
coach: "Nicky Christensen",
};
webCourse.title = "A new title"; //ERROR. Çünkü readonly field oalrak tanımladık. İlk atamadaki değeri alır onu korur.
interface auth {
id: number;
username: string;
}
interface Category {
id: number;
title: string;
}
interface Post {
id: number;
title: string;
desc: string;
exttra: auth[] | Category[];
}
///Buraya kadar bildiiğimiz İnterface
interface PostBetter<T> {
id: number;
title: string;
extra: T[];
}
//Burada <T> ile gördüğünüz bize bir parametre döndürmemizi istiyor >> Type Parameter
const testGenerics: PostBetter<String> = {
// Burada o Beklediği Type Parametreyi giriyoruz <String> olarak
id: 1,
title: "Big Titlle",
extra: ["extra1", "extra2"], // Burada tanımlamamız bu şekilde
};
interface UpgradePostWithObject<T extends Object> {
id: number;
title: string;
extra: T[];
}
const test2Generics: UpgradePostWithObject<{ id: number; username: string }> = {
id: 1,
title: "Big Titlle",
extra: [{ id: 1, username: "taha" }],
}; // Burada Obje çağırdık çüngü UpgradePotWithObject interface kısmıbnda T nin üzerine bir de obje ekle dedik
let myAge;
myAge = 29;
const newAge = (<string>myAge).toLowerCase();
const newAge2 = (myAge as string).toLowerCase();
//tsyi susturyoruz ama runtime aşamasında hata döner.çünkü numberın toLowerCase metodu yoktur.
`npx tsc --init`
# bu komutla birlikte tsconfig.json dosyası oluşur. Sonrasında app.ts de yazdığımız kodların js e dönüşmesi için aşağıdaki komutu gireriz:
`tsc app.ts`
# Bu komutton sonra bize otomatik olarak aynı isimde js dosyası oluşturur. Biz index.html e oluşan app.js dosyasını bağlamamız gerekir.her yeni işlemde terminale girmem gerekiyor.
`tsc app.ts -w`
# watch moduna alıp her yaptığım işlemi anında compile eder.
npx create-react-app todo-ts --template typescript
#or
yarn create react-app todo-ts --template typescript
Command => pnpm create vite or yarn create vite
Framework => React
Variant => Typescript
# or
pnpm create vite todoapp --template react-ts
function Card(props: { children: React.ReactNode }) {
return <button>{props.children}</button>;
}
// interface de kullanabiliriz
type CardProps = {
title: string;
};
function Card(props: CardProps) {
return <h1>{props.title}</h1>;
}
// with destructuring
function Card({ title }: ButtonProps) {
return <h1>{title}</h1>;
}
interface ICardProps = {
disabled?: boolean;
title: string;
};
function Card({ disabled = true, title }: ICardProps) {
return (
<div disabled={disabled}>
<h1>{title}</h1>
<button disabled={disabled}>Change</button>
</div>
);
}
import React from "react";
interface ICardProps = {
disabled?: boolean;
title: string;
};
const Card:React.FC<ICardProps> = ({ disabled = true, title }) => {
return (
<div disabled={disabled}>
<h1>{title}</h1>
<button disabled={disabled}>Change</button>
</div>
);
}
// ❌ Typescript her zaman initial değere string atadığınızda o statein string olduğunu bilir.
const [text, setText] = useState<string>("");
// ✅ Type Inference sayesinde primitive typelarda initia değer verdiğimizde type tanımlamıza ihtiyaç yok.
const [text, setText] = useState("");
type Todo = {
id: number;
text: string;
};
// ama non-primitive typelarda initial değere boş array veya obje verdiğimizde typeı tanımlamalıyız.
const [todos, setTodos] = useState<Todo[]>([]);
const [todos, setTodos] = useState<Todo[] | null>(null);
export const AddTodo = () => {
// initial değer varsa type tanımlamaya gerek yok
const myRef = useRef("");
// initial değer yoksa type tanımlamlanır
const yourRef = useRef<string>();
useEffect(() => {
myRef.current = "Random value!";
yourRef.current = "Random value!";
}, []);
return <div></div>;
};
// HTML elementleri ile kullanım
export const AddTodo = () => {
// hangi elemente tanımlayacaksak onu belirtiyoruz. İnitial değere de null atıyoruz.
const inputRef = useRef<HTMLInputElement>(null);
return <input ref={inputRef} />;
};
//ThemeContext.ts
import React,{ createContext, useState,useContext } from "react";
type ThemeContextType = "light" | "dark";
const ThemeContext = createContext<ThemeContextType | null>("light");
const ThemeContextProvider: React.FC = ({ children }:React.ReactNode) => {
const [myTheme, setMyTheme] = useState<ThemeContextType>("light");
return (
<ThemeContext.Provider value=>
{children}
</ThemeContext.Provider>
);
};
export const useThemeContext = () => {
return useContext(ThemeContext)
}
//index.tsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import ThemeContextProvider from './context/ThemeContext';
const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
);
root.render(
<ThemeContextProvider>
<App />
</ThemeContextProvider>
);
//App.tsx
import { useThemeContext } from "./context/ThemeContext";
const App = () => {
const {myTheme} = useThemeContext();
return <p>current theme: {myTheme}</p>;
};
Redux Toolkit Dökümanından ayrıntılı inceleyebilirsiniz.
//input-form examples
onChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
onSubmit: (event: React.FormEvent<HTMLFormElement>) => void;
onFocus: (event: FocusEvent<HTMLInputElement>) => void;
onBlur: (event: FocusEvent<HTMLInputElement>) => void;
//button-div examples
onClick: (event: React.MouseEvent<HTMLButtonElement>) => void;
onDoubleClick: (event: MouseEvent<HTMLDivElement>) => void;
onMouseEnter: (event: MouseEvent<HTMLButtonElement>) => void;
onMouseLeave: (event: MouseEvent<HTMLButtonElement>) => void;