首頁 > web前端 > js教程 > 介紹JavaScript和TypeScript的聲明類型

介紹JavaScript和TypeScript的聲明類型

巴扎黑
發布: 2017-08-16 10:40:55
原創
1940 人瀏覽過

從 JavaScript 語法改寫為 TypeScript 語法,有兩個關鍵點,一點是類別成員變數(Field)需要聲明,另一點是要為各種東西(變數、參數、函數/方法等)聲明類型。 
從 ES6 語法改寫為 TypeScript 語法,有兩個比較重要的知識點,一個是宣告類別成員,另一個是宣告類型。這兩個語法特點在 JavaScript 中都不存在。而這兩個點直接引出了兩個關鍵性的問題,有哪些類型?怎樣聲明?

類型 

在說TypeScript 的型別之前,我們先複習一下JavaScript 的七種型別:

undefined

function

boolean

number

string

object

symbol

這七種型別都是可以透過typeof 運算子算出來的,但其中並沒有我們常見的Array、null,Date 之類的類型——因為它們其實都是object。
TypeScript 的重要特性之一就是型,所以TypeScript 中的型別要講究得多,除了JavaScript 中的型別之外,還定義了其它一些(不完全列表)

Array ,或T[],表示T 類型的陣列

null,空型,其作用與strictNullChecks 編譯參數有關

Tuple(元組),形如[Number, String]

enum T,定義枚舉類型T,可理解為集中對數值常數進行命名

interface T,接口,T 是一種接口類型

class T,類, T 是一種類型

any,代表任意型別

void,表示沒有類型,用於宣告函數型別

never,表示函數不可傳回的神奇型別

……

具體的類型這裡就不詳述了,官方Handbook 的 Basic Type、Interfaces、Classes、Enum、Advanced Types 這幾部分說得非常清楚。 
不過仍有一種與類型相關的特性不得不提-泛型。如果只是說資料型,純粹的 JSer 們還可以理解,畢竟類型不是新鮮玩意兒,只是擴展了點種類。但是泛型這個東西,純粹的 JSer 們可能就沒啥概念了。
泛型主要是用一個符號來表示一些類型,只要是符合約束條件(預設無約束)的類型,都可以替換掉這個類型符號來使用,例如 

function test (v: T) {
   console.log(v);}
test(true);    // 明確指定T 由boolean 取代test("hello"); 隱式       // 推斷("hello"); ) T 被string 取代test(123);              // 推斷(隱含) T 被number 取代

#泛型與強型別相關,即需要嚴格的型別檢查,又想少寫相似程式碼,所以乾脆用某個符號來代替類型。泛型這個名稱本身可能不是很好理解,但是如果借用 C++ 的「模板」概念,就好理解了。例如上面的泛型函數,根據後面的調用,可以解釋為三個函數,相當於套用模板,用實際型別取代了T: 
function test(v: boolean) { ... }function test( v: string) { ... }function test(v: number) { ... }

關於泛型,更詳細的內容可以參考Handbook 的Generic 部分。 
類型就簡述到這裡,簡單的類型一看就能明白,高級一點的類型我們以後再開專題來詳述。不過既然選擇使用 TypeScript,必然會用到它的靜態型別特性,那就必須強化辨識類型的意識,養成這樣的習慣。對於純 JSer 來說,這是一個巨大的挑戰。 


宣告類型 

宣告類型,主要指宣告變數/常數,函數/方法與類別成員的型別。 JS 中使用 var 宣告一個變量,ES6 擴展了 let 和 const。這幾種聲明 TypeScript 都支援。要為變數或常數指定型別也很簡單,就是在變數/常數名後面加個冒號,再指定型別即可,例如 

// # typescript
 // 声明函数 pow 是 number 类型,即返回值是 number 类型// 声明参数 n 是 number 类型function pow(n: number): number {
    return n * n;}
 // 声明 test 是无返回值的function test(): void {
    for (let i: number = 0; i < 10; i++) {  // 声明 i 是 number
        console.log(pow(i));
    }}
登入後複製

這段程式碼示範了對函數型別、參數型和變數類型地聲明。這相對於 JavaScript 程式碼來說,似乎變得更複雜了。但考慮下,如果我們在某處不小心這樣調用了pow: 

// # javascript
 let n = "a";let r = pow(n);     // 这里存在一个潜在的错误
登入後複製

JavaScript 不會提前檢查錯誤的,只有在執行到r = pow(n) 的時候給r 賦值為NaN。然後如果別處又用到 r,可能就會造成連鎖錯誤,可能很要調試一陣才把問題找得出來。
不過上面兩行程式碼在TypeScript 裡是通不過轉譯的,它會報告一個類型不符的錯誤: 
Argument of type 'string' is not assignable to parameter of type 'number'.


宣告類別成員 

這時先來看一段JavaScript 程式碼 

// # javascript (es6)
 class Person {
    constructor(name) {
        this._name = name;
    }
 
    get name() {
        return this._name;
    }}
登入後複製

這段JavaScript 程式碼如果翻譯成TypeScript 程式碼,會是這樣 

// # typescript
 class Person {
    private _name: string;
 
    public constructor(name: string) {
        this._name = name;
    }
 
    public get name(): string {
        return this._name;
    }}
登入後複製

注意到 private _name: string,这句话是在声明类成员变量 _name。JavaScript 里是不需要声明的,对 this._name 赋值,它自然就有了,但在 TypeScript 里如果不声明,就会报告属性不存在的错误: 
Property '_name' does not exist on type 'Person'.

虽然写起来麻烦了一点,但是我也能理解 TypeScript 的苦衷。如果没有这些声明,tsc 就搞不清楚你在使用 obj.xxxx 或者this.xxxx 的时候,这个 xxxx 到底确实是你想要添加的属性名称呢,还是你不小心写错了的呢? 
另外要注意到的是 private 和 public 修饰符。JavaScript 中存在私有成员,为了实现私有,大家都想了不少办法,比如闭包。 
TypeScript 提供了 private 来修饰私有成员,protected 修改保护(子类可用)成员,public 修饰公共成员。如果不添加修饰符,默认作为 public,以兼容 JavaScript 的类成员定义。不过特别需要注意的是,这些修饰符只在 TypeScript 环境(比如转译过程)有效,转译成 JavaScript 之后,仍然所有成员都是公共访问权限的。比如上例中的 TypeScript 代码转译出来基本上就是之前的 JavaScript 代码,其 _name 属性在外部仍可访问。 
当然在 TypeScript 代码中,如果外部访问了 _name,tsc 是会报告错误的 
Property '_name' is private and only accessible within class 'Person'.

所以应用内使用 private 完全没问题,但是如果你写的东西需要做为第三方库发布,那就要想一些手段来进行“私有化”了,其手段和 JavaScript 并没什么不同。 


小结 

从 JavaScript 语法改写 TypeScript 语法,我们来做个简单的总结:

类成员需要声明。

变量、函数参数和返回值需要申明类型。

如果所有这些东西都要声明类型,工作量还是满大的,所以我建议:就接口部分声明类型。也就是说,类成员、函数/方法的参数和返回类型要声明类型,便于编辑器进行语法提示,局部使用的变量或者箭头函数,在能明确推导出其类型的时候,可以不声明类型。 

以上是介紹JavaScript和TypeScript的聲明類型的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板