TypeScript语法的详细教程

200 阅读7分钟

Typescript为JavaScript引入了静态类型,但在了解静态类型是什么之前,我们并不清楚这意味着什么。有什么理由让我们喜欢它而不喜欢虚构的Javascript吗?本文打算快速介绍一下为什么typecript(或任何类型的语言)是个大问题,然后为那些从Javascript迁移过来的人介绍TypeScript的语法。如果你已经在使用ES6或以上的语言,你可以在一个小时内开始使用这种语言。

目录

  1. 类型化有什么好的?
  2. 语法

1.类型化的好处是什么

如果你曾经用一个数字除以0,或者试图用4除以 "苹果",你就会遇到代码中的类型错误。类型错误只是可能出现的错误的一个子集。对于像Javascript这样的解释性语言,所有这些错误都是在你的代码运行时处理的。编译器倒是可以看一下你的代码,指出很多这样的类型错误。编译器只是通过查看你的代码,而不是执行它来指出这些错误,这叫做静态类型检查。Javascript已经有了类型检查,但这是一个动态的类型检查,直到它绝对需要时才会抱怨。

它很乐意将4/0评估为无穷大,将0/0评估为NaN。前者的结果甚至值得商榷(如果你知道如何取极限,问问自己4/x的极限是否会随着x趋于0而收敛),甚至NaN的值也相当模糊。NaN永远不等于它自己,从Infinity - Infinity"Dogs" - "Cats" ,都会给出NaN。静态类型检查器将不允许这样的代码,它将在编译时抛出一个错误,也就是在代码运行之前。这样,你可能有问题的代码就不会被加入,并在你已经忘记它的时候造成问题。

有时,灵活性也是很重要的。在我开始使用Javascript的时候,我对这种语言的灵活性感到非常高兴。当然,我也犯过错误,
但我从不认为纠正我的错误是语言的责任。一旦你学会写正确的代码并避免常见的陷阱,
语言的灵活性可以直接转化为更紧凑和更简洁的代码,节省时间和磁盘空间。然而,在大型应用程序中,错误可能会被埋没。在成千上万行的代码中,所以你能得到的那种工具,以最大限度地减少以后在你的代码中发现错误的机会,受到了那些不关心大型应用程序的程序员或那些不在大型团队中工作的程序员的热情欢迎。告诉大家
使用TypeScript比强迫他们每次修改代码(这需要有人专门阅读新代码并提供反馈)要容易得多。

我确实发现类型化的语法比非类型化的语法表现力稍差。鉴于上述优点,程序员可以自己选择
他更喜欢的类型,即类型化或非类型化。如果是前者,而且你已经了解Javascript(ECMAScript 6或以上),那么让我们深入了解一下Typescript的语法。

语法

TypeScript是Javascript的一个超集。所有的JavaScript文件都是有效的TypeScript文件--只要把扩展名从.js 改为.ts 。因此,你可以
根据自己的意愿或需要,选择加入。也许你会使用一行特定的typescript功能,只是这样而已--或者你可以在你
的代码中散布types,如果你喜欢这样的话。让我们从现在开始只用一行。

let x = "Hi"; 

这里没有什么新东西。但是typescript足够聪明,在这里发现x的类型是字符串。JavaScript也有这些类型,你可以通过使用typeof 看到。然而,由于typescript有一个编译步骤,将你的代码转换为vanilla JavaScript,如果你犯了一个错误,编译器会抱怨,而不是让你的代码通过,成为javascript代码。

如果你是那种明确的、啰嗦的人,那么你可能就会写成

let x : string =  "Hi" ; 

这和上面的第一段代码是一样的。有时你就是明确,比如在函数参数中。

function add(a : number, b : number ) : number {  // a is a number, b is a number and the return value is also a number. 
    return a + b; 
}

如果你没有添加类型,就不会清楚a和b是两个数字、字符串还是数组,因为这个函数对所有这些情况
都能给出有效的结果。在这种情况下,typescript会给这些值分配类型any ,这本质上等于说 "这个变量可以
有任何类型的值"--这是需要避免的。如果你所有的值都是any ,你就没有可能继续使用typescript
,应该迁移到Javascript,以节省你在编译TypeScript时浪费的时间。

你也可以表达 "A、B和C具有相同的类型",而不用事先说那会是什么类型。

function add<X>(a : X, b : X) : X { // a and b have some type X, as does the return value
    return a + b; 
}

也许我想让我的函数对数组中的字符串和数字起作用。为此,你可以创建一个叫做addable的新类型,它允许所有的三种基本类型。要检查一个值是哪种基本类型,只需使用typeof。

type addable = number | string | any[]; // one of these types
function add( a : addable, b : addable) : addable { 
    return a + b;
}

但在这里,typescript会抛出一个错误。理由很充分,因为有些操作会导致意外的结果。
例如,[1,2]+[3,4]的结果不是一个数组。相反,它和做 "1,2"+"3,4 "的结果一样,都是 "1,23,4"。我们被迫在我们的函数中明确地检查类型。让我们再试一次。

type addable = number | string | any[];
function add( a : addable, b : addable) : addable {
  if (typeof a !== typeof b) throw TypeError(`${a} and ${b} are dissimilar types and can't be added`);
  if (typeof a === 'number' || typeof a === 'string') return a + b;
  return a.concat(b);
}

仍然是一个错误。这一次,这个错误不是我们自己的错。Typescript并没有聪明到只看上面的代码就知道a和b在函数的第一行之后总是同一类型,否则我们就会出错。这就是静态与动态类型检查的关系。如果类型检查是动态的,我们可以直接开始执行代码,并在遇到错误时抱怨,而我们不会有这样的错误。但是上面的静态类型检查就不那么聪明了,它期望上面的代码会导致错误。要想让上面的代码通过静态类型检查,你就得更啰嗦一些。

type addable = number | string | any[];
function add( a : addable, b : addable) : addable { 
  if (typeof a === 'number' && typeof b === 'number') return a + b; 
  else if (typeof a === 'object' && typeof b === 'object') return a.concat(b); // typescript figures this is the any[] case
  return a + '' + b;
}

最后一行说a + '' + b ,说即使a和b的类型不匹配,只要把它们胁迫成一个字符串。这与上面的代码不同,后者只在a和b的类型相同的情况下通过。

如果这种繁琐的操作看起来有点多,你并不孤单。即使是我,也更愿意只写一个快速的单行本,说let a = (a, b)=>a+b; ,然后承担后果(通常没有任何后果)。然而,在大型应用程序中,类型检查可以是一个福音,它可以防止你(和你无法控制的人)犯错。静态类型检查并不是每个人都需要的,所以它可能适合你,也可能不适合你。在这篇文章中,我也没有提到接口和结构类型系统,尽管这些都是非常重要和基本的概念。接口允许你预先声明一些东西的类型,所以你必须少打一些,你可以重复使用你的代码。结构类型允许你传递和返回的值不是明确的你想要的类型,但要遵守与你的类型相同的结构。有了这些概念,你就可以开始编写TypeScript了,在这里试一下吧。祝你打字愉快。