TypeScript'i Kullanmak

TypeScript, JavaScript kod tabanlarına tip tanımları eklemenin popüler bir yoludur. TypeScript,kullanıma hazır olarak JSX’i destekler ve projenize @types/react ve @types/react-dom ekleyerek tam React Web desteği alabilirsiniz.

Kurulum

Tüm üretim düzeyindeki React framework’leri, TypeScript kullanımını destekler. Kurulum için framework’e özel kılavuzu takip edin:

Mevcut Bir React Projesine TypeScript Ekleme

React’in tip tanımlamalarının en son sürümünü yüklemek için:

Terminal
npm install @types/react @types/react-dom

tsconfig.json dosyanızda aşağıdaki derleyici seçeneklerinin ayarlanması gerekir::

  1. dom, lib’e dahil edilmelidir (Not: Eğer lib seçeneği belirtilmemişse, dom varsayılan olarak dahil edilir).
  2. jsx geçerli seçeneklerden birine ayarlanmalıdır. Çoğu uygulama için preserve yeterli olacaktır. Eğer bir kütüphane yayımlıyorsanız, hangi değeri seçeceğiniz konusunda If you’re publishing a library, consult the jsx documentation başvurun.

React Bileşenleri ile TypeScript

Not

JSX içeren her dosya tsx dosya uzantısını kullanmalıdır. Bu, TypeScript’e bu dosyanın JSX içerdiğini belirten TypeScript’e özel bir uzantıdır.

React ile TypeScript yazmak, React ile JavaScript yazmaya çok benzer. Bir bileşenle çalışırken ana fark, bileşenin props’ları için tipler sağlayabilmenizdir. Bu tipler, doğruluk kontrolü yapmak ve editörlerde satır içi dokümantasyon sağlamak için kullanılabilir

Hızlı Başlangıç kılavuzundan MyButton bileşenini alarak, butonun title’ını tanımlayan bir tip ekleyebiliriz:

function MyButton({ title }: { title: string }) {
  return (
    <button>{title}</button>
  );
}

export default function MyApp() {
  return (
    <div>
      <h1>Uygulamama hoş geldiniz</h1>
      <MyButton title="Ben bir butonum" />
    </div>
  );
}

Not

Bu sandboxlar TypeScript kodunu çalıştırabilir, ancak tip denetleyicisini çalıştırmaz. Bu, TypeScript sandboxlar öğrenmek için değiştirebileceğiniz, ancak tip hataları veya uyarıları almayacağınız anlamına gelir. Tip denetimi almak için TypeScript Playground kullanabilir veya daha tam özellikli bir çevrimiçi sandbox kullanabilirsiniz.

Bu yerinde sözdizimi, bir bileşen için tipler sağlamanın en basit yoludur; ancak birkaç alan tanımlamaya başladığınızda karmaşık hale gelebilir. Bunun yerine, bileşenin prop’larını tanımlamak için bir interface veya type kullanabilirsiniz:

interface MyButtonProps {
  /** Butonun içinde görüntülenecek metin */
  title: string;
  /** Butonun etkileşime girilip girilemeyeceği */
  disabled: boolean;
}

function MyButton({ title, disabled }: MyButtonProps) {
  return (
    <button disabled={disabled}>{title}</button>
  );
}

export default function MyApp() {
  return (
    <div>
      <h1>Uygulamama hoş geldiniz</h1>
      <MyButton title="Ben devre dışı bırakılmış bir butonum" disabled={true}/>
    </div>
  );
}

Bileşeninizin props’larını tanımlayan tip, ihtiyaç duyduğunuz kadar basit veya karmaşık olabilir; ancak bunlar ya type ya da interface ile tanımlanmış bir nesne tipi olmalıdır. TypeScript’in nesneleri nasıl tanımladığını Nesne Tipleri bölümünde öğrenebilirsiniz, ayrıca birkaç farklı tipten birini alabilen bir prop tanımlamak için Birleşim Tipleri kullanmayı ve daha karmaşık kullanım senaryoları için Tiplerden tip Oluşturma kılavuzunu incelemeyi de düşünebilirsiniz.

Örnek Hooklar

@types/react’den gelen tip tanımlamaları, yerleşik Hooks için tipleri içerir, böylece bileşenlerinizde ek bir ayar yapmadan kullanabilirsiniz. Bu tipler, bileşeninizde yazdığınız kodu dikkate alacak şekilde tasarlanmıştır, bu nedenle çoğu zaman çıkarılan tipleralırsınız ve ideal olarak tipleri sağlama detaylarıyla ilgilenmeniz gerekmez.

@types/react paketindeki tip tanımlamaları, yerleşik Hook’lar için tipleri içerir; bu nedenle, bileşenlerinizde ek bir kurulum yapmadan bunları kullanabilirsiniz. Bu tipler, bileşeninizde yazdığınız kodu dikkate alacak şekilde tasarlanmıştır; bu sayede çoğu zaman çıkarımsal tipler elde edersiniz ve ideal olarak tipleri manuel olarak belirtmenize gerek kalmaz.

Yine de, Hook’lar için tip sağlamaya dair birkaç örneğe bakabiliriz.

useState

useState Hook’udeğerinin tipini belirlemek için başlangıç durumu olarak geçirilen değeri yeniden kullanacaktır. Örneğin:

// Infer the type as "boolean"
const [enabled, setEnabled] = useState(false);

Bu, enabled değişkenine boolean tipini atayacak ve setEnabled fonksiyonu ya bir boolean argümanı ya da bir boolean döndüren bir fonksiyon alacaktır. Eğer duruma açıkça bir tip sağlamak istiyorsanız, bunu useState çağrısına bir tip argümanı vererek yapabilirsiniz:

// Türü açıkça “boolean” olarak ayarlayın
const [enabled, setEnabled] = useState<boolean>(false);

Bu durumda çok faydalı değil, ancak bir tip sağlamanız gereken yaygın bir durum, bir birleşim tipiyle karşılaştığınızda ortaya çıkar. Örneğin, burada status birkaç farklı string değerinden biri olabilir

type Status = "idle" | "loading" | "success" | "error";

const [status, setStatus] = useState<Status>("idle");

Ya da, Durum yapılandırma ilkeleri bölümünde önerildiği gibi, ilgili durumu bir nesne olarak gruplandırabilir ve farklı olasılıkları nesne tipleri aracılığıyla tanımlayabilirsiniz:

type RequestState =
| { status: 'idle' }
| { status: 'loading' }
| { status: 'success', data: any }
| { status: 'error', error: Error };

const [requestState, setRequestState] = useState<RequestState>({ status: 'idle' });

useReducer

useReducer Hook’u, bir azaltıcı fonksiyon ve bir başlangıç durumu alan daha karmaşık bir Hook’tur. Azaltıcı fonksiyonun tipleri, başlangıç durumundan çıkarılır. useReducer çağrısına bir tip argümanı sağlayarak duruma bir tip verebilirsiniz, ancak genellikle tipi başlangıç durumuna ayarlamak daha iyidir:

import {useReducer} from 'react';

interface State {
   count: number
};

type CounterAction =
  | { type: "reset" }
  | { type: "setCount"; value: State["count"] }

const initialState: State = { count: 0 };

function stateReducer(state: State, action: CounterAction): State {
  switch (action.type) {
    case "reset":
      return initialState;
    case "setCount":
      return { ...state, count: action.value };
    default:
      throw new Error("Unknown action");
  }
}

export default function App() {
  const [state, dispatch] = useReducer(stateReducer, initialState);

  const addFive = () => dispatch({ type: "setCount", value: state.count + 5 });
  const reset = () => dispatch({ type: "reset" });

  return (
    <div>
      <h1>Sayacıma hoş geldiniz</h1>

      <p>Sayaç: {state.count}</p>
      <button onClick={addFive}>5 Ekle</button>
      <button onClick={reset}>Sıfırla</button>
    </div>
  );
}

TypeScript’i birkaç önemli yerde kullanıyoruz:

  • interface State reducer’ın durumunun yapısını tanımlar.
  • type CounterAction reducer’a gönderilebilecek farklı eylemleri tanımlar.
  • const initialState: State başlangıç durumu için bir tip sağlar ve ayrıca varsayılan olarak useReducer tarafından kullanılan tiptir.
  • stateReducer(state: State, action: CounterAction): State reducer fonksiyonunun argümanları ve dönüş değeri için tipleri belirler.

initialState’e tip ayarlamanın daha açık bir alternatifi, useReducer’a bir tip argümanı sağlamaktır:

import { stateReducer, State } from './your-reducer-implementation';

const initialState = { count: 0 };

export default function App() {
const [state, dispatch] = useReducer<State>(stateReducer, initialState);
}

useContext

useContext Hook’uverileri bileşen ağacında aşağıya doğru geçirebilmenin bir tekniğidir ve bu işlem için bileşenler üzerinden props geçirmeye gerek kalmaz. Bir sağlayıcı bileşeni oluşturarak ve genellikle bir alt bileşende değeri tüketmek için bir Hook oluşturarak kullanılır.

Context tarafından sağlanan değerin tipi, createContext çağrısına geçirilen değerden çıkarılır:

import { createContext, useContext, useState } from 'react';

type Theme = "light" | "dark" | "system";
const ThemeContext = createContext<Theme>("system");

const useGetTheme = () => useContext(ThemeContext);

export default function MyApp() {
  const [theme, setTheme] = useState<Theme>('light');

  return (
    <ThemeContext value={theme}>
      <MyComponent />
    </ThemeContext>
  )
}

function MyComponent() {
  const theme = useGetTheme();

  return (
    <div>
      <p>Güncel tema: {theme}</p>
    </div>
  )
}

Bu teknik, mantıklı bir varsayılan değeriniz olduğunda işe yarar — ancak bazen böyle bir değeriniz olmayabilir ve bu durumlarda null varsayılan değer olarak mantıklı görünebilir. Ancak, tip sisteminin kodunuzu anlayabilmesi için, createContext üzerinde açıkça ContextShape | null belirtmeniz gerekir.

Bu, bağlam tüketicileri için tipte | nullu ortadan kaldırmanız gerektiği sorununu doğurur. Önerimiz, Hook’un varlığını çalışma zamanında kontrol etmesi ve mevcut değilse bir hata fırlatmasıdır:

import { createContext, useContext, useState, useMemo } from 'react';

// Bu daha basit bir örnek, ama burada daha karmaşık bir nesne hayal edebilirsiniz.
type ComplexObject = {
kind: string
};

// Context, varsayılan değeri doğru bir şekilde yansıtmak için tipte `| null` ile oluşturulmuştur.
const Context = createContext<ComplexObject | null>(null);

// `| null` Hook’taki kontrol aracılığıyla kaldırılacaktır.
const useGetComplexObject = () => {
const object = useContext(Context);
if (!object) { throw new Error("useGetComplexObject must be used within a Provider") }
return object;
}

export default function MyApp() {
const object = useMemo(() => ({ kind: "complex" }), []);

return (
<Context value={object}>
<MyComponent />
</Context>
)
}

function MyComponent() {
const object = useGetComplexObject();

return (
<div>
<p>Mevcut nesne: {object.kind}</p>
</div>
)
}

useMemo

Not

React Compiler değerleri ve işlevleri otomatik olarak hafızaya alır ve manuel useMemo çağrılarına olan ihtiyacı azaltır. Derleyiciyi kullanarak hafızaya almayı otomatik olarak gerçekleştirebilirsiniz.

useMemo Hook’u, bir fonksiyon çağrısından elde edilen önbelleğe alınmış (memorized) bir değeri oluşturur veya yeniden erişir ve yalnızca ikinci parametre olarak verilen bağımlılıklar (dependencies) değiştiğinde fonksiyonu yeniden çalıştırır. Hook’un dönüş değeri, ilk parametredeki fonksiyonun dönüş değerinden türetilir (inferred). Daha net olmak için Hook’a bir type argument sağlayabilirsiniz.

// visibleTodos’un tipi, filterTodos’un dönen değerinden çıkarılır.
const visibleTodos = useMemo(() => filterTodos(todos, tab), [todos, tab]);

useCallback

Not

React Compiler otomatik olarak değerleri ve fonksiyonları memoizes ederek manuel useCallback çağrılarına olan ihtiyacı azaltır. Memoizasyonu otomatik olarak yönetmek için compiler’ı kullanabilirsiniz.

useCallback ikinci parametreye verilen bağımlılıklar aynı kaldığı sürece bir fonksiyona sabit bir referans sağlar. useMemo gibi, fonksiyonun tipi ilk parametredeki fonksiyonun dönüş değerinden türetilir ve Hook’a bir tip argümanı sağlayarak daha açık olabilirsiniz.

const handleClick = useCallback(() => {
// ...
}, [todos]);

TypeScript strict modunda çalışırken, useCallback kullanırken geri çağırma fonksiyonunuzun parametreleri için tip eklemeniz gerekir. Bunun nedeni, geri çağırma fonksiyonunun tipinin dönen değerden çıkarılmasıdır ve parametreler olmadan tip tam olarak anlaşılamaz.

Kod stil tercihinize bağlı olarak, callback’i tanımlarken aynı zamanda event handler için tipi belirtmek üzere React tiplerinden *EventHandler fonksiyonlarını kullanabilirsiniz:

import { useState, useCallback } from 'react';

export default function Form() {
const [value, setValue] = useState("Change me");

const handleChange = useCallback<React.ChangeEventHandler<HTMLInputElement>>((event) => {
setValue(event.currentTarget.value);
}, [setValue])

return (
<>
<input value={value} onChange={handleChange} />
<p>Value: {value}</p>
</>
);
}

Kullanışlı Tipler

@types/react paketinden gelen oldukça geniş bir tip seti vardır ve React ile TypeScript’in nasıl etkileşime girdiğini anladığınızda incelemeye değer. Bunları DefinitelyTyped’teki React klasöründe. bulabilirsiniz. Burada daha yaygın kullanılan birkaç tipi ele alacağız.

DOM Olayları

React’te DOM olaylarıyla çalışırken, olayın tipi genellikle olay işleyicisinden çıkarılabilir. Ancak, bir fonksiyonu olay işleyicisine geçirmek üzere ayırmak istediğinizde, olayın tipini açıkça belirtmeniz gerekir.

import { useState } from 'react';

export default function Form() {
  const [value, setValue] = useState("Beni değiştir");

  function handleChange(event: React.ChangeEvent<HTMLInputElement>) {
    setValue(event.currentTarget.value);
  }

  return (
    <>
      <input value={value} onChange={handleChange} />
      <p>Değer: {value}</p>
    </>
  );
}

React tiplerinde birçok olay tipi sağlanmıştır - tam listeye buradan ulaşabilirsiniz. Bu liste, DOM’daki en popüler olaylara.

Kullandığınız olay işleyici için tipi belirlerken, ilk olarak olay işleyicinin üzerine geldiğinizde görünen bilgiye bakabilirsiniz; bu, olayın tipini gösterecektir.

Bu listede yer almayan bir olayı kullanmanız gerekirse, tüm olaylar için temel tip olan React.SyntheticEvent tipini kullanabilirsiniz.

Children

Bir bileşenin children prop’unu tanımlamak için iki yaygın yol vardır. İlki, JSX içinde children olarak geçebilecek tüm olası tiplerini birleşimi olan React.ReactNode tipini kullanmaktır:

interface ModalRendererProps {
title: string;
children: React.ReactNode;
}

Bu, children için oldukça geniş bir tanımdır. İkinci yol ise, sadece JSX öğelerini ve JavaScript ilkel tipleri (string veya number gibi) içermeyen React.ReactElement tipini kullanmaktır:

interface ModalRendererProps {
title: string;
children: React.ReactElement;
}

Not: Çocukların belirli bir JSX türü olduğunu TypeScript ile tanımlayamazsınız; bu nedenle, sadece <li> çocuklarını kabul eden bir bileşeni tip sistemiyle tanımlayamazsınız.

React.ReactNode ve React.ReactElement örneklerini tip denetleyicisi ile birlikte bu TypeScript playground’ında görebilirsiniz.

Stil Propları

React’ta inline stiller kullanırken, style prop’una geçirilen nesneyi tanımlamak için React.CSSProperties kullanabilirsiniz. Bu tip, tüm olası CSS özelliklerinin birleşimidir ve style prop’una geçerli CSS özellikleri sağladığınızdan emin olmak ve düzenleyicinizde otomatik tamamlama almak için iyi bir yoldur.

interface MyComponentProps {
style: React.CSSProperties;
}

Daha Fazla Öğrenme

Bu rehberde, TypeScript’i React ile kullanmanın temelleri ele alındı, ancak öğrenilecek daha çok şey var. Dokümanlardaki bireysel API sayfaları, TypeScript ile nasıl kullanılacağına dair daha derinlemesine belgeler içerebilir.

Aşağıdaki kaynakları öneriyoruz: