C# 是 TypeScript 的最佳替補?
TypeScript非常優(yōu)秀。它完美地結(jié)合了強類型和快速開發(fā),因此非常好用,我在許多情況下都會默認選擇這個庫。但是,世上沒有完美的語言,有些情況下TypeScript并不是最合適的工具:
- 性能至關重要(例如實時通信、視頻游戲)
- 需要與原生代碼(如C/C++或Rust)交互
- 需要更嚴格的類型系統(tǒng)(例如金融系統(tǒng))
對于這些情況,TypeScript開發(fā)人員最好還是選用其他語言。C#、Go和Java都是非常好的選擇。它們的速度遠超 TypeScript,每種語言都有自己的長處。C#能與TypeScript配合得很好,我來解釋一下為什么。
TypeScript 就是添加了 C# 的 JavaScript
C#能與TypeScript配合得很好,因為它們看上去就像是同一種語言。兩者都是由Anders Hejlsberg設計的,而且從許多方面來看,TypeScript就是添加了C#的JavaScript。它們的特性和語法都很相似,因此在同一個項目中結(jié)合使用二者非常容易。更重要的是,C#的語言與TypeScript很相似,因此開發(fā)人員閱讀和編寫代碼也非常輕松。
相反,Go是一種完全不同的語言:沒有類,沒有繼承,沒有異常,沒有包級別的封裝(只有類級別的封裝),而且語法也完全不同。當然這并不一定是壞事,但開發(fā)人員的確需要重新思考并用不同的方式設計代碼,因此,同時使用Go和TypeScript是比較困難的。不過,Java與C#很相似,但依然缺乏許多C#和TypeScript都有的功能。
C#和TypeScript的相似之處
也許你已經(jīng)知道,C#和TypeScript有很多相似之處,如基于C的語法、類、接口、泛型等。下面,我來詳細列舉一下二者的相似之處:
- async/await
- lambda表達式和函數(shù)式數(shù)組方法
- 用于處理空的操作符(?,!,??)
- 解構(gòu)
- 命令行界面(CLI)
async/await
首先,C#和JavaScript都使用async/await來處理異步代碼。在JavaScript中,異步操作用Promise表示,而應用程序可以await一個異步操作結(jié)束。C#中的Promise其實是Task,概念上與Promise完全相同,也有相應的方法。下面的例子演示了兩種語言中async/await的用法:
- async function fetchAndWriteToFile(url: string, filePath:string): Promise<string> {
- // fetch() returns aPromise
- const response = awaitfetch(url);
- const text = awaitresponse.text();
- // By the way, we'reusing Deno (https://deno.land)
- awaitDeno.writeTextFile(filePath, text);
- return text;
- }
- using System.IO;
- using System.Net.Http;
- using System.Threading.Tasks;
- async Task<string> FetchAndWriteToFile(string url, stringfilePath) {
- // HttpClient.GetAsync()returns a Task
- var response = await newHttpClient().GetAsync(url);
- var text = awaitresponse.Content.ReadAsStringAsync();
- awaitFile.WriteAllTextAsync(filePath, text);
- return text;
- }
下面是JavaScript的Promise API與等價的C# Task API:
Lambda表達式和函數(shù)式數(shù)組方法
C#和JavaScript都用熟悉的=>語法(即箭頭函數(shù))來表示lambda表達式。下面是TypeScript和C#的比較:
- const months = ['January', 'February', 'March', 'April'];
- const shortMonthNames = months.filter(month => month.length< 6);
- const monthAbbreviations = months.map(month =>month.substr(0, 3));
- const monthStartingWithF = months.find(month => {
- returnmonth.startsWith('F');
- });
TypeScript中使用lambda表達式
- using System.Collections.Generic;
- using System.Linq;
- var months = new List<string> {"January","February", "March", "April"};
- var shortMonthNames = months.Where(month => month.Length <6);
- var monthAbbreviations = months.Select(month =>month.Substring(0, 3));
- var monthStartingWithF = months.Find(month => {
- returnmonth.StartsWith("F");
- });
C#中使用lambda表達式
上述示例演示了C#的System.Linq命名空間中的一些方法,相當于JavaScript的函數(shù)式數(shù)組方法。下面是JavaScript的數(shù)組方法與等價的C# Linq方法:
性能:C#很快。C#的ASP.NET Web框架一直在Techempower的評測中名列前茅,而C#的.NET CoreCLR運行時的性能每個主要版本都在提高。C#擁有優(yōu)良性能的原因之一是,通過使用結(jié)構(gòu)而不是類,應用程序可以最小化甚至完全消除垃圾回收。因此,C#在視頻游戲編程中非常流行。
游戲和混合現(xiàn)實:C#是游戲開發(fā)最流行的語言之一,像Unity、Godot甚至Unreal游戲引擎都使用了C#。C#在混合現(xiàn)實中也很流行,因為VR和AR應用程序都是用Unity編寫的。
由于C#擁有第一方庫、工具和文檔,因此一些任務非常容易實現(xiàn),比如,在C#中創(chuàng)建gRPC客戶端要比TypeScript方便得多。相反,在Node.js中使用TypeScript時,就必須找出正確的模塊和工具的組合,才能正確地生成JavaScript gRPC客戶端,以及相應的TypeScript類型。
高級功能:C#有許多其他語言沒有的功能,如運算符重載、析構(gòu)函數(shù)等。
如前所述,世上沒有完美的語言。在設計語言時總要有所權(quán)衡,所以一些語言的速度更快,但使用難度會增加(例如Rust的借出檢查)。另一方面,一些語言非常易用,但通常性能的優(yōu)化難度就會增加(例如JavaScript的動態(tài)語言特性)。正因如此,我相信掌握一組相似的語言會非常有用:這些語言分別有各自的長處,但都很相似,而且能互相配合。例如,下面是我選擇的一組語言:
TypeScript
- 最高層的語言,開發(fā)速度最快
- 性能并非最佳,但適用于大多數(shù)應用
- 不太適合與原生代碼結(jié)合
C#
- 仍然是高級語言,支持垃圾回收,所以很容易使用,盡管并不如TypeScript那么容易。
- 從速度和內(nèi)存占用量來看,其性能都優(yōu)于 TypeScript
- 最重要的是,能夠與底層很好地結(jié)合
C++
- 開發(fā)難度較大(例如需要手動內(nèi)存管理),因此開發(fā)速度會慢很多
- 但運行時的性能最佳!而且隨處可用,能與許多已有的軟件相結(jié)合
- 很像C#,而且標準庫很好,但也有許多陷阱(大多數(shù)與內(nèi)存管理有關)。我更希望使用Rust,因為它的內(nèi)存安全性更好,但我的許多工作都要與已有的C++代碼結(jié)合,因此使用C++會更容易。