آموزش تایپ اسکریپت

در این صفحه می خوانید :

معرفی تایپ اسکریپت

TypeScript یک زبان برنامه نویسی اوپن سورس است که توسط مایکروسافت نگهداری و توسعه داده می شود. تایپ اسکریپت یک superset syntactical از JavaScript است و تایپ استاتیک اختیاری را به زبان اضافه می کند. TypeScript برای توسعه برنامه های بزرگ و transcompiles به JavaScript طراحی شده است. از آنجا که TypeScript یک مجموعه از JavaScript است، برنامه های JavaScript موجود نیز دارای برنامه های TypeScript معتبر هستند. TypeScript ممکن است برای توسعه برنامه های JavaScript برای اجرای هر دو طرف کلاینت یا سمت سرور (مانند Node.js یا Deno) استفاده شود. گزینه های گوناگونی برای ارتباط وجود دارد. یا از Checker TypeScript پیش فرض استفاده می شود، یا می توان از کامپایلر Babel برای تبدیل TypeScript به JavaScript استفاده کرد.

TypeScript از فایل های توصیفی پشتیبانی می کند که می توانند حاوی اطلاعاتی از نوع کتابخانه های موجود JavaScript باشند، دقیقاً مانند فایل های هدر سی پلاس پلاس می توانند ساختار فایل های موجود را توصیف کنند. این قابلیت برنامه های دیگر را قادر می سازد از مقادیر تعریف شده در فایل ها استفاده کند. فایل های هدر شخص ثالث برای کتابخانه های محبوب مانند جی کوئری (JQuery)، مانگو دی بی (MongoDB) و دی تری جی اس (D3.js) وجود دارد. هدر TypeScript برای ماژول های اساسی Node.js نیز موجود است که امکان توسعه برنامه های نود جی اس (Node.js) را در TypeScript فراهم می کند.

از ابتدا جاوااسکریپت با رشد چشمگیر به ویژه در سال های اخیر روبرو شد. این زبان دامنه برنامه خود را به مراتب فراتر از مرورگر گسترش داده است. در حال حاضر با قدرت در Backend، برنامه های هیبریدی موبایل، راه حل های معماری ابر، طراحی شبکه های عصبی مصنوعی و حتی کنترل روبات ها استفاده می شود. همه کاره بودن و ویژگی های غنی جاوااسکریپت با نرخ پذیرش بالا باعث افزایش روز افزون تقاضا برای برنامه های جاوااسکریپت شده است. این به نوبه خود نیاز به ابزار، کتابخانه ها و فریمورک هایی را ایجاد کرده است. این تقاضا برای عملکرد با کیفیت بالا، قابلیت نگهداری و جاوااسکریپت قوی باعث معرفی TypeScript شد.

Anders Hejlsberg، معمار برجسته سی شارپ و خالق دلفی و Turbo Pascal، روی توسعه TypeScript کار کرده است.

تاریخچه تایپ اسکریپت

ابتدا در اکتبر 2012 پس از دو سال توسعه داخلی در مایکروسافت به صورت عمومی در نسخه (0.8) منتشر شد. در سال 2013 نسخه (0.9) منتشر شد که پشتیبانی از Generic ها را اضافه کرد. در کنفرانس توسعه مایکروسافت در سال 2014 نسخه 1.0 منتشر شد. ویژوال استودیو 2013 به روز رسانی 2 پشتیبانی TypeScript را فراهم می کند. در ژوئیه 2014 تیم توسعه یک کامپایلر TypeScript جدید را اعلام کرد که 5 برابر عملکرد بیشتر را ادعا می کرد. همزمان، کد منبع، که ابتدا در CodePlex میزبانی می شد به گیت هاب (GitHub) منتقل شد و در سال 2016 نسخه 2.0 منتشر شد. در حال حاضر نسخه 3.4 در دسترس می باشد.

معماری تایپ اسکریپت

TypeScript از کاستی های JavaScript برای توسعه برنامه های بزرگ در مایکروسافت و همچنین در بین مشتریان خارجی آنها نشأت گرفته است. چالش های مواجهه با کد پیچیده JavaScript منجر به تقاضا برای ابزارهای سفارشی برای سهولت در توسعه اجزاء در زبان شد.

توسعه دهندگان TypeScript به دنبال راه حلی بودند که نتواند سازگاری با استاندارد و پشتیبانی از سیستم متقابل آن را بشکند. با دانستن اینکه پیشنهاد استاندارد فعلی ECMAScript وعده حمایت آینده از برنامه نویسی مبتنی بر کلاس را دارد، TypeScript بر اساس این پیشنهاد بود. این امر به یک کامپایلر جاوااسکریپت با مجموعه ای از برنامه های افزودنی زبان نحوی منجر شد، یک Superset بر اساس این پیشنهاد، که پسوندها را به JavaScript معمولی تبدیل می کند. از این نظر TypeScript پیش نمایش آنچه در انتظار ECMAScript 2015 بود بود. یک جنبه منحصر به فرد که در پیشنهاد نیست بلکه به TypeScript اضافه شده است، تایپ استاتیک اختیاری است که تجزیه و تحلیل زبان استاتیک را قادر می سازد، که این امر باعث تسهیل ابزار و پشتیبانی از IDE می شود.

پشتیبانی از اکما اسکریپت (ECMAScript)

TypeScript پشتیبانی از ویژگی هایی مانند کلاس ها، ماژول ها و نحو عملکرد فلش را مطابق استاندارد ECMAScript 2015 تعریف می کند.

کامپایلر تایپ اسکریپت به نام tsc در TypeScript نوشته شده است. در نتیجه می توان آن را به جاوااسکریپت معمولی کامپایل و سپس در هر موتور جاوااسکریپت مانند مرورگر اجرا کرد. در پس زمینه اجرا، تمام کدهای TypeScript به کد جاوااسکریپت کامپایل شده و سپس توسط پلتفرم هدفش اجرا می شود. همچنین یک نسخه آلفای کامپایلر سمت سرویس گیرنده وجود دارد که پس از بارگذاری صفحه کد TypeScript را در مرورگر میزبان اجرا می کند. مرورگر هیچ اشاره ای به اینکه این کد کامپیال شده است ندارد و درست مانند جاوااسکریپت اجرا میکند. بنابراین هیچ سرباری بر روی برنامه ندارد.

ویژگی های تایپ اسکریپت

TypeScript یک برنامه افزودنی زبانی است که ویژگی هایی را به ECMAScript اضافه می کند. 6. ویژگی های اضافی شامل موارد زیر است:

  • نوشتن یادداشت ها و بررسی نوع compile-time
  • انواع اینترفیس
  • انواع erasure
  • اینترفیس ها
  • انواع شمارنده
  • ژنریک ها (Generics)
  • فضای نامی (Namespaces)
  • تاپل (Tuples)
  • Async/await

ویژگی های زیر از ECMAScript 2015 بازنویسی شده است:

  • کلاس ها
  • ماژول ها
  • سینتکس مختصر "arrow" برای توابع ناشناس
  • پارامترهای اختیاری و پارامترهای پیش فرض

از نظر نحوی، TypeScript بسیار شبیه به JScript .NET است، یکی دیگر از اجرای مایکروسافت استاندارد زبان ECMA-262 که به پشتیبانی از تایپ استاتیک و ویژگی های زبان کلاسیک شی گرا مانند کلاس ها، وراثت، رابط ها و مکان های نام اضافه می کند.

سازگاری با جاوااسکریپت

TypeScript یک مجموعه فوق العاده از ECMAScript 2015 است، که خود یک Superset از ECMAScript 5 است، که معمولاً به عنوان JavaScript خوانده می شود. به همین ترتیب، یک برنامه JavaScript نیز یک برنامه TypeScript معتبر است و یک برنامه TypeScript می تواند یکپارچه JavaScript را مصرف کند. به طور پیش فرض، کامپایلر ECMAScript 5، استاندارد رایج فعلی را هدف قرار می دهد، اما همچنین قادر به ساخت سازه های مورد استفاده در ECMAScript 3 یا 2015 است.

با TypeScript، می توانید از كدهای موجود JavaScript استفاده كنید، از كتابخانه های معروف JavaScript استفاده كنید و از كدهای ایجاد شده TypeScript از سایر JavaScript تماس بگیرید. اعلامیه های نوع برای این کتابخانه ها با کد منبع ارائه می شود.

انواع تفسیر

TypeScript تایپ استاتیک از طریق انواع تفسیر برای فعال کردن بررسی نوع در زمان کامپایل فراهم می کند. این اختیاری است و نمی توان از تایپ پویا منظم جاوااسکریپت استفاده کرد.

function add(left: number, right: number): number {
	return left + right;
}

انواع تفسیر برای انواع اولیه number، boolean و string است. ساختارهای ضعیف یا پویا از نوع any هستند.

انواع تفسیر را می توان به یک فایل اعلامی جداگانه اکسپورت کرد تا اطلاعات مربوط به نوع را برای اسکریپت های TypeScript با استفاده از انواع موجود در جاوااسکریپت در دسترس قرار دهد. همانطور که برای Node.js و jQuery انجام شده است، می توانید یادداشت ها را برای یک کتابخانه JavaScript موجود اعلام کنید.

کامپایلر TypeScript در صورت عدم ارائه انواع، از انواع اینترفیس استفاده می کند. به عنوان مثال، روش add در کد فوق به این نتیجه می رسد که یک number را برگرداند حتی اگر هیچگونه تفسیر از نوع بازگشت ارائه نشده باشد. این براساس انواع استاتیک numbers های left و right است و دانش کامپایلر مبنی بر این نتیجه است اضافه شدن دو numbers همیشه یک number است. با این حال، صریحا اعلام نوع بازگشت به کامپایلر اجازه می دهد تا صحت را بررسی کند.

اگر به دلیل عدم اعلام هیچ نوع استنباطی قابل استنباط نباشد، آن را به صورت پیش فرض از نوع پویا any قرار می دهد. مقدار از نوع any از همان عملیات به عنوان یک مقدار در جاوااسکریپت پشتیبانی می کند و حداقل بررسی نوع استاتیک برای عملیات روی هر مقدار انجام می شود.

فایل های اعلامی

هنگامی که یک اسکریپت TypeScript کامپایل می شود، گزینه ای برای تولید یک فایل اعلامیه (با پسوند .d.ts) وجود دارد که به عنوان واسط اجزای موجود در JavaScript کامپایل شده عمل می کند. در این فرآیند کامپایلر کلیه اجسام عملکرد و روش را از بین می برد و فقط امضاهای انواع صادر شده را حفظ می کند. سپس فایل اعلامیه حاصل می تواند برای توصیف انواع TypeScript مجازی صادر شده از یک کتابخانه یا ماژول JavaScript که یک توسعه دهنده شخص ثالث آن را از TypeScript مصرف می کند، استفاده شود.

مفهوم فایل های اعلامیه مشابه مفهوم فایل هدر موجود در C / C ++ است.

declare namespace arithmetics {
    add(left: number, right: number): number;
    subtract(left: number, right: number): number;
    multiply(left: number, right: number): number;
    divide(left: number, right: number): number;
}

فایل های اعلامیه نوع را می توان برای کتابخانه های موجود JavaScript نوشت، همانطور که برای jQuery و Node.js. انجام شده است. مجموعه های زیادی از فایل های اعلامیه برای کتابخانه های محبوب JavaScript در گیت هاب (GitHub) در DefinitelyTyped میزبان هستند.

کلاس ها (Classes)

TypeScript از کلاس های ECMAScript 2015 که انواع تفسیر اختیاری را ادغام می کند، پشتیبانی می کند.

class Person {
    private name: string;
    private age: number;
    private salary: number;

    constructor(name: string, age: number, salary: number) {
        this.name = name;
        this.age = age;
        this.salary = salary;
    }

    toString(): string {
        return `${this.name} (${this.age}) (${this.salary})`; // As of version 1.4
    }
}

ژنریک ها (Generics)

تایپ اسکریپت از برنامه نویسی ژنریک پشتیبانی می کند. موارد زیر مثالی از تابع identity است.

function doSomething<T>(arg: T): T {
    return arg;
}

ماژول ها و فضاهای نامی (namespaces)

TypeScript بین ماژول ها و namespaces تفاوت قائل می شود. هر دو ویژگی در TypeScript از کپسوله سازی کلاس ها، اینترفیس ها، توابع و متغیرها در کانتینر پشتیبانی می کنند. فضاهای نامی (ماژول های داخلی سابق) از عبارت تابعی immediately-invoked جاوااسکریپت برای کپسوله کردن کد استفاده می کنند، در حالی که ماژول ها (ماژول های خارجی) از الگوهای کتابخانه جاوااسکریپت بهره می گیرند (AMD یا CommonJS).

ابزار های توسعه تایپ اسکریپت

کامپایلر

کامپایلر TypeScript با نام tsc در TypeScript نوشته شده است. در نتیجه، می توان آن را به صورت منظم JavaScript وارد کرد و سپس در هر موتور JavaScript (به عنوان مثال یک مرورگر) قابل اجرا است. بسته کامپایلر با یک میزبان اسکریپت همراه است که می تواند کامپایلر را اجرا کند. همچنین به عنوان یک بسته Node.js در دسترس است که از Node.js به عنوان میزبان استفاده می کند.

همچنین یک نسخه آلفا از کامپایلر سمت مشتری در جاوا اسکریپت وجود دارد که کد TypeScript را در پرواز و با بارگذاری صفحه اجرا می کند.

نسخه فعلی کامپایلر به طور پیش فرض از ECMAScript 5 پشتیبانی می کند. گزینه ای برای هدف قرار دادن ECMAScript 2015 استفاده شده است تا از ویژگی های زبان منحصر به فرد برای آن نسخه استفاده شود (مثلاً تولید کنندگان). کلاس ها، با وجود اینکه جزئی از استاندارد ECMAScript 2015 هستند، در هر دو حالت در دسترس هستند.

IDE و ویرایشگر ها

امروزه پشتیبانی از دیگر IDE ها، به خصوص در اکلیپس (Eclipse)، از طریق یک افزونه توسط Palantir Technologies پشتیبانی می شود. TypeScript منحصر به فرد به انگولار جی اس (AngularJS) نیست و ویرایشگر های متنوع از جمله ایماکس (Emacs)،ویم (Vim)،Sublime،وب استرم (Webstorm)،Atom و ویژوال استودیو کد (Visual Studio Code) نیز از TypeScript پشتیبانی می کنند.

کاربرد تایپ اسکریپت

در شرایط زیر استفاده از TypeScript منطقی است:

وقتی یک کدبیس بزرگ دارید.

وقتی کدبیس شما بسیار بزرگ است و بیش از یک نفر روی پروژه کار می کند، یک سیستم نوع می تواند به شما در جلوگیری از خطاهای رایج کمک کند. این امر به ویژه در مورد برنامه های تک صفحه ای صادق است.

هر زمان که یک توسعه دهنده می تواند تغییرات شکنی را معرفی کند، به طور کلی خوب است که نوعی مکانیسم ایمنی داشته باشید. حمل و نقل TypeScript آشکارترین اشتباهات را آشکار می کند - اگرچه نیاز به اشکال زدایی را به طرز جادویی از بین نمی برد.

اگر پایه کد شما این همه بزرگ نیست، احتمالاً منطقی نیست با افزودن حاشیه نویسی از نوع، آن را بزرگتر کنیم. من 180 فایل را از جاوا اسکریپت به TypeScript تبدیل کرده ام و در اکثر موارد، تقریباً 30٪ به کل کد اضافه شده است.

هنگامی که توسعه دهندگان تیم شما از قبل به زبان های statically-typed آشنا است.

اگر شما یا اکثریت تیم از یک زبان کاملاً تایپ شده مانند سی شارپ یا جاوا استفاده می کنید و نمی خواهید در JavaScript همه کار کنید، TypeScript یک جایگزین خوب است.

هنگامی که یک کتابخانه یا فریمورک، تایپ اسکریپت را توصیه می کند.

اگر از Angular 2 یا کتابخانه دیگری استفاده می کنید که TypeScript را توصیه می کند، به دنبال آن بروید. فقط می دانید که - حتی اگر TypeScript می تواند از تمام کتابخانه های جاوا اسکریپت استفاده کند - اگر می خواهید خطاهای نحوی خوبی داشته باشید، باید توضیحات نوع آن کتابخانه ها را به صورت خارجی اضافه کنید. خوشبختانه بچه های خوب در DefinitelyTyped یک repo جامعه محور با ابزاری برای انجام همین کار ایجاد کرده اند. اما این هنوز یک قدم اضافی هنگام تنظیم پروژه است

چرا باید از تایپ اسکریپت استفاده کرد؟

  • TypeScript کد JavaScript را ساده می کند، خواندن و دیباگینگ را آسان تر می کند.
  • TypeScript ابزارهای تولیدی بسیار مؤثر را برای IDE ها و روش های JavaScript مانند بررسی استاتیک فراهم می کند.
  • TypeScript خواندن و درک کد را آسانتر می کند.
  • با TypeScript، می توانیم پیشرفت چشمگیری نسبت به JavaScript ساده داشته باشیم.
  • TypeScript تمام مزایای ECMAScript 6 را به همراه بهره وری بیشتر به ما می دهد.
  • TypeScript می تواند به ما کمک کند تا از خطاهایی که معمولاً برنامه نویسان هنگام نوشتن JavaScript با نوشتن کد استفاده می کنند، جلوگیری کنیم.
  • سیستم نوع قدرتمند، از جمله generics.
  • TypeScript چیزی جز JavaScript با برخی از ویژگی های اضافی نیست.
  • برای پشتیبانی از جدیدترین مرورگر، می توان کد TypeScript را طبق استاندارد ES5 و ES6 گردآوری کرد.
  • برای سازگاری با ECMAScript هماهنگ شد.
  • با JavaScript شروع و پایان می یابد.
  • تایپ استاتیک را پشتیبانی می کند.
  • TypeScript در زمان توسعه دهندگان صرفه جویی می کند.
  • TypeScript مجموعه ای از ES3،ES5 و ES6 است.

مقایسه تایپ اسکریپت و جاوااسکریپت

جاوااسکریپت (Javascript)

جاوااسکریپت زبان برنامه‌نویسی سطح بالا، پویا، مبتنی بر شی، چند رویه ای و تفسیری است. این زبان اغلب به عنوان بخشی از صفحات وب استفاده می شود که پیاده سازی آن ها به اسکریپت سمت کلاینت اجازه می دهد تا با کاربر ارتباط برقرار کرده و صفحات دینامیکی ایجاد کند. جاوااسکریپت زبان برنامه نویسی تفسیر شده با قابلیت های شی گرا است. Javascript زبان برنامه نویسی داینامیک اسکریپتی است که در کنار اچ تی ام ال و سی اس اس (CSS) یکی از مهم ترین عنصر فناوری های وب استاندارد به شمار می رود. جاوااسکریپت صفحات وب تعاملی را فعال می کند و جزئی اساسی در برنامه های وب است. اکثریت قریب به اتفاق وب سایت ها از آن استفاده می کنند و مرورگرهای اصلی وب برای اجرای آن از موتور جاوااسکریپت اختصاصی استفاده می کنند. این زبان هم به صورت ساخت یافته و هم به صورت شی گرا مورد استفاده برنامه نویسان قرار می گیرد. در حقیقت Javascript به صفحات وب زندگی می بخشد. این برنامه امکان اجرای مسائل پیچیده را برای شما فراهم می کند. هر بار که صفحه وب، اطلاعات استاتیک، به روزرسانی های محتوا، نقشه های تعاملی، گرافیک های دو بعدی یا سه بعدی، اسکرول کردن jukebox های ویدئویی و غیره را به شما نمایش می دهد، می توانید از دخیل بودن Javascript در آن اطمینان حاصل کنید.

چرا TypeScript با وجود JavaScript توسعه داده می شود؟

وقتی JavaScript توسعه یافت، تیم توسعه JavaScript جاوااسکریپت را به عنوان یک زبان برنامه نویسی سمت کلاینت معرفی کرد. اما وقتی افراد از JavaScript استفاده می کردند، توسعه دهنده فهمید که از JavaScript می توان به عنوان یک زبان برنامه نویسی سمت سرور نیز استفاده کرد. اما وقتی JavaScript در حال رشد بود، کد JavaScript پیچیده و سنگین شد. به همین دلیل، JavaScript حتی نتوانسته است زبان برنامه نویسی شی گرا را به طور کامل اجرا کند. این مانع از موفقیت JavaScript در سطح سازمانی به عنوان یک فناوری سمت سرور می شود. سپس TypeScript توسط تیم توسعه برای ایجاد این شکاف ساخته شد.

تفاوت بین تایپ اسکریپت و جاوااسکریپت

  • TypesScript به عنوان زبان برنامه نویسی شی گرا شناخته می شود در حالی که JavaScript یک زبان برنامه نویسی است.
  • TypeScript دارای ویژگی است که با عنوان تایپ استاتیک شناخته می شود اما جاوااسکریپت این ویژگی را ندارد.
  • TypeScript از ماژول ها پشتیبانی می کند در حالی که جاوااسکریپت از ماژول ها پشتیبانی نمی کند.
  • TypeScript دارای رابط است اما جاوااسکریپت رابط ندارد.
  • TypeScript از عملکرد پارامتر اختیاری پشتیبانی می کند اما JavaScript از عملکرد پارامتر اختیاری پشتیبانی نمی کند.

مزایای استفاده از TypeScript روی JavaScript

  • TypeScript همیشه خطاهای گردآوری را فقط در زمان توسعه ذکر می کند. به همین دلیل در زمان اجرا احتمال بروز خطا بسیار کمتر است در حالی که جاوااسکریپت یک زبان تفسیر شده است.
  • TypeScript دارای ویژگی ای است که کاملاً تایپ شده است یا از تایپ استاتیک پشتیبانی می کند. این بدان معنی است که تایپ استاتیک امکان بررسی صحت نوع را در زمان کامپایل فراهم می کند. این در JavaScript در دسترس نیست.
  • TypeScript چیزی نیست جز JavaScript و برخی از ویژگی های اضافی یعنی ویژگی های ES6 نیست. ممکن است در مرورگر هدف شما پشتیبانی نشود اما کامپایلر TypeScript می تواند فایل های ts. را در ES3، ES4 و ES5 نیز وارد کند.

تایپ اسکریپت و ری اکت

تایپ اسکریپت و ری اکت

ری اکت (React)

ری اکت (React) یک کتابخانه جاوااسکریپت برای ایجاد رابط کاربری است. این برنامه توسط فیس بوک و جامعه ای از توسعه دهندگان و شرکت های خاص نگهداری می شود. React را می توان به عنوان پایه ای در توسعه برنامه های تک صفحه ای یا تلفن همراه استفاده کرد. با این وجود React فقط به ارائه داده به DOM مربوط می شود و بنابراین ایجاد برنامه های React معمولاً نیاز به استفاده از کتابخانه های اضافی برای مدیریت state، مسیریابی و تعامل با API دارد. Redux،React Router و axios نمونه های مربوط به چنین کتابخانه هایی هستند

React و TypeScript با هم کار می کنند؟

React یک "کتابخانه جاوااسکریپت برای ایجاد واسط های کاربری" است، در حالی که TypeScript یک "superset جاواسکریپت تایپ شده است که به JavaScript ساده کامپایل می شود." با استفاده از آنها با هم، در اصل UI ها را با استفاده از یک نسخه تایپ شده از JavaScript ساخته شده است. دلیل استفاده شما از آنها، به دست آوردن مزایای استفاده از زبان آماری تایپ شده (TypeScript) برای رابط کاربر می باشد. این به معنای ایمنی بیشتر و حمل و نقل باگ های کمتر به قسمت فرانت اند است.

TypeScript یک انتخاب مناسب طبیعی برای React است، نه تنها به این دلیل که TypeScript کامپایلر کامل JSX است. این بدان معنی است که شما به یک ساختمان بزرگ احتیاج ندارید. TypeScript شامل همه مواردی است که شما نیاز دارید. یک چیز شما ممکن است بخواهید یک ابزار بسته بندی است. بسته انتخابی آسان و بدون پیکربندی است اما می توانید از Webpack نیز استفاده کنید.

نمونه کد های تایپ اسکریپت

نمایش !Hello world

var message:string = "Hello World" 
console.log(message)

متغیر ها در تایپ اسکریپت

var name:string = "John"; 
var score1:number = 50;
var score2:number = 42.50
var sum = score1 + score2 
console.log("name"+name) 
console.log("first score: "+score1) 
console.log("second score: "+score2) 
console.log("sum of the scores: "+sum)

تابع ها درتایپ اسکریپت

function disp_details(id:number,name:string,mail_id?:string) { 
   console.log("ID:", id); 
   console.log("Name",name); 
   
   if(mail_id!=undefined)  
   console.log("Email Id",mail_id); 
}
disp_details(123,"John");
disp_details(111,"mary","mary@xyz.com");
نظرتون درباره این نوشته چیه؟ عالیه بد نیست خوب نبود