Ana içeriğe geç

TypeScript Kullanımı

TypeScript, JavaScript kod tabanlarına tür tanımlamaları eklemekte popüler bir yöntemdir. Kutudan çıktığı gibi TypeScript JSX'i destekler ve projeye @types/react ve @types/react-dom ekleyerek tam React Web desteği alabilirsiniz.

  • React Bileşenleri ile TypeScript
  • Kancalarla yazma örnekleri
  • @types/react'den ortak türler`
  • Daha fazla öğrenme kaynakları

Kurulum {/installation/}

Tüm üretim kalitesindeki React çerçeveleri TypeScript kullanımı için destek sunar. Kurulum için çerçeveye özel kılavuzu izleyin:

Var olan bir React projesine TypeScript ekleme {/adding-typescript-to-an-existing-react-project/}

React'in tür tanımlamalarının son sürümünü yüklemek için:

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

tsconfig.json dosyanızda aşağıdaki derleyici seçeneklerini ayarlamanız gerekmektedir:

  1. dom lib içinde bulunmalıdır (Not: Eğer lib seçeneği belirtilmezse, default olarak dom dahil edilir).
  2. jsx geçerli seçeneklerden birine ayarlanmalıdır. preserve çoğu uygulama için yeterli olmalıdır. Eğer bir kütüphane yayınlıyorsanız, ne tür bir değer seçeceğinize dair jsx belgelerine danışın.

React Bileşenleri ile TypeScript {/typescript-with-react-components/}

JSX bulunan her dosya .tsx uzantısını kullanmalıdır. Bu, TypeScript'in bu dosyanın JSX içerdiğini anlamasını sağlayan TypeScript'e özgü bir uzantıdır.

React ile TypeScript yazmak, React ile JavaScript yazmaya çok benzerdir. Bir bileşenle çalışmanın ana farkı, bileşeninizin prop'ları için türler sağlayabilmenizdir. Bu türler doğruluk kontrolü için ve editörlerde çevrimiçi belgeler sağlamak için kullanılabilir.

Hızlı Başlangıç kılavuzundaki MyButton bileşeni'ni alarak butonun title`'ını tanımlayan bir tür 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>
);
}
import AppTSX from "./App.tsx";
export default App = AppTSX;

Bu kumandalar TypeScript kodunu işleyebilir, ancak tür denetleyicisini çalıştırmaz. Bu, TypeScript kumandalarını öğrenmek için değiştirebileceğiniz anlamına gelir, ancak hiçbir tür hatası veya uyarısı almayacaksınız. Tür denetimi almak için TypeScript Playground kullanabilir veya daha kapsamlı bir çevrimiçi kumanda kullanabilirsiniz.

Bu çevrimiçi sözdizimi, bir bileşen için türler sağlamak için en basit yoldur, ancak tanımlamak için birkaç alana sahip olduğunuzda karmaşıklaşabilir. Bunun yerine, bileşenin prop'larını tanımlamak için bir interface veya type kullanabilirsiniz:

interface MyButtonProps {
/** Buton içinde görüntülenecek metin */
title: string;
/** Butona etkileşim yapılabilir mi */
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ışı bir butonum" disabled={true}/>
</div>
);
}
import AppTSX from "./App.tsx";
export default App = AppTSX;

Bileşeninizin prop'larını tanımlayan tür, ihtiyaç duyduğunuz kadar basit veya karmaşık olabilir, ancak bir type veya interface ile tanımlanmış bir nesne türü olmalıdır. TypeScript'in nesneleri nasıl tanımladığı hakkında daha fazla bilgi edinmek isterseniz Nesne Türleri ve bir prop'un birkaç farklı türden biri olabileceğini açıklamak için Birlik Türleri ve daha kapsamlı kullanım durumları için Türlerden Türler Oluşturma kılavuzuna göz atabilirsiniz.

Örnek Kancalar {/example-hooks/}

@types/react'ten gelen tür tanımlamaları, yerleşik Kancalar için türleri içerir, bu nedenle bileşenlerinizde ek bir kurulum olmadan bunları kullanabilirsiniz. Kullandığınız koda göre, çoğu zaman çıkarılan türler alırsınız ve ideal olarak türleri sağlama detaylarıyla uğraşmak zorunda kalmazsınız.

Ancak, Kancalar için tür sağlamanın birkaç örneğine bakalım.

useState {/typing-usestate/}

useState Kancası`, ilk durumda geçen değeri yeniden kullanarak değerin türünün ne olması gerektiğini belirleyecektir. Örneğin:

// Türü "boolean" olarak çıkar
const [enabled, setEnabled] = useState(false);

Bu, enabled için türü boolean atar ve setEnabled boolean argümanı alan veya boolean döndüren bir fonksiyon olarak tanımlanır. Eğer duruma açıkça bir tür sağlamak istiyorsanız, bunu useState çağrısına bir tür argümanı sağlayarak yapabilirsiniz:

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

Bu durumda çok faydalı değildir, ancak union türü olan bir duruma tür sağlamak istediğinizde yaygın bir durumdur. Örneğin, status burada birkaç farklı dizeden biri olabilir:

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

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

Veya, durum yapılandırmasını organize etme ilkeleri önerildiği gibi, ilişkili durumu bir nesne olarak gruplandırabilir ve farklı olasılıkları nesne türleri ile tanımlayabilirsiniz:

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

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

useReducer {/typing-usereducer/}

useReducer Kancası, bir azaltıcı fonksiyon ve bir başlangıç durumu alır. Azaltıcı fonksiyon için türler ilk durumdan çıkarılır. İsterseniz, useReducer` çağrısına bir tür argümanı sağlayarak duruma bir tür sağlayabilirsiniz, ancak genellikle türü 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("Bilinmeyen işlem");
}
}

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>Sayaç uygulamama hoş geldiniz</h1>

<p>Sayım: {state.count}</p>
<button onClick={addFive}>5 ekle</button>
<button onClick={reset}>Sıfırla</button>
</div>
);
}
import AppTSX from "./App.tsx";
export default App = AppTSX;

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

  • interface State, azaltıcının durumunun şeklini tanımlar.
  • type CounterAction, azaltıcıya iletilebilecek farklı eylemleri tanımlar.
  • const initialState: State, başlangıç durumu için bir tür sağlar ve ayrıca useReducer tarafından default olarak kullanılan türdür.
  • stateReducer(state: State, action: CounterAction): State, azaltıcı fonksiyonunun argümanları ve dönüş değeri için türleri ayarlar.

initialState üzerinde tür ayarlamanın daha açık bir alternatifi, useReducer'a bir tür 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 {/typing-usecontext/}

useContext Kancası`, verileri bileşen ağacında aşağı doğru iletmek için bir tekniktir; bileşenler aracılığıyla prop'ları iletmenize gerek kalmadan kullanılabilir. Bu, bir sağlayıcı bileşen oluşturarak ve genellikle bir çocuk bileşeninde değeri tüketmek için bir Kanca oluşturarak kullanılır.

Kapsayıcı tarafından sağlanan değerin türü, createContext çağrısına geçilen 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.Provider value={theme}>
<MyComponent />
</ThemeContext.Provider>
)
}

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

return (
<div>
<p>Geçerli tema: {theme}</p>
</div>
)
}
import AppTSX from "./App.tsx";
export default App = AppTSX;

Bu teknik, mantıklı bir varsayılan değere sahip olduğunuzda çalışır - ancak bazen böyle bir değer yoksa, bu durumda varsayılan değer olarak null mantıklı olabilir. Ancak, tür sisteminin kodunuzu anlaması için createContext üzerinde açıkça ContextShape | null ayarlamanız gerekir.

Bu, kapsayıcı tüketiciler için | null ifadesini ortadan kaldırmanız gerektiği sorununu doğurur. Önerimiz, Kancanın varlığını runtime kontrol etmesi ve mevcut olmadığında bir hata fırlatmasıdır:

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

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

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

// `| null` ifadesi Kancadaki kontrol aracılığıyla kaldırılacak.
const useGetComplexObject = () => {
const object = useContext(Context);
if (!object) { throw new Error("useGetComplexObject, bir Sağlayıcı içinde kullanılmalıdır") }
return object;
}

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

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

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

return (
<div>
<p>Geçerli nesne: {object.kind}</p>
</div>
)
}

useMemo {/typing-usememo/}

useMemo Kancası, bir fonksiyon çağrısından bir hafızalı değerin oluşturulmasını/erişilmesini sağlar; yalnızca 2. parametrede belirtilen bağımlılıklar değiştiğinde fonksiyonu yeniden çalıştırır. Kancanın çağrılma sonucu, ilk parametredeki fonksiyonun döndürdüğü değerden çıkarılır. Kanca üzerinde bir tür argümanı sağlayarak daha açık olabilirsiniz.

// visibleTodos'ın türü filterTodos'un döndürdüğü değerden çıkar
const visibleTodos = useMemo(() => filterTodos(todos, tab), [todos, tab]);

useCallback {/typing-usecallback/}

useCallback ikinci parametrede geçirilen bağımlılıklar aynı kaldığı sürece bir fonksiyona sabit bir referans sağlar. useMemo gibi, fonksiyonun türü ilk parametredeki fonksiyonun döndürdüğü değerden çıkarılır ve Kanca'ya daha açık bir tür argümanı sağlayarak daha da açık olabilirsiniz.

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

TypeScript katı modunda çalışırken useCallback, geri çağırma içindeki parametrelere tür eklemeyi gerektirir. Bunun nedeni, geri çağırmanın türünün fonksiyonun dönüş değerinden çıkarılmasıdır ve parametreler olmadan tür tamamen anlaşılamaz.

Kod stili tercihinize bağlı olarak, geriye dönüş fonksiyonunu tanımlarken etkinlik işleyicisi türü ile birlikte sağlamak için React türlerindeki *EventHandler fonksiyonlarını kullanabilirsiniz:

import { useState, useCallback } from 'react';

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

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

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

Kullanışlı Türler {/useful-types/}

@types/react paketinden gelen oldukça geniş bir tür seti bulunmaktadır, React ve TypeScript'in nasıl etkileşime girdiğini anladıktan sonra göz atmaya değer. Bunları DefinitelyTyped'deki React klasöründe bulabilirsiniz. Burada daha yaygın türlerden birkaçını kapsayacağız.

DOM Olayları {/typing-dom-events/}

React'te DOM olaylarıyla çalışırken, olayın türü genellikle olay işleyicisinden çıkarılabilir. Ancak, bir etkinliği olay işleyicisine geçirmek için bir fonksiyonu dışa aktarmak istediğinizde, olayın türünü açıkça ayarlamanız gerekecektir.

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>
</>
);
}
import AppTSX from "./App.tsx";
export default App = AppTSX;

React türlerinde sağlanan birçok olay türü bulunmaktadır - tam liste burada bulunabilir ve bu liste DOM'daki en popüler olaylara dayanmaktadır.

Aradığınız türü belirlerken, kullandığınız olay işleyicisi için ipucu bilgilerine bakabilirsiniz; bu ipucu, olayın türünü gösterecektir.

Eğer bu listede yer almayan bir olayı kullanmanız gerekiyorsa, tüm olayların temel türü olan React.SyntheticEvent türünü kullanabilirsiniz.

Çocuklar {/typing-children/}

Bir bileşenin çocuklarını tanımlamanın iki yaygın yolu vardır. İlk yol, JSX'te çocuk olarak geçirilebilecek tüm olası türlerin birleşimi olan React.ReactNode türünü kullanmaktır:

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

Bu, çocuklar için çok geniş bir tanımdır. İkinci yol ise, yalnızca JSX öğeleri içeren React.ReactElement türünü kullanmaktır, bu da JavaScript ilkel türlerini (string veya number gibi) içermez:

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

Dikkat edilmesi gereken nokta; TypeScript'i kullanarak çocukların belirli bir türde JSX öğeleri olduğunu tanımlayamazsınız. Bu nedenle, yalnızca `` çocuklarını kabul eden bir bileşeni tanımlamak için tür sistemini kullanamazsınız.

React.ReactNode ve React.ReactElement türlerinin tür denetleyicisinde nasıl çalıştığını görmek için bu TypeScript playground örneğine bakabilirsiniz.

Stil Props {/typing-style-props/}

React'te satır içi stiller kullanırken, style prop'una geçirilen nesneyi tanımlamak için React.CSSProperties kullanabilirsiniz. Bu tür, tüm olası CSS özelliklerinin birleşimidir ve style prop'una geçerli CSS özellikleri geçirdiğinizden emin olmak için iyi bir yoldur ve editörünüzde otomatik tamamlama sağlar.

interface MyComponentProps {
style: React.CSSProperties;
}

Daha Fazla Öğrenme {/further-learning/}

Bu kılavuz, TypeScript'i React ile kullanmanın temellerini kapsadı, ancak öğrenilecek çok daha fazla şey var. Belgelerdeki bireysel API sayfaları, bunları TypeScript ile nasıl kullanacağınız konusunda daha derinlemesine belgeler içerebilir.

Aşağıdaki kaynakları öneriyoruz: