In the confusing jungle of transpiler languages for JavaScript, there are some gems. TypeScript is mainstream, ReScript is starting to establish itself, and Elm is still an insider tip. This article takes a detailed look at ReScript – but also sheds light on the limitations of the young language. In what projects does its use make sense? What projects should rather use TypeScript on the one hand or Elm on the other?
نگارش نهایی TypeScript 3.7 منتشر شد
We’ve got a lot of great features in TypeScript 3.7, including:
Optional Chaining
Nullish Coalescing
Assertion Functions
Better Support for never-Returning Functions
--declaration and --allowJs
(More) Recursive Type Aliases
The useDefineForClassFields Flag and The declare Property Modifier
Build-Free Editing with Project References
Uncalled Function Checks
Flatter Error Reporting
// @ts-nocheck in TypeScript Files
Semicolon Formatter Option
Website and Playground Updates
Breaking Changes
DOM Changes
Class Field Mitigations
Function Truthy Checks
Local and Imported Type Declarations Now Conflict
API Changes
This project uses mocha, chai, typescript and vs code debug toghether, so you can write your api tests easily.
This is useful for scenarios when you've some api developed in python for example, but you'd prefer to develop tests in typescript/javascript.
Another use case is when you've some legacy api and you want to develop some tests to make [risk free change] of your legacy api possibel!
Features
ReSharper Ultimate 2016.1 منتشر شد
- اطلاعات بیشتر
پس از نصب TypeScript 2.0 برای ویژوال استودیو و همچنین NodeJS
npm install -g typescript@2.0
<TypeScriptToolsVersion>2.0</TypeScriptToolsVersion>
معرفی موجودیت Person
در مثال این مطلب قصد داریم، معادل توابع بومی مخصوص SQL Server را که امکان کار با DateTime را مهیا میکنند، در EF Core تعریف کنیم. به همین جهت نیاز به موجودیتی داریم که دارای خاصیتی از این نوع باشد:
using System; namespace EFCoreDbFunctionsSample.Entities { public class Person { public int Id { get; set; } public string Name { get; set; } public DateTime AddDate { get; set; } } }
گزارشگیری بر اساس تعداد روز گذشتهی از ثبت نام
اکنون فرض کنید میخواهیم گزارشی را از تمام کاربرانی که در طی 10 روز قبل ثبت نام کردهاند، تهیه کنیم. اگر کوئری زیر را برای این منظور تهیه کنیم:
var usersInfo = context.People.Where(person => (DateTime.Now - person.AddDate).Days <= 10).ToList();
'The LINQ expression 'DbSet<Person>.Where(p => (DateTime.Now - p.AddDate).Days <= 10)' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync(). See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.'
SELECT [p].[Id], [p].[AddDate], [p].[Name] FROM [People] AS [p] WHERE DATEDIFF(Day, [p].[AddDate], GETDATE()) <= 10
روش تعریف تابع DATEDIFF سفارشی در EF Core
برای تعریف متد DateDiff مخصوص EF Core، ابتدا باید یک کلاس static را تعریف کرد و سپس تنها امضای این متد را، معادل امضای تابع توکار SQL Server تعریف کرد. این متد نیازی نیست تا پیاده سازی را داشته باشد. به همین جهت بدنهی آنرا صرفا با یک throw new InvalidOperationException مقدار دهی میکنیم. هدف از این متد، استفادهی از آن در LINQ Expressions است و قرار نیست به صورت مستقیمی بکار گرفته شود:
namespace EFCoreDbFunctionsSample.DataLayer { public enum SqlDateDiff { Year, Quarter, Month, DayOfYear, Day, Week, Hour, Minute, Second, MilliSecond, MicroSecond, NanoSecond } public static class SqlDbFunctionsExtensions { public static int SqlDateDiff(SqlDateDiff interval, DateTime initial, DateTime end) => throw new InvalidOperationException($"{nameof(SqlDateDiff)} method cannot be called from the client side."); public static readonly MethodInfo SqlDateDiffMethodInfo = typeof(SqlDbFunctionsExtensions) .GetRuntimeMethod( nameof(SqlDbFunctionsExtensions.SqlDateDiff), new[] { typeof(SqlDateDiff), typeof(DateTime), typeof(DateTime) } ); } }
روش معرفی تابع DATEDIFF سفارشی به EF Core
پس از تعریف امضای متد معادل DateDiff، اکنون نوبت به معرفی آن به EF Core است:
namespace EFCoreDbFunctionsSample.DataLayer { public class ApplicationDbContext : DbContext { // ... protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); modelBuilder.HasDbFunction(SqlDbFunctionsExtensions.SqlDateDiffMethodInfo) .HasTranslation(args => { var parameters = args.ToArray(); var param0 = ((SqlConstantExpression)parameters[0]).Value.ToString(); return SqlFunctionExpression.Create("DATEDIFF", new[] { new SqlFragmentExpression(param0), // It should be written as DateDiff(day, ...) and not DateDiff(N'day', ...) . parameters[1], parameters[2] }, SqlDbFunctionsExtensions.SqlDateDiffMethodInfo.ReturnType, typeMapping: null); }); } } }
سپس توسط متد HasTranslation، مشخص میکنیم که این متد به چه نحوی قرار است به یک عبارت SQL ترجمه شود. پارامتر args ای که در اینجا در اختیار ما قرار میگیرد، دقیقا همان پارامترهای متد public static int SqlDateDiff(SqlDateDiff interval, DateTime initial, DateTime end) هستند که در این مثال خاص، شامل سه پارامتر میشوند. پارامترهای دوم و سوم آنرا به همان نحوی که دریافت میکنیم، به SqlFunctionExpression.Create ارسال خواهیم کرد. اما پارامتر اول را از نوع enum تعریف کردهایم و همچنین قرار نیست به صورت 'N'day و رشتهای به سمت بانک اطلاعاتی ارسال شود، بلکه باید به همان نحو اصلی آن (یعنی day)، در کوئری نهایی درج گردد، به همین جهت ابتدا Value آنرا استخراج کرده و سپس توسط SqlFragmentExpression عنوان میکنیم آنرا باید به همین نحو درج کرد.
پارامتر اول متد SqlFunctionExpression.Create، باید دقیقا معادل نام متد توکار مدنظر باشد. پارامتر دوم آن، لیست پارامترهای این تابع است. پارامتر سوم آن، نوع خروجی این تابع است که از طریق MethodInfo معادل، قابل استخراج است.
استفادهی از DbFunction سفارشی جدید در برنامه
پس از این تعاریف و معرفیها، اکنون میتوان متد سفارشی SqlDateDiff تهیه شده را به صورت مستقیمی در کوئریهای LINQ استفاده کرد تا قابلیت ترجمهی به SQL را پیدا کنند:
var sinceDays = 10; users = context.People.Where(person => SqlDbFunctionsExtensions.SqlDateDiff(SqlDateDiff.Day, person.AddDate, DateTime.Now) <= sinceDays).ToList(); /* SELECT [p].[Id], [p].[AddDate], [p].[Name] FROM [People] AS [p] WHERE DATEDIFF(Day, [p].[AddDate], GETDATE()) <= @__sinceDays_0 */
کدهای کامل این مثال را از اینجا میتوانید دریافت کنید: EFCoreDbFunctionsSample.zip
این کدها به همراه چند تابع سفارشی دیگر نیز هستند.
- سرعت بالاتر بارگذاری و اجرای کدها
- استفاده از آخرین فناوریهای وب مانند ES 6 و وب کامپوننتها با پشتیبانی تا IE 9.
- سطح API آن با طراحی جدید آن، به شدت کاهش یافته و خلاصه شدهاست. همین امر یادگیری آنرا نیز سادهتر میکند.
برای یادگیری Angular 2 نیازی به فراگیری Angular 1 نیست. در اینجا با آشنایی با TypeScript، به این نتیجه خواهید رسید که برنامههای Angular 2 چیزی بیشتر از یک مثال عملی TypeScript نیستند. زبان TypeScript، زبان اول و توصیه شدهی کار با Angular 2 است و مزیت آن دسترسی به تمام قابلیتهای ES 6 است؛ با این تفاوت که کامپایلر TypeScript قادر است آنها را به ES 5 یا نگارش فعلی جاوا اسکریپت که توسط تمام مرورگرها پشتیبانی میشود، ترجمه و تبدیل کند. به این نحو به یک طراحی شیءگرا، مدرن و با قابلیت نگهداری بالا خواهید رسید که با تمام مرورگرهای جدید نیز سازگار است.
بنابراین پیشنیازهای اصلی کار با Angular 2، فراگیری ES 6 و TypeScript هستند که دو سری ویژه و مختص به آنها در سایت جاری تهیه شدهاند:
«مبانی ES 6»
«مبانی TypeScript»
در این قسمت قصد داریم پیشنیازهای دریافت و نصب اجزاء و وابستگیهای AngularJS 2 را به همراه TypeScript، در ویژوال استودیو 2015 بررسی کنیم. البته استفاده از ویژوال استودیو در اینجا ضروری نیست و اساسا AngularJS وابستگی به ویژوال استودیو ندارد. اگر به دنبال پشتیبانی بهتری از TypeScript هستید، VSCode رایگان، سورس باز و چند سکویی، گزینهی بسیار بهتری است نسبت به ویژوال استودیوی کامل. البته این مورد تعجبی هم ندارد؛ از این جهت که VSCode با TypeScript نوشته شدهاست.
اهمیت آشنایی با npm
اگر در طی سالهای اخیر با ویژوال استودیو کار کرده باشید، به طور قطع با NuGet نیز آشنا هستید. NuGet به عنوان یک package manager دات نتی شناخته میشود و کار آن دریافت وابستگیهای یک پروژه، از مخزنی مشخص و نصب و به روز رسانی خودکار آنها است. اما این روزها خارج از محیط توسعهی مایکروسافت، مدیرهای بستههای دیگری مانند Bower نیز برای نصب و به روز رسانی بستههای front end مانند کتابخانههای CSS ایی و جاوا اسکریپتی، بسیار رواج پیدا کردهاند. Bower یکی از ابزارهای NodeJS است که توسط NPM یا NodeJS Package Manager نصب میشود. به این معنا که استفاده از Bower به معنای استفاده از NPM است. پیش از این از NPM صرفا جهت نصب بستههای مرتبط با NodeJS استفاده میشد، اما در طی یکسال اخیر، استفاده از NPM نیز برای مدیریت بستههای front end رواج پیدا کردهاست و در صدر مدیر بستههای نصب کتابخانههای front end قرار دارد. همچنین در این حالت شما تنها نیاز به یک ابزار و یک فایل تنظیمات آن خواهید داشت، بجای استفاده از چندین ابزار و چندین فایل تنظیمات جداگانه. به علاوه این روزها انجام کارهای جدی جاوا اسکریپتی بدون دانش NPM دیگر میسر نیست. بهترین ابزارها، کامپایلرها، فشرده کنندههای front end و امثال آنها، تحت NodeJS اجرا میشوند. برای کار با AngularJS 2.0 و دریافت وابستگیهای آن نیز استفاده از npm، روش پیش فرض و توصیه شدهاست.
کار با npm جهت دریافت وابستگیهای کتابخانههای front end
برای کار با npm یا میتوان از دستورات خط فرمان آن به صورت مستقیم استفاده کرد و یا از امکانات یکپارچگی آن با ویژوال استودیو نیز بهره گرفت که ما در ادامه از این روش استفاده خواهیم کرد. البته توانمندیهای خط فرمان npm فراتر است از امکانات توکار VS.NET، اما در اینجا نیازی به آنها نیست و هدف صرفا دریافت و به روز رسانی وابستگیهای مرتبط است.
ویژوال استودیوی 2015 به همراه ابزارهای NodeJS ارائه میشود. اما مشکل اینجا است که این ابزارها هم اکنون قدیمی شدهاند و تطابقی با آخرین نگارش ابزارهای NodeJS ندارند. برای نمونه حین نصب وابستگیهای AngularJS 2.0 که یکی از آنها RxJS است، یک چنین خروجی را در پنجرهی output ویژوال استودیو مشاهده میکنید:
npm WARN engine rxjs@5.0.0-beta.6: wanted: {"npm":">=2.0.0"} (current: {"node":"v0.10.31","npm":"1.4.9"})
همانطور که در تصویر نیز ملاحظه میکنید، به مسیر Tools->Options->Projects and Solutions->External Web Tools مراجعه کرده و متغیر محیطی PATH ویندوز را به ابتدای لیست منتقل کنید. به این صورت ابزارهای به روز شدهی خط فرمان، مقدم خواهند شد بر ابزارهای قدیمی به همراه نگارش فعلی ویژوال استودیو.
البته فرض بر این است که آخرین نگارش nodejs را از آدرس https://nodejs.org/en دریافت و نصب کردهاید. با نصب آن، برنامه npm، در خط فرمان ویندوز به صورت مستقیم قابل استفاده خواهد بود؛ از این جهت که مسیر آن به PATH ویندوز اضافه شدهاست:
افزودن فایل project.json به پروژه
تا اینجا فرض بر این است که nodejs را از سایت آن دریافت و نصب کردهاید. همچنین متغیر PATH را در External Web Tools ویژوال استودیو به ابتدای لیست آن منتقل کردهاید تا همواره از آخرین نگارش npm نصب شدهی در سیستم، استفاده شود.
پس از آن همانند نیوگت که از فایل xml ایی به نام packages.config برای ثبت آخرین تغییرات خودش استفاده میکند، npm نیز از فایلی به نام package.json برای ذکر وابستگیهای مورد نیاز پروژه بهره میبرد. برای افزودن آن، از منوی Project گزینهی Add new item را انتخاب کرده و سپس npm را در آن جستجو کنید:
در اینجا نام پیش فرض package.json را پذیرفته و این فایل را به پروژه و ریشهی آن اضافه کنید.
اگر گزینهی فوق را در لیست Add new item مشاهده نمیکنید، مهم نیست. یک فایل متنی را به نام package.json به ریشهی پروژهی جاری اضافه کنید.
در ادامه محتوای این فایل را به نحو ذیل تغییر دهید:
{ "name": "asp-net-mvc5x-angular2x", "version": "1.0.0", "author": "DNT", "description": "", "scripts": {}, "license": "Apache-2.0", "dependencies": { "jquery": "2.2.3", "angular2": "2.0.0-beta.15", "systemjs": "^0.19.26", "es6-promise": "^3.1.2", "es6-shim": "^0.35.0", "reflect-metadata": "0.1.2", "rxjs": "5.0.0-beta.2", "zone.js": "^0.6.12", "bootstrap": "^3.3.6" }, "devDependencies": { "typescript": "^1.8.9", "typings": "^0.8.1" }, "repository": { } }
چند نکته:
- هر زمانیکه این فایل را ذخیره کنید، بلافاصله کار دریافت این بستهها از اینترنت آغاز خواهد شد. جزئیات آنرا میتوان در پنجرهی output ویژوال استودیو مشاهده کرد (و حتما اینکار را جهت دیباگ کار انجام دهید. بسیاری از مشکلات و خطاها، در اینجا لاگ میشوند). بنابراین اگر قصد دارید کار همگام سازی تغییرات را انجام دهید، فقط کافی است دکمههای ctrl+s یا save را بر روی این فایل اعمال کنید.
- کاری که دکمهی ctrl+s در این فایل انجام میدهد، اعمال خودکار دستور npm install بر روی پوشهای است که package.json در آن قرار دارد. بنابراین برای دریافت این بستهها، روش خط فرمان آن، ابتدا وارد شدن به ریشهی پروژهی جاری و سپس صدور دستور npm install است (که نیازی به آن نیست و ویژوال استودیو اینکار را به صورت خودکار انجام میدهد).
- بستههای دریافت شده، در پوشهای به نام node_modules در ریشهی پروژه ذخیره میشوند:
برای مشاهدهی آنها میتوان بر روی دکمهی show all files در solution explorer کلیک نمائید.
- درون فایل package.json، پشتیبانی کاملی از intellisense وجود دارد. برای مثال اگر علاقمند بودید تا آخرین نگارش AngularJS را مشاهده کنید، پس از خاصیت angular2 در تنظیمات فوق، " را تایپ کنید تا منوی تکمیل کنندهای ظاهر شود:
بدیهی است این منو جهت دریافت آخرین اطلاعات، نیاز به اتصال به اینترنت را دارد.
البته همیشه آخرین شماره نگارش AngularJS 2.0 را در این آدرس نیز میتوانید مشاهده کنید: CHANGELOG.md
- در این فایل شماره نگارش آغاز شدهای با ^ مانند "3.1.2^" به این معنا است که اجازهی نصب نگارشهای جدیدتری از 3.1.2 نیز داده شدهاست.
به روز رسانی کامپایلر TypeScript
نیاز است یکبار مطلب «مبانی TypeScript؛ تنظیمات TypeScript در ویژوال استودیو» را جهت آشنایی با نحوهی به روز رسانی اجزای مرتبط با TypeScript مطالعه کنید.
افزودن فایل tsconfig.json به پروژه
مرحلهی بعد شروع به کار با AngularJS و TypeScript، انجام تنظیمات کامپایلر TypeScript است. برای این منظور از منوی پروژه، گزینهی Add new item، عبارت typescript را جستجو کرده و در لیست ظاهر شده، گزینهی TypeScript JSON Configuration File را با نام پیش فرض آن انتخاب کنید:
اگر این گزینهی ویژه را در لیست add new items ندارید، مهم نیست. یک فایل متنی را به نام tsconfig.json به ریشهی پروژهی جاری اضافه کنید.
پس از افزودن فایل tsconfig.json به ریشهی سایت، تنظیمات آنرا به نحو ذیل تغییر دهید:
{ "compileOnSave": true, "compilerOptions": { "target": "es5", "module": "system", "moduleResolution": "node", "noImplicitAny": false, "noEmitOnError": true, "removeComments": false, "sourceMap": true, "emitDecoratorMetadata": true, "experimentalDecorators": true }, "exclude": [ "node_modules", "wwwroot", "typings/main", "typings/main.d.ts" ] }
برای نمونه خاصیت compileOnSave سبب خواهد شد تا پس از ذخیره سازی یک فایل ts، بلافاصله فایل js معادل آْن تولید شود. نوع ماژولها در اینجا به system.js تنظیم شدهاست و خروجی کدهای js آن از نوع ES 5 درنظر گرفته شدهاست. همچنین فعال سازی decorators نیز در اینجا صورت گرفتهاست. از این جهت که AngularJS2 استفادهی گستردهای را از این مفهوم، انجام میدهد.
در قسمت excludes به کامپایلر TypeScript اعلام شدهاست تا از یک سری از مسیرها مانند پوشهی node_modules که پیشتر آنرا تنظیم و دریافت کردیم، صرفنظر کند.
خلاصهی بحث
تا اینجا با نحوهی نصب پیشنیازهای AngularJS 2 و همچنین TypeScript آشنا شدیم. به صورت خلاصه:
- nmp اصلی را از سایت nodejs دریافت و نصب کنید.
- متغیر PATH را در ویژوال استودیو، به ابتدای لیست ابزارهای خارجی وب آن منتقل کنید تا از npm اصلی استفاده کند.
- فایل project.json را با محتوای ذکر شده، به ریشهی پروژه اضافه کنید. سپس یکبار آنرا save کنید تا وابستگیها را از اینترنت دریافت کند.
- اطمینان حاصل کنید که آخرین کامپایلر TypeScript را نصب کردهاید.
- فایل tsconfig.json را با محتوای ذکر شده، به ریشهی پروژه اضافه کنید.