Everyday Types

استفاده از انواع داده‌ های پرکاربرد در تایپ اسکریپت

The Primitives

سه تایپ string، number و boolean از همه متداول تر اند و در TypeScript و JavaScript یکسان هستند.

Array

برای تعریف آرایه‌ای از هر نوع مقدار استفاده می‌شود. انواع روش‌های تعریف تایپ از نوع آرایه:

// --- syntax 1
// ex: 1. array of numbers
let numbers: number[] = [1, 2, 3];
// ex: 2. array of strings
let names: string[] = ["Ali", "Reza"];

// --- syntax 2
// ex: 1. array of numbers
let numbers: Array<number> = [1, 2, 3];
// ex: 2. array of strings
let names: Array<string> = ["Ali", "Reza"];

Any

هرگز پیشنهاد نمی شود از این نوع استفاده کنید زیرا هر نوع داده ای را مجاز می کند و عملاً حضور TypeScript را بی تأثیر می‌کند. این نوع زمانی استفاده می شود که TypeScript نوع داده ای را تشخیص نمی دهد یا نوع داده مدنظر نامشخص است.

const chartConfig: any = {
  title: "Sales Chart",
  data: [10, 20, 30],
  colors: ["red", "green", "blue"],
  animation: true
};

oldChartLibrary(chartConfig);

اگر نوع متغیر را مشخص نکنید و تایپ اسکریپت هم نتواند نوعش را تخمین (infer) بزند، کامپایلر به‌طور پیش‌فرض آن را any در نظر می‌گیرد. برای جلوگیری از این اتفاق، گزینه زیر را در فایل tsconfig.json خود تنظیم کنید:

tsconfig.json
{
  "compilerOptions": {
    "noImplicitAny": true
  }
}

Type Annotations on Variables

زمانی که از var، const یا let برای تعریف متغیر استفاده می کنیم، می توانیم یک توضیح نوع به آن اضافه کنیم تا نوع متغیر به صورت کاملاً صریح مشخص شود.

// ex: 1. variable with number type
let age: number = 25;

// ex: 2. variable with string type
let name: string = "Sara";

// ex: 3. variable with boolean type
let isActive: boolean = true;

// ex: 4
let data: null = null;

// ex: 5
let value: undefined = undefined;

Function

تایپ اسکریپت این امکان را می‌دهد که نوع پارامتر ها و خروجی های توابع را مشخص کنیم.

Parameter Type Annotations

نوع هر پارامتر را می‌توانیم بعد از نام آن مشخص کنیم.

function greetUser(name: string): string {
  return `سلام ${name}! خوش آمدی.`;
}

در این تابع، ورودی name از نوع string تعریف شده. بنابراین تایپ اسکریپت انتظار دارد هنگام استفاده از تابع،آرگومان اول را از نوع string پاس دهیم.

Return Type Annotations

در تایپ اسکریپ می‌توانید نوع مقداری را که یک تابع برمی‌گرداند (return می‌کند)، بعد از پارامتر ها مشخص کنید.

function getFavoriteNumber(): number {
  return 26;
}

در اغلب موارد نیازی به تعریف نوع بازگشتی به صورت دستی نیست. چون خود تایپ اسکریپت به طور نوع خروجی را از روی مقدار return شده تشخیص(infer) می‌دهد.

چرا بعضی از برنامه‌نویسان نوع بازگشتی را می‌نویسند؟

  • برای مستندسازی بهتر کد
  • برای جلوگیری از تغییر ناخواسته‌ی نوع بازگشتی در آینده
  • یا صرفاً به‌عنوان سبک شخصی یا قراردادی در پروژه.

Functions Which Return Promises

مشخص کردن نوع توابعی که خروجی آن‌ها به صورت یک Promise است:

function fetchData(data: string): Promise<string> {
  return new Promise((resolve, reject) => {
    // Simulate a 2-second delay
    setTimeout(() => {
      if (data) {
        resolve(`داده دریافت شد: ${data}`);
      } else {
        reject(new Error("داده ورودی خالی است!"));
      }
    }, 2000);
  });
}

Anonymous Function

TypeScript می تواند نوع ورودی های تابع ناشناس را بسته به موقعیت مورد استفاده تشخیص دهد.

در مثال زیر، TypeScript نوع ورودی name را به دلیل اینکه names آرایه‌ای از رشته‌ها است و متد forEach هم قرار است که تک تک این رشته‌ها را به تابع ناشناس ارسال کند، تشخیص می‌دهد:

const names = ["Alice", "Bob", "Eve"];

// ex: 1
// Contextual typing for function - parameter s inferred to have type string
names.forEach(function(name) {
  console.log(name.toUpperCase());
});

// ex: 2
// Contextual typing also applies to arrow functions
names.forEach((name) => {
  console.log(name.toUpperCase());
});

Object Types

برای تعریف نوع یک Object کافی است ویژگی‌ها و نوع آنها را فهرست کنید.

در مثال زیر، نوع ورودی pt که یک Object است، در همان زمان تعریف نوشته شده است:

// --- syntax 1
function printCoord(pt: { x: number; y: number }) {
  console.log("The coordinate's x value is " + pt.x);
  console.log("The coordinate's y value is " + pt.y);
}
printCoord({ x: 3, y: 7 });

برای جدا کردن پراپرتی(property) می‌توان از ,(کاما) یا ;(سمی‌کالن) استفاده کرد(قرار دادن جدا کننده اختیاری است).

یکی دیگر از روش های تعیین نوع برای Object، استفاده از interface است.

interface Pt {
  x: number;
  y: number;
}

function printCoord(pt: Pt) {
  console.log("The coordinate's x value is " + pt.x);
  console.log("The coordinate's y value is " + pt.y);
}
printCoord({ x: 3, y: 7 });

Optional Property

برای ایجاد یک پراپرتی اختیاری، باید بعد از نام پراپرتی و قبل از :، علامت ? را قرار دهیم:

function printName(obj: { first: string; last?: string }) {
  // ...
}

// ex: 1
printName({ first: "Bob" });
// ex: 2
printName({ first: "Alice", last: "Alisson" });
function printName(obj: { first: string; last?: string }) {
  console.log(obj.last?.toUpperCase());
}

Union Type

تایپ اسکریپت این امکان را می‌دهد که با استفاده از عملگرها type جدیدی را از ترکیب type های موجود ساخت. یکی از ساده ترین و پرکاربرد ترین روش ها برای ترکیب type ها، union type(نوع ترکیبی) است.

Defining a Union Type

یک Union Type از دو یا چند type دیگر ساخته می‌شود و نشان می‌دهد که یک مقدار می‌تواند یکی از آن type ها باشد. وقتی یک متغیر از نوع union تعریف می‌شود، فقط می‌توان عملیات‌هایی روی آن انجام داد که برای هر یک از اعضای union قابل انجام باشد.

در مثال زیر ورودی id می‌تواند رشته‌ای یا عددی باشد. از متدهایی می‌توان استفاده کرد که هم برای نوع number و هم string در دسترس باشند.

function printId(id: number | string) {
  console.log("Your ID is: " + id);
}
// OK
printId(101);
// OK
printId("202");
// Error: Argument of type '{ myID: number; }' is not assignable to parameter of type 'string | number'.
printId({ myID: 22342 });

Working with Union

وقتی متغیری از نوع ترکیبی(union) دارید (مثل string | number)، مقدار ورودی می‌تواند هر یک از اعضای union باشد. اما تایپ اسکریپت فقط اجازه‌ی استفاده از عملیات‌هایی را می‌دهد که برای تمام اعضای آن union معتبر باشند.

در مثال زیر تایپ اسکریپت اجازه استفاده از متد toUpperCase را نمی‌دهد چون ممکن است ورودی عدد باشد نه یک رشته:

function printId(id: number | string) {
  console.log(id.toUpperCase());
  // Error: Property 'toUpperCase' does not exist on type 'string | number'.
  //          Property 'toUpperCase' does not exist on type 'number'.
}

برای حل این مشکل، باید نوع را محدود(narrow) کنید؛ یعنی به تایپ اسکریپت نشان دهید در هر بخش از کد، دقیقاً کدام نوع مدنظر شماست.

در مثال زیر، تایپ اسکریپت به‌طور خودکار متوجه می‌شود در شاخه‌ی if مقدار از نوع string و در else از نوع number است.

function printId(id: number | string) {
  if (typeof id === "string") {
    // In this branch, id is of type 'string'
    console.log(id.toUpperCase());
  } else {
    // Here, id is of type 'number'
    console.log(id);
  }
}

اگر تمام اعضای یک union دارای ویژگی مشترک باشند، می‌توانید مستقیماً از آن ویژگی استفاده کنید بدون اینکه type ها را محدود(narrow) کنید.

// Return type is inferred as number[] | string
function getFirstThree(x: number[] | string) {
  return x.slice(0, 3);
}