TypeScript ilə Supabase İnteqrasiyası — Tam Tip Təhlükəsizliyi
Supabase + TypeScript ilə runtime xətaları unudun: avtomatik tip generasiyası, end-to-end type safety və real layihə nümunəsi ilə tam praktiki bələdçi.
TypeScript ilə Supabase İnteqrasiyası — Tam Tip Təhlükəsizliyi
Salam, developer dostlar! 👋
Bakıda son 2 ildə startup ekosistemi ciddi böyüyür. Kontakt Home-un e-commerce platformasından tutmuş, Bravo-nun loyalty sistemlərinə qədər — backend-də sürətli, ucuz və scalable həllər lazımdır. Firebase alternativləri arasında Supabase artıq ciddi oyunçudur: açıq mənbəli, PostgreSQL əsaslı, və ən əsası — TypeScript ilə mükəmməl işləyir.
Bu məqalədə sənə Supabase + TypeScript inteqrasiyasının tam yolunu göstərəcəm. Söhbət sadəcə any yazıb keçməkdən deyil — database-dən UI-a qədər tam tip təhlükəsizliyindən gedir.
Niyə Supabase? Niyə TypeScript?
Əvvəlcə rəqəmlərə baxaq:
- Supabase 2025-ci ildə 900,000+ aktiv layihəyə çatıb (rəsmi blog)
- TypeScript Stack Overflow 2025 sorğusunda ən çox sevilən dillərin 3-cüsüdür
- Bakıda TypeScript bilən developer üçün orta maaş 1800-3500 AZN arasıdır (LinkedIn və boss.az datası əsasında), sadəcə JavaScript bilənlərə nisbətən 20-30% yuxarı
Supabase sənə bunları verir:
- ✅ PostgreSQL database + real-time subscriptions
- ✅ Authentication (Google, GitHub, email)
- ✅ Storage (fayl yükləmə)
- ✅ Edge Functions (serverless)
- ✅ Avtomatik TypeScript tip generasiyası
Son punkt — bu məqalənin əsas mövzusudur.
Addım 1: Layihəni Qururuq
Supabase hesabı açıb yeni layihə yarat. Sonra terminal aç:
bashnpm create vite@latest my-app -- --template react-ts cd my-app npm install @supabase/supabase-js npm install supabase --save-dev
Supabase CLI ilə login ol:
bashnpx supabase login npx supabase init npx supabase link --project-ref YOUR_PROJECT_REF
Addım 2: Database Strukturu
Tutaq ki, Bakıda restoran sifariş sistemi qurursan. SQL ilə table yaradırıq:
sqlCREATE TABLE restaurants ( id UUID DEFAULT gen_random_uuid() PRIMARY KEY, name TEXT NOT NULL, cuisine TEXT NOT NULL, rating NUMERIC(2,1) CHECK (rating >= 0 AND rating <= 5), district TEXT NOT NULL, -- Nəsimi, Yasamal, Səbail... created_at TIMESTAMPTZ DEFAULT now() ); CREATE TABLE orders ( id UUID DEFAULT gen_random_uuid() PRIMARY KEY, restaurant_id UUID REFERENCES restaurants(id), customer_name TEXT NOT NULL, total_azn NUMERIC(10,2) NOT NULL, status TEXT DEFAULT 'pending' CHECK (status IN ('pending','preparing','delivered','cancelled')), created_at TIMESTAMPTZ DEFAULT now() );
Addım 3: Avtomatik Tip Generasiyası ✨
Bax, sehrli hissə budur. Bir əmrlə bütün database strukturun TypeScript tiplərinə çevrilir:
bashnpx supabase gen types typescript --linked > src/types/database.ts
Bu əmr sənin üçün belə bir fayl yaradır:
typescript// src/types/database.ts (avtomatik generasiya olunub) export type Json = string | number | boolean | null | { [key: string]: Json } | Json[] export interface Database { public: { Tables: { restaurants: { Row: { id: string name: string cuisine: string rating: number | null district: string created_at: string } Insert: { id?: string name: string cuisine: string rating?: number | null district: string created_at?: string } Update: { id?: string name?: string cuisine?: string rating?: number | null district?: string created_at?: string } } orders: { Row: { id: string restaurant_id: string | null customer_name: string total_azn: number status: string | null created_at: string } Insert: { id?: string restaurant_id?: string | null customer_name: string total_azn: number status?: string | null created_at?: string } Update: { id?: string restaurant_id?: string | null customer_name?: string total_azn?: number status?: string | null created_at?: string } } } } }
Diqqət et: Row, Insert və Update ayrı-ayrı tipdirlər. Insert-də id optional-dır (database özü yaradır), Update-də isə hər şey optional-dır (yalnız dəyişən sahələri göndərirsən).
Addım 4: Typed Supabase Client
İndi client-i tiplə birlikdə yaradırıq:
typescript// src/lib/supabase.ts import { createClient } from '@supabase/supabase-js' import type { Database } from '../types/database' const supabaseUrl = import.meta.env.VITE_SUPABASE_URL const supabaseKey = import.meta.env.VITE_SUPABASE_ANON_KEY export const supabase = createClient<Database>(supabaseUrl, supabaseKey)
Bu bir sətirlik <Database> generic — hər şeyi dəyişir. Artıq bütün query-lərin tiplidir.
Addım 5: CRUD Əməliyyatları — Tam Type Safety
typescript// src/services/restaurant.ts import { supabase } from '../lib/supabase' import type { Database } from '../types/database' type Restaurant = Database['public']['Tables']['restaurants']['Row'] type NewRestaurant = Database['public']['Tables']['restaurants']['Insert'] // ✅ SELECT — nəticə avtomatik Restaurant[] tipindədir export async function getRestaurants(district?: string) { let query = supabase .from('restaurants') // ← autocomplete işləyir! .select('*') if (district) { query = query.eq('district', district) } const { data, error } = await query // data tipi: Restaurant[] | null if (error) throw error return data } // ✅ INSERT — yanlış sahə göndərsən, COMPILE vaxtı xəta verir export async function addRestaurant(restaurant: NewRestaurant) { const { data, error } = await supabase .from('restaurants') .insert(restaurant) .select() .single() if (error) throw error return data // tipi: Restaurant } // ✅ UPDATE — yalnız mövcud sahələri qəbul edir export async function updateRating(id: string, rating: number) { const { data, error } = await supabase .from('restaurants') .update({ rating }) // ← yalnız Restaurant['Update'] sahələri .eq('id', id) .select() .single() if (error) throw error return data } // ❌ BU COMPILE OLMAYACAQ: // supabase.from('restaurants').insert({ name: 'Test', price: 100 }) // Error: 'price' does not exist in type InsertRestaurant
Gördün? price deyə sahə yoxdur — TypeScript bunu runtime-dan əvvəl tutur. Production-da 3 gecə saat 3-də crash olmaqdansa, VSCode-da qırmızı xətt görmək daha yaxşıdır 😄
Addım 6: React Komponentdə İstifadə
typescript// src/components/RestaurantList.tsx import { useEffect, useState } from 'react' import { getRestaurants } from '../services/restaurant' import type { Database } from '../types/database' type Restaurant = Database['public']['Tables']['restaurants']['Row'] export function RestaurantList() { const [restaurants, setRestaurants] = useState<Restaurant[]>([]) const [loading, setLoading] = useState(true) useEffect(() => { getRestaurants('Nəsimi') .then(setRestaurants) .catch(console.error) .finally(() => setLoading(false)) }, []) if (loading) return <p>Yüklənir...</p> return ( <ul> {restaurants.map((r) => ( <li key={r.id}> {r.name} — {r.cuisine} — ⭐ {r.rating ?? 'N/A'} {/* r.price yazsaq → compile error! */} </li> ))} </ul> ) }
Pro Tip: CI/CD-yə Daxil Et
Database schema dəyişəndə tipləri yeniləməyi unutmamaq üçün bunu package.json-a əlavə et:
json{ "scripts": { "types:generate": "supabase gen types typescript --linked > src/types/database.ts", "build": "npm run types:generate && tsc && vite build" } }
Beləcə hər build-dən əvvəl tiplər yenilənir. Schema ilə kod heç vaxt sync-dən çıxmır.
Nəticə: Bu Niyə Vacibdir?
Bakıda işləyən bir çox startupda belə bir mənzərə görürəm: backend developer table-a yeni column əlavə edir, frontend developer xəbəri olmur, production-da undefined xətası çıxır, QA tapır, hotfix gedir... Bu dövranı tiplərlə qırmaq olar.
Supabase + TypeScript combo-su sənə bunları verir:
- 🔒 Database-dən UI-a qədər tam tip təhlükəsizliyi
- 🚀 Autocomplete — API docs-a baxmağa ehtiyac qalmır
- 🐛 Bug-ların 40%-i compile vaxtı tutulur (Microsoft-un TypeScript statistikası)
- 💰 Free tier — Supabase-in pulsuz planı 500MB database, 50,000 aktiv istifadəçi
Əgər Bakıda freelance işləyirsənsə, bir Supabase + Next.js + TypeScript stack ilə saytlar qurub layihə başına 800-2000 AZN qazana bilərsən. Stack sadədir, amma peşəkar görünür.
Tiplərinizi generasiya edin, any-dən uzaq durun, və production-da gecə rahat yatın. 🚀
Sualın var? Kommentdə yaz, ya da Telegram qrupumuza qoşul.
Oxşar məqalələr
Zod ilə TypeScript Runtime Validasiyası: Bugları Production-da Deyil, Əvvəlcədən Tut
TypeScript compile-time-da tip yoxlayır, amma runtime-da API-dən gələn datanı kim yoxlayacaq? Zod ilə validasiyanı necə həll edəcəyini real nümunələrlə göstərirəm.
TypeScript ilə Supabase inteqrasiyası — tam tip təhlükəsizliyi
Supabase + TypeScript birlikdə işlədəndə runtime xətaları minimuma enir. Database-dən gələn hər sətir tipli olur. Necə? Bu məqalədə.
TypeScript Generics — Nədir, Niyə Lazımdır, Necə İstifadə Olunur?
TypeScript generics-i başa düşmək Bakıda frontend və backend vakansiyaların 70%-ində tələb olunan skilldir. Bu bələdçi ilə generics-i bir dəfəlik öyrən.