TS in React

Install#

برای استفاده از ts می توان از دستورات زیر برای ساخت یک پروژه پیکربندی شده با ts استفاده کرد:

npx create-react-app my-app --template typescript
# or
yarn create react-app my-app --template typescript

یا اگر پروژه ما از قبل ساخته شده است و می خواهیم ب آن ts را اضافه کنیم، می توان از پکیج های زیر استفاده کنیم:

npm install --save typescript @types/node @types/react @types/react-dom @types/jest
# or
yarn add typescript @types/node @types/react @types/react-dom @types/jest

🎉 همچنین باید دقت داشت ک بعد از نصب پکیج ها باید تمام فایل های js و jsx را ب ts و tsx تبدیل کنیم و یکبار پروژه را resetکنیم.

🎉 همچنین باید حواسمان باشد ک بعد از تغییر فرمت فایل ها، حال باید تایپ ها را در پروژه درست کنیم و پارامتر ها، آرگومان ها و خیلی موارد دیگر را تایپ دهی کنیم.

Tips#

🎉 بعضی از پکیج هایی ک در پروژه های ts نصب می کنیم، باید ب صورت جداگانه حتما type های آن را نیز نصب کنیم وگرنه ب ارور می خوریم، مثل نمونه پایین:

yarn add react-helmet
# and
yarn add @types/react-helmet -D

props#

می توان به صورت زیر کامپوننت و prop ها در tsx استفاده کرد، در واقع در این روش می توان هم برای prop و هم برای کامپوننت type مشخص کرد:

interface ChildProps {
color: string;
onClick: (msg: string) => void;
}
export const Child = ({color, onClick}: ChildProps) => {
return (
<div>
<h1>{color}</h1>
<button onClick={() => onClick("first")}>Click me</button>
</div>
)
}
Child.defaultProps = {
color: "blue"
}
export const ChildAsFC: React.FC<ChildProps> = ({color, onClick}) => {
return (
<div>
<h1>{color}</h1>
<button onClick={() => onClick("second")}>Click me</button>
</div>
)
};
ChildAsFC.defaultProps = {
color: "green"
}

که روش دوم بهتر است زیرا ts متوجه کامپوننت می شود.

🎉 برای استفاده از children در tsx بهتر است از روش دوم استفاده شود زیرا ts کامپوننت را می شناسد، در روش اول باید حتما در interface حتما children را تعریف کنیم.

state#

برای تعریف type برای state ها میتوان به صورت زیر عمل کرد و برای هر useState از یک generic خاص استفاده کرد:

const GuestList: React.FC = () => {
const [name, setName] = useState("");
const [guests, setGuests] = useState<string[]>([]);
const onClick = () => {
setGuests([...guests, name]);
setName("");
}
}

🎉 اگر این کار را انجام ندهیم، خود ts برای متغییری مثل guests از تایپ []never استفاده می کند

Union#

در react هم می توان از union تایپ ها نیز استفاده کرد ک بسیار کاربردی می باشد، زمانی ک بخواهیم مشخص کنیم ک یک متغییر امکان دارد ک چند تایپ داشته باشد، از آن استفاده می کنیم:

const [user, setUser] = useState<{ name: string, age: number | undefined }>()

event#

برای اینکه از event در توابع خود استفاده کنیم، باید حتما تایپ را برای آن ها نیز مشخص کنیم:

const EventComponent: React.FC = () => {
const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
console.log(e)
}
const onDragStart = (e: React.DragEvent<HTMLDivElement>) => {
console.log(e)
}
return (
<div>
<input onChange={onChange}/>
<div draggable onDragStart={onDragStart}>Drag Me!</div>
</div>
)}

🎉 برای راحتی کار، میتوان موس را روی event مورد نظر قرار داد و تایپ مربوط به آن را کپی کنیم و در تابع خود استفاده کنیم.

ref#

برای ref نیز باید تایپ تگی که به آن رفرنس زدیم را مشخص کنیم و مقدار اولیه آن را null قرار دهیم، زیرا هنگام لود شدن، به چیزی رفرنس نمی شود:

const inputRef = useRef<HTMLInputElement | null>(null);

🎉 اگر در tsconfig.json بجای jsx: preserve یا jsx: react از jsx: react-jsx استفاده کنیم، دیگر نیازی ب import کردن react در همه کامپوننت ها نیست ( این قابلیت از ورژن 17 به بعد ب react اضافه شده است )

🎉 هرگاه بخواهیم در یک آبجکت در interface کاری کنیم ک بتوان ب صورت دلخواه، در جاهای مختلف از پراپرتی های مختلف استفاده کنیم، باید ب صورت زیر عمل کنیم:

export interface IRoutes {
path: string,
component: any,
layout: LayoutsEnum,
meta?: {
authRequired: boolean,
[propName: string]: unknown // propName is just a name
},
children?: IRouteChildren[]
}