摘要:如果屬性的值不能是,那么它必須在構造函數中進行初始化。為帶來了額外的層靜態類型。類型檢查可確保這些預測能夠實現。元素不一定具有相同的類型。相反,在中,和由多帶帶的不相交類型處理。類型存在于元級別。將傳遞給的構造函數。
翻譯:瘋狂的技術宅
原文:http://2ality.com/2018/04/typ...
本文首發微信公眾號:jingchengyideng
歡迎關注,每天都給你推送新鮮的前端技術文章
閱讀本文后,你應該能夠理解以下代碼的含義:
interface Array{ concat(...items: Array ): T[]; reduce( callback: (state: U, element: T, index: number, array: T[]) => U, firstState?: U): U; ··· }
如果你認為這段代碼非常神秘 —— 那么我同意你的意見。但是(我希望證明)這些符號還是相對容易學習的。一旦你能理解它們,就能馬上全面、精確的理解這種代碼,從而無需再去閱讀冗長的英文說明。
運行代碼案例TypeScript 有一個在線運行環境。為了得到最全面的信息,你應該在 “Options” 菜單中打開所有選項開關。這相當于在 --strict 模式下運行TypeScript編譯器。
關于類型檢查的詳細說明我在用 TypeScript 時總是喜歡打開 --strict 開關設置。沒有它,程序可能會稍微好寫一點,但是你也失去了靜態類型檢查的好處。目前此設置能夠開啟以下子設置:
--noImplicitAny:如果 TypeScript 無法推斷類型,則必須指定它。這主要用于函數和方法的參數:使用此設置,你必須對它們進行注釋。
--noImplicitThis:如果 this 的類型不清楚則會給出提示信息。
--alwaysStrict:盡可能使用 JavaScript 的嚴格模式。
--strictNullChecks:null 不屬于任何類型(除了它自己的類型,null),如果它是可接受的值,則必須明確指定。
--strictFunctionTypes:對函數類型更加嚴格的檢查。
--strictPropertyInitialization:如果屬性的值不能是 undefined ,那么它必須在構造函數中進行初始化。
更多信息:TypeScript 手冊中的“編譯器選項”一章。
類型在本文中,我們把類型看作是一組值的集合。 JavaScript 語言(不是TypeScript!)有7種類型:
Undefined:具有唯一元素 undefined 的集合。
Null:具有唯一元素“null”的集合。
Boolean:具有兩個元素 false 和 true 的集合。
Number:所有數字的集合。
String:所有字符串的集合。
Symbol:所有符號的集合。
Object:所有對象的集合(包括函數和數組)。
所有這些類型都是 dynamic:可以用在運行時。
TypeScript 為 JavaScript 帶來了額外的層:靜態類型。這些僅在編譯或類型檢查源代碼時存在。每個存儲位置(變量或屬性)都有一個靜態類型,用于預測其動態值。類型檢查可確保這些預測能夠實現。還有很多可以進行 靜態 檢查(不運行代碼)的東西。例如,如果函數 f(x) 的參數 x 是靜態類型 number,則函數調用 f("abc") 是非法的,因為參數 "abc" 是錯誤的靜態類型。
類型注釋變量名后的冒號開始 類型注釋:冒號后的類型簽名用來描述變量可以接受的值。例如以代碼告訴 TypeScript 變量 “x” 只能存儲數字:
let x: number;
你可能想知道用 undefined 去初始化 x 是不是違反了靜態類型。 TypeScript 不會允許這種情況出現,因為在為它賦值之前不允許操作 x。
類型推斷即使在 TypeScript 中每個存儲位置都有靜態類型,你也不必總是明確的去指定它。 TypeScript 通常可以對它的類型進行推斷。例如如果你寫下這行代碼:
let x = 123;
然后 TypeScript 會推斷出 x 的靜態類型是 number。
類型描述在類型注釋的冒號后面出現的是所謂的類型表達式。這些范圍從簡單到復雜,并按如下方式創建。
基本類型是有效的類型表達式:
對應 JavaScript 動態類型的靜態類型:
- `undefined`, `null` - `boolean`, `number`, `string` - `symbol` - `object`
注意:值 undefined 與類型 undefined(取決于所在的位置)
TypeScript 的特定類型:
Array(從技術上講不是 JS 中的類型)
any(所有值的類型)
等等其他類型
請注意,“undefined作為值“ 和 ”undefined作為類型” 都寫做 undefined。根據你使用它的位置,被解釋為值或類型。 null 也是如此。
你可以通過類型運算符對基本類型進行組合的方式來創建更多的類型表達式,這有點像使用運算符 union(∪)和intersection(∩)去合并集合。
下面介紹 TypeScript 提供的一些類型運算符。
數組類型數組在 JavaScript 中扮演以下兩個角色(有時是兩者的混合):
列表:所有元素都具有相同的類型。數組的長度各不相同。
元組:數組的長度是固定的。元素不一定具有相同的類型。
數組作為列表數組 arr 被用作列表有兩種方法表示 ,其元素都是數字:
let arr: number[] = []; let arr: Array= [];
通常如果存在賦值的話,TypeScript 就可以推斷變量的類型。在這種情況下,實際上你必須幫它解決類型問題,因為在使用空數組時,它無法確定元素的類型。
稍后我們將回到尖括號表示法(Array
如果你想在數組中存儲二維坐標點,那么就可以把這個數組當作元組去用。看上去是這個樣子:
let point: [number, number] = [7, 5];
在這種情況下,你不需要類型注釋。
另外一個例子是 Object.entries(obj) 的返回值:一個帶有一個 [key,value] 對的數組,它用于描述 obj 的每個屬性。
> Object.entries({a:1, b:2}) [ [ "a", 1 ], [ "b", 2 ] ]
Object.entries() 的返回值類型是:
Array<[string, any]>函數類型
以下是函數類型的例子:
(num: number) => string
這個類型是一個函數,它接受一個數字類型參數并且返回值為字符串。在類型注釋中使用這種類型(String 在這里是個函數)的例子:
const func: (num: number) => string = String;
同樣,我們一般不會在這里使用類型注釋,因為 TypeScript 知道 String 的類型,因此可以推斷出 func 的類型。
以下代碼是一個更實際的例子:
function stringify123(callback: (num: number) => string) { return callback(123); }
由于我們使用了函數類型來描述 stringify123() 的參數 callback,所以TypeScript 拒絕以下函數調用。
f(Number);
但它接受以下函數調用:
f(String);函數聲明的返回類型
對函數的所有參數進行注釋是一個很好的做法。你還可以指定返回值類型(不過 TypeScript 非常擅長去推斷它):
function stringify123(callback: (num: number) => string): string { const num = 123; return callback(num); }特殊返回值類型 void
void 是函數的特殊返回值類型:它告訴 TypeScript 函數總是返回 undefined(顯式或隱式):
function f1(): void { return undefined } // OK function f2(): void { } // OK function f3(): void { return "abc" } // error可選參數
標識符后面的問號表示該參數是可選的。例如:
function stringify123(callback?: (num: number) => string) { const num = 123; if (callback) { return callback(num); // (A) } return String(num); }
在 --strict 模式下運行 TypeScript 時,如果事先檢查時發現 callback 沒有被省略,它只允許你在 A 行進行函數調用。
參數默認值TypeScript支持 ES6 參數默認值:
function createPoint(x=0, y=0) { return [x, y]; }
默認值可以使參數可選。通常可以省略類型注釋,因為 TypeScript 可以推斷類型。例如它可以推斷出 x 和 y 都是 number 類型。
如果要添加類型注釋,應該這樣寫:
function createPoint(x:number = 0, y:number = 0) { return [x, y]; }rest 類型
你還可以用 ES6 rest operator 進行 TypeScript 參數定義。相應參數的類型必須是數組:
function joinNumbers(...nums: number[]): string { return nums.join("-"); } joinNumbers(1, 2, 3); // "1-2-3"Union
在JavaScript中,有時候變量會是有幾種類型之中的一種。要描述這些變量,可以使用 union types。例如,在下面的代碼中,x 是 null 類型或 number 類型:
let x = null; x = 123;
x 的類型可以描述為 null | number:
let x: null|number = null; x = 123;
類型表達式 s | t 的結果是類型 s 和 t 在集合理論意義上的聯合(正如我們之前看到的那樣,兩個集合)。
下面讓我們重寫函數 stringify123():這次我們不希望參數 callback 是可選的。應該總是調用它。如果調用者不想傳入一個函數,則必須顯式傳遞 null。實現如下。
function stringify123( callback: null | ((num: number) => string)) { const num = 123; if (callback) { // (A) return callback(123); // (B) } return String(num); }
請注意,在行 B 進行函數調用之前,我們必須再次檢查 callback 是否真的是一個函數(行A)。如果沒有檢查,TypeScript 將會報告錯誤。
Optional 與 undefined|T類型為 T 的可選參數和類型為 undefined|T 的參數非常相似。 (另外對于可選屬性也是如此。)
主要區別在于你可以省略可選參數:
function f1(x?: number) { } f1(); // OK f1(undefined); // OK f1(123); // OK
But you can’t omit parameters of type
但是你不能省略 undefined|T 類型的參數:
function f2(x: undefined | number) { } f2(); // error f2(undefined); // OK f2(123); // OK值 null 和 undefined 通常不包含在類型中
在許多編程語言中,null 是所有類型的一部分。例如只要 Java 中的參數類型為 String,就可以傳遞 null 而Java 不會報錯。
相反,在TypeScript中,undefined 和 null 由多帶帶的不相交類型處理。如果你想使它們生效,必須要有一個類型聯合,如 undefined|string 和 null|string。
對象與Arrays類似,對象在 JavaScript 中扮演兩個角色(偶爾混合和/或更加動態):
記錄:在開發時已知的固定數量的屬性。每個屬性可以有不同的類型。
字典:在開發時名稱未知的任意數量的屬性。所有屬性鍵(字符串和/或符號)都具有相同的類型,屬性值也是如此。
我們將在本文章中忽略 object-as-dictionaries。順便說一句,無論如何,map 通常是比字典的更好選擇。
通過接口描述 objects-as-records接口描述 objects-as-records 。例如:
interface Point { x: number; y: number; }
TypeScript 類型系統的一大優勢在于它的結構上,而不是在命名上。也就是說,接口 Point 能夠匹配適當結構的所有對象:
function pointToString(p: Point) { return `(${p.x}, ${p.y})`; } pointToString({x: 5, y: 7}); // "(5, 7)"
相比之下,Java 的標稱類型系統需要類來實現接口。
可選屬性如果可以省略屬性,則在其名稱后面加上一個問號:
interface Person { name: string; company?: string; }方法
接口內還可以包含方法:
interface Point { x: number; y: number; distance(other: Point): number; }類型變量和泛型類型
使用靜態類型,可以有兩個級別:
值存在于對象級別。
類型存在于元級別。
同理:
普通變量定義在對象級別之上。
類型變量存在于元級別之上。它們是值為類型的變量。
普通變量通過 const,let 等引入。類型變量通過尖括號( <> )引入。例如以下代碼包含類型變量 T,通過
interface Stack{ push(x: T): void; pop(): T; }
你可以看到類型參數 T 在 Stack 的主體內出現兩次。因此,該接口可以直觀地理解如下:
Stack 是一堆值,它們都具有給定的類型 T。每當你提到 Stack 時,必須寫 T。接下來我們會看到究竟該怎么用。
方法 .push() 接受類型為 T 的值。
方法 .pop() 返回類型為 T 的值。
如果使用 Stack,則必須為 T 指定一個類型。以下代碼顯示了一個虛擬棧,其唯一目的是匹配接口。
const dummyStack: Stack例子:map= { push(x: number) {}, pop() { return 123 }, };
map 在 TypeScript 中的定義。例如:
const myMap: Map函數的類型變量= new Map([ [false, "no"], [true, "yes"], ]);
函數(和方法)也可以引入類型變量:
function id(x: T): T { return x; }
你可以按以下方式使用此功能。
id(123);
由于類型推斷,還可以省略類型參數:
id(123);傳遞類型參數
函數可以將其她的類型參數傳給接口、類等:
function fillArray(len: number, elem: T) { return new Array (len).fill(elem); }
類型變量 T 在這段代碼中出現三次:
fillArray
elem:T:使用類型變量,從參數中選擇它。
Array
這意味著:我們不必顯式指定Array
const arr = fillArray(3, "*"); // Inferred type: string[]總結
讓我們用前面學到的知識來理解最開始看到的那段代碼:
interface Array{ concat(...items: Array ): T[]; reduce( callback: (state: U, element: T, index: number, array: T[]) => U, firstState?: U): U; ··· }
這是一個Array的接口,其元素類型為 T,每當使用這個接口時必須填寫它:
方法.concat()有零個或多個參數(通過 rest 運算符定義)。其中每一個參數中都具有類型 T[]|T。也就是說,它是一個 T 類型的數組或是一個 T 值。
方法.reduce() 引入了自己的類型變量 U。 U 表示以下實體都具有相同的類型(你不需要指定,它是自動推斷的):
Parameter state of callback() (which is a function)
state 是 callback() 的參數(這是一個函數)
Result of callback()
callback()的返回
.reduce()的可選參數 firstState
Result of .reduce()
.reduce()的返回
callback 還將獲得一個 element 參數,其類型與 Array 元素具有相同的類型 T,參數 index 是一個數字,參數 array 是 T 的值。
擴展閱讀
書籍(免費在線閱讀):“Exploring ES6”
ECMAScript規范中的“ECMAScript語言類型”。
“TypeScript 手冊”:寫得非常好,并解釋了TypeScript支持的各種其他類型和類型的運算符。
GitHub 上有 完整 ECMAScript 標準庫的類型定義。這是練習類型符號的簡單方法。
本文首發微信公眾號:jingchengyideng 歡迎掃描二維碼關注公眾號,每天都給你推送新鮮的前端技術文章 歡迎繼續閱讀本專欄其它高贊文章:12個令人驚嘆的CSS實驗項目
世界頂級公司的前端面試都問些什么
CSS Flexbox 可視化手冊
過節很無聊?還是用 JavaScript 寫一個腦力小游戲吧!
從設計者的角度看 React
CSS粘性定位是怎樣工作的
一步步教你用HTML5 SVG實現動畫效果
程序員30歲前月薪達不到30K,該何去何從
7個開放式的前端面試題
React 教程:快速上手指南
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/102536.html
摘要:泛型通過在函數接口類變量名后使用定義。抽象類可以包括具體實現一個類只能繼承一個類,但是可以實現多個接口。該開源項目目前由社區進行維護。通常通過中的字段,或者聲明文件進行聲明。 TypeScript 是 Javascript 的一個超集,提高了代碼的可讀性和可維護性。Typescript 官網提供的文檔已經相當完善,但完整地看一遍需要一定的時間,本文試將 TypeScript 中要點提出...
摘要:是一項標準,于年月獲得批準。靜態限制在分配之前阻止使用。使用通用到基于自定義迭代器的迭代。迭代基于這些鴨子類型接口僅使用類型語法進行展示生成器生成器使用和簡化迭代器。生成器是迭代器的子類型,包括額外的和。 ECMAScript 2015是一項ECMAScript標準,于2015年6月獲得批準。 ES2015是該語言的重要更新,也是自2009年ES5標準化以來該語言的第一次重大更新。現在...
摘要:前面講泛型的時候,提到了接口。和泛型一樣,接口也是目前中并不存在的語法。不過可不吃這一套,所以這里通過注釋關閉了對該接口的命名檢查。這樣的接口不能由類實現。 前面講 泛型 的時候,提到了接口。和泛型一樣,接口也是目前 JavaScript 中并不存在的語法。 由于泛型語法總是附加在類或函數語法中,所以從 TypeScript 轉譯成 JavaScript 之后,至少還存在類和函數(只是...
本文收集學習過程中使用到的資源。 持續更新中…… 項目地址 https://github.com/abc-club/f... 目錄 vue react react-native Weex typescript Taro nodejs 常用庫 css js es6 移動端 微信公眾號 小程序 webpack GraphQL 性能與監控 高質文章 趨勢 動效 數據結構與算法 js core 代碼規范...
閱讀 954·2019-08-30 15:55
閱讀 550·2019-08-26 13:56
閱讀 2079·2019-08-26 12:23
閱讀 3295·2019-08-26 10:29
閱讀 600·2019-08-26 10:17
閱讀 2867·2019-08-23 16:53
閱讀 697·2019-08-23 15:55
閱讀 2813·2019-08-23 14:25