TypeScript bilan React — props, hooks, events, children tiplari

~25 daq · TypeScript · Modullar, Sozlash va Amaliy

React da TypeScript eng ko'p ishlatilishi — props, hooks va event handlerlar uchun. Bu darsda amalda kerak bo'lgan barcha asosiy pattern lar.


Props tipizatsiyasi

// interface yoki type — ikkalasi ishlaydi, interface afzalroq
interface ButtonProps {
  matn:       string;
  variant?:   "primary" | "secondary" | "danger";
  boldi:      boolean;
  onClick:    () => void;
}

function Button({ matn, variant = "primary", boldi, onClick }: ButtonProps) {
  return (
    <button
      disabled={boldi}
      className={`btn btn-${variant}`}
      onClick={onClick}
    >
      {matn}
    </button>
  );
}

children

import { ReactNode } from "react";

interface CardProps {
  sarlavha: string;
  children: ReactNode; // har qanday React element
}

function Card({ sarlavha, children }: CardProps) {
  return (
    <div className="card">
      <h2>{sarlavha}</h2>
      {children}
    </div>
  );
}

ReactNode — matn, element, massiv, null — hammasi.


useState tipizatsiyasi

import { useState } from "react";

// Qiymatdan tur aniqlanadi
const [son, setSon]     = useState(0);           // number
const [matn, setMatn]   = useState("");           // string
const [faol, setFaol]   = useState(false);        // boolean

// Aniq ko'rsatish — null bo'lishi mumkin
const [user, setUser]   = useState<User | null>(null);

// Ob'ekt
const [forma, setForma] = useState<{ ism: string; email: string }>({
  ism: "", email: ""
});

useRef tipizatsiyasi

import { useRef } from "react";

// DOM element uchun
const inputRef  = useRef<HTMLInputElement>(null);
const divRef    = useRef<HTMLDivElement>(null);

// O'zgaruvchan qiymat uchun (mutable)
const timerRef  = useRef<NodeJS.Timeout | null>(null);

// Ishlatish
<input ref={inputRef} />
inputRef.current?.focus(); // optional chaining — null bo'lishi mumkin

Event handler tipizatsiyasi

import { ChangeEvent, FormEvent, MouseEvent } from "react";

function Forma() {
  const [qiymat, setQiymat] = useState("");

  const onChange = (e: ChangeEvent<HTMLInputElement>) => {
    setQiymat(e.target.value);
  };

  const onSubmit = (e: FormEvent<HTMLFormElement>) => {
    e.preventDefault();
    // ...
  };

  const onClick = (e: MouseEvent<HTMLButtonElement>) => {
    console.log(e.currentTarget.textContent);
  };

  return (
    <form onSubmit={onSubmit}>
      <input onChange={onChange} value={qiymat} />
      <button onClick={onClick}>Yuborish</button>
    </form>
  );
}

Generic komponent

interface RoYxatProps<T> {
  elementlar: T[];
  kalit:      (el: T) => string | number;
  render:     (el: T) => ReactNode;
}

function RoYxat<T>({ elementlar, kalit, render }: RoYxatProps<T>) {
  return (
    <ul>
      {elementlar.map(el => (
        <li key={kalit(el)}>{render(el)}</li>
      ))}
    </ul>
  );
}

// Ishlatish
<RoYxat
  elementlar={users}
  kalit={u => u.id}
  render={u => <span>{u.ism}</span>}
/>

FC vs funksiya

import { FC, ReactNode } from "react";

// FC — React.FunctionComponent, children bilan (eski usul)
const Button: FC<ButtonProps> = ({ matn }) => <button>{matn}</button>;

// Zamonaviy — oddiy funksiya (afzalroq)
function Button({ matn }: ButtonProps) {
  return <button>{matn}</button>;
}

FC dan voz kechish sababi — FC avtomatik children qo'shardi (TypeScript 18+ da o'zgartildi).


Xulosa

// Props
interface Props { matn: string; onClick: () => void; }
function Comp({ matn, onClick }: Props) { ... }

// children
import { ReactNode } from "react";
interface Props { children: ReactNode; }

// useState
useState<User | null>(null)

// useRef
useRef<HTMLInputElement>(null)

// Event
(e: ChangeEvent<HTMLInputElement>) => e.target.value
(e: FormEvent<HTMLFormElement>) => e.preventDefault()
(e: MouseEvent<HTMLButtonElement>) => { ... }

Keyingi dars

61-dars: TypeScript bilan Node.js va Express — tiplar, middleware