<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
型別可以出現在很多地方,不僅僅是在型別註解 (type annotations)中。我們不僅要學習型別本身,也要學習在什麼地方使用這些型別產生新的結構。
我們先複習下最基本和常見的型別,這些是構建更復雜型別的基礎。
string
,number
和 boolean
(The primitives)
JavaScript 有三個非常常用的原始型別:string
,number
和 boolean
,每一個型別在 TypeScript 中都有對應的型別。他們的名字跟你在 JavaScript 中使用 typeof
操作符得到的結果是一樣的。
string
表示字串,比如 "Hello, world"number
表示數位,比如 42,JavaScript 中沒有 int
或者 float
,所有的數位,型別都是 number
boolean
表示布林值,其實也就兩個值: true
和 false
型別名 String
,Number
和 Boolean
(首字母大寫)也是合法的,但它們是一些非常少見的特殊內建型別。所以型別總是使用 string
,number
或者 boolean
。
宣告一個類似於 [1, 2, 3]
的陣列型別,你需要用到語法 number[]
。這個語法可以適用於任何型別(舉個例子,string[]
表示一個字串陣列)。你也可能看到這種寫法 Array<number>
,是一樣的。我們會在泛型章節為大家介紹 T<U>
語法。
TypeScript 有一個特殊的型別,any
,當你不希望一個值導致型別檢查錯誤的時候,就可以設定為 any
。
當一個值是 any
型別的時候,你可以獲取它的任意屬性 (也會被轉為 any
型別),或者像函數一樣呼叫它,把它賦值給一個任意型別的值,或者把任意型別的值賦值給它,再或者是其他語法正確的操作,都可以:
let obj: any = { x: 0 }; // None of the following lines of code will throw compiler errors. // Using `any` disables all further type checking, and it is assumed // you know the environment better than TypeScript. obj.foo(); obj(); obj.bar = 100; obj = "hello"; const n: number = obj;
當你不想寫一個長長的型別程式碼,僅僅想讓 TypeScript 知道某段特定的程式碼是沒有問題的,any
型別是很有用的。
如果你沒有指定一個型別,TypeScript 也不能從上下文推斷出它的型別,編譯器就會預設設定為 any
型別。
如果你總是想避免這種情況,畢竟 TypeScript 對 any 不做型別檢查,你可以開啟編譯項 noImplicitAny,當被隱式推斷為 any 時,TypeScript 就會報錯。
當你使用 const
、var
或 let
宣告一個變數時,你可以選擇性的新增一個型別註解,顯式指定變數的型別:
let myName: string = "Alice";
TypeScript 並不使用“在左邊進行型別宣告”的形式,比如 int x = 0
;型別註解往往跟在要被宣告型別的內容後面。
不過大部分時候,這不是必須的。因為 TypeScript 會自動推斷型別。舉個例子,變數的型別可以基於初始值進行推斷:
// No type annotation needed -- 'myName' inferred as type 'string' let myName = "Alice";
大部分時候,你不需要學習推斷的規則。如果你剛開始使用,嘗試儘可能少的使用型別註解。你也許會驚訝於,TypeScript 僅僅需要很少的內容就可以完全理解將要發生的事情。
函數是 JavaScript 傳遞資料的主要方法。TypeScript 允許你指定函數的輸入值和輸出值的型別。
當你宣告一個函數的時候,你可以在每個引數後面新增一個型別註解,宣告函數可以接受什麼型別的引數。引數型別註解跟在引數名字後面:
// Parameter type annotation function greet(name: string) { console.log("Hello, " + name.toUpperCase() + "!!"); }
當引數有了型別註解的時候,TypeScript 便會檢查函數的實參:
// Would be a runtime error if executed! greet(42); // Argument of type 'number' is not assignable to parameter of type 'string'.
即便你對引數沒有做型別註解,TypeScript 依然會檢查傳入引數的數量是否正確
你也可以新增返回值的型別註解。返回值的型別註解跟在參數列後面:
function getFavoriteNumber(): number { return 26; }
跟變數型別註解一樣,你也不需要總是新增返回值型別註解,TypeScript 會基於它的 return
語句推斷函數的返回型別。像這個例子中,型別註解寫和沒寫都是一樣的,但一些程式碼庫會顯式指定返回值的型別,可能是因為需要編寫檔案,或者阻止意外修改,亦或者僅僅是個人喜好。
匿名函數有一點不同於函數宣告,當 TypeScript 知道一個匿名函數將被怎樣呼叫的時候,匿名函數的引數會被自動的指定型別。
這是一個例子:
// No type annotations here, but TypeScript can spot the bug const names = ["Alice", "Bob", "Eve"]; // Contextual typing for function names.forEach(function (s) { console.log(s.toUppercase()); // Property 'toUppercase' does not exist on type 'string'. Did you mean 'toUpperCase'? }); // Contextual typing also applies to arrow functions names.forEach((s) => { console.log(s.toUppercase()); // Property 'toUppercase' does not exist on type 'string'. Did you mean 'toUpperCase'? });
儘管引數 s
並沒有新增型別註解,但 TypeScript 根據 forEach
函數的型別,以及傳入的陣列的型別,最後推斷出了 s
的型別。
這個過程被稱為上下文推斷(contextual typing),因為正是從函數出現的上下文中推斷出了它應該有的型別。
跟推斷規則一樣,你也不需要學習它是如何發生的,只要知道,它確實存在並幫助你省掉某些並不需要的註解。後面,我們還會看到更多這樣的例子,瞭解一個值出現的上下文是如何影響它的型別的。
除了原始型別,最常見的型別就是物件型別了。定義一個物件型別,我們只需要簡單的列出它的屬性和對應的型別。
舉個例子:
// The parameter's type annotation is an object type function printCoord(pt: { x: number; y: number }) { console.log("The coordinate's x value is " + pt.x); console.log("The coordinate's y value is " + pt.y); } printCoord({ x: 3, y: 7 });
這裡,我們給引數新增了一個型別,該型別有兩個屬性, x
和 y
,兩個都是 number
型別。你可以使用 ,
或者 ;
分開屬性,最後一個屬性的分隔符加不加都行。
每個屬性對應的型別是可選的,如果你不指定,預設使用 any
型別。
物件型別可以指定一些甚至所有的屬性為可選的,你只需要在屬性名後新增一個 ?
:
function printName(obj: { first: string; last?: string }) { // ... } // Both OK printName({ first: "Bob" }); printName({ first: "Alice", last: "Alisson" });
在 JavaScript 中,如果你獲取一個不存在的屬性,你會得到一個 undefined
而不是一個執行時錯誤。因此,當你獲取一個可選屬性時,你需要在使用它前,先檢查一下是否是 undefined
。
function printName(obj: { first: string; last?: string }) { // Error - might crash if 'obj.last' wasn't provided! console.log(obj.last.toUpperCase()); // Object is possibly 'undefined'. if (obj.last !== undefined) { // OK console.log(obj.last.toUpperCase()); } // A safe alternative using modern JavaScript syntax: console.log(obj.last?.toUpperCase()); }
TypeScript 型別系統允許你使用一系列的操作符,基於已經存在的型別構建新的型別。現在我們知道如何編寫一些基礎的型別了,是時候把它們組合在一起了。
第一種組合型別的方式是使用聯合型別,一個聯合型別是由兩個或者更多型別組成的型別,表示值可能是這些型別中的任意一個。這其中每個型別都是聯合型別的成員(members)。
讓我們寫一個函數,用來處理字串或者數位:
function printId(id: number | string) { console.log("Your ID is: " + id); } // OK printId(101); // OK printId("202"); // Error printId({ myID: 22342 }); // Argument of type '{ myID: number; }' is not assignable to parameter of type 'string | number'. // Type '{ myID: number; }' is not assignable to type 'number'.
提供一個符合聯合型別的值很容易,你只需要提供符合任意一個聯合成員型別的值即可。那麼在你有了一個聯合型別的值後,你該怎樣使用它呢?
TypeScript 會要求你做的事情,必須對每個聯合的成員都是有效的。舉個例子,如果你有一個聯合型別 string | number
, 你不能使用只存在 string
上的方法:
function printId(id: number | string) { console.log(id.toUpperCase()); // Property 'toUpperCase' does not exist on type 'string | number'. // Property 'toUpperCase' does not exist on type 'number'. }
解決方案是用程式碼收窄聯合型別,就像你在 JavaScript 沒有型別註解那樣使用。當 TypeScript 可以根據程式碼的結構推斷出一個更加具體的型別時,型別收窄就會出現。
舉個例子,TypeScript 知道,對一個 string
型別的值使用 typeof
會返回字串 "string"
:
function printId(id: number | string) { if (typeof id === "string") { // In this branch, id is of type 'string' console.log(id.toUpperCase()); } else { // Here, id is of type 'number' console.log(id); } }
再舉一個例子,使用函數,比如 Array.isArray
:
function welcomePeople(x: string[] | string) { if (Array.isArray(x)) { // Here: 'x' is 'string[]' console.log("Hello, " + x.join(" and ")); } else { // Here: 'x' is 'string' console.log("Welcome lone traveler " + x); } }
注意在 else
分支,我們並不需要做任何特殊的事情,如果 x
不是 string[]
,那麼它一定是 string
.
有時候,如果聯合型別裡的每個成員都有一個屬性,舉個例子,數位和字串都有 slice
方法,你就可以直接使用這個屬性,而不用做型別收窄:
// Return type is inferred as number[] | string function getFirstThree(x: number[] | string) { return x.slice(0, 3); }
以上就是TypeScript常見型別及應用範例講解的詳細內容,更多關於TypeScript常見型別及應用的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45