詳解TS對象擴(kuò)展運(yùn)算符和rest運(yùn)算符
概述
TypeScript 2.1 增加了對 對象擴(kuò)展運(yùn)算和 rest 屬性提案的支持,該提案在 ES2018 中標(biāo)準(zhǔn)化??梢砸灶愋桶踩姆绞绞褂?rest 和 spread 屬性。
對象 rest 屬性
假設(shè)已經(jīng)定義了一個(gè)具有三個(gè)屬性的簡單字面量對象
const marius = { name: "Marius Schulz", website: "https://mariusschulz.com/", twitterHandle: "@mariusschulz" };
使用 ES6 解構(gòu)語法,可以創(chuàng)建幾個(gè)局部變量來保存相應(yīng)屬性的值。TypeScript 將正確地推斷每個(gè)變量的類型:
const { name, website, twitterHandle } = marius; name; // Type string website; // Type string twitterHandle; // Type string
這些都是正確的,但這到現(xiàn)在也啥新鮮的。除了提取感興趣的一組屬性之外,還可以使用...語法將所有剩余的屬性收集到rest元素中:
const { twitterHandle, ...rest } = marius; twitterHandle; // Type string rest; // Type { name: string; website: string; }
TypeScript 會(huì)為得到結(jié)果的局部變量確定正確的類型。雖然twitterHandle變量是一個(gè)普通的字符串,但rest變量是一個(gè)對象,其中包含剩余兩個(gè)未被解構(gòu)的屬性。
對象擴(kuò)展屬性
假設(shè)咱們希望使用fetch()API 發(fā)出 HTTP 請求。它接受兩個(gè)參數(shù):一個(gè)URL和一個(gè)options對象,options包含請求的任何自定義設(shè)置。
在應(yīng)用程序中,可以封裝對fetch()的調(diào)用,并提供默認(rèn)選項(xiàng)和覆蓋給定請求的特定設(shè)置。這些配置項(xiàng)類似如下:
const defaultOptions = { method: "GET", credentials: "same-origin" }; const requestOptions = { method: "POST", redirect: "follow" };
使用對象擴(kuò)展,可以將兩個(gè)對象合并成一個(gè)新對象,然后傳遞給fetch()方法
// Type { method: string; redirect: string; credentials: string; } const options = { ...defaultOptions, ...requestOptions };
對象擴(kuò)展屬性創(chuàng)建一個(gè)新對象,復(fù)制defaultOptions中的所有屬性值,然后按照從左到右的順序復(fù)制requestOptions中的所有屬性值,最后得到的結(jié)果如下:
console.log(options); // { // method: "POST", // credentials: "same-origin", // redirect: "follow" // }
請注意,分配順序很重要。如果一個(gè)屬性同時(shí)出現(xiàn)在兩個(gè)對象中,則后分配的會(huì)替換前面的。
當(dāng)然,TypeScript 理解這種順序。因此,如果多個(gè)擴(kuò)展對象使用相同的鍵定義一個(gè)屬性,那么結(jié)果對象中該屬性的類型將是最后一次賦值的屬性類型,因?yàn)樗采w了先前賦值的屬性:
const obj1 = { prop: 42 }; const obj2 = { prop: "Hello World" }; const result1 = { ...obj1, ...obj2 }; // Type { prop: string } const result2 = { ...obj2, ...obj1 }; // Type { prop: number }
制作對象的淺拷貝
對象擴(kuò)展可用于創(chuàng)建對象的淺拷貝。假設(shè)咱希望通過創(chuàng)建一個(gè)新對象并復(fù)制所有屬性來從現(xiàn)有todo項(xiàng)創(chuàng)建一個(gè)新todo項(xiàng),使用對象就可以輕松做到:
const todo = { text: "Water the flowers", completed: false, tags: ["garden"] }; const shallowCopy = { ...todo };
實(shí)際上,你會(huì)得到一個(gè)新對象,所有的屬性值都被復(fù)制:
console.log(todo === shallowCopy); // false console.log(shallowCopy); // { // text: "Water the flowers", // completed: false, // tags: ["garden"] // }
現(xiàn)在可以修改text屬性,但不會(huì)修改原始的todo項(xiàng):
hallowCopy.text = "Mow the lawn"; console.log(shallowCopy); // { // text: "Mow the lawn", // completed: false, // tags: ["garden"] // } console.log(todo); // { // text: "Water the flowers", // completed: false, // tags: ["garden"] // }
但是,新的todo項(xiàng)引用與第一個(gè)相同的tags數(shù)組。由于是淺拷貝,改變數(shù)組將影響這兩個(gè)todo
shallowCopy.tags.push("weekend"); console.log(shallowCopy); // { // text: "Mow the lawn", // completed: false, // tags: ["garden", "weekend"] // } console.log(todo); // { // text: "Water the flowers", // completed: false, // tags: ["garden", "weekend"] // }
如果想創(chuàng)建一個(gè)序列化對象的深拷貝,可以考慮使用jsON.parse(jsON.stringify(obj))或其他方法,如object.assign()。對象擴(kuò)展僅拷貝屬性值,如果一個(gè)值是對另一個(gè)對象的引用,則可能導(dǎo)致意外的行為。
keyof 和查找類型
JS 是一種高度動(dòng)態(tài)的語言。在靜態(tài)類型系統(tǒng)中捕獲某些操作的語義有時(shí)會(huì)很棘手。以一個(gè)簡單的prop函數(shù)為例:
function prop(obj, key) { return obj[key]; }
它接受一個(gè)對象和一個(gè)鍵,并返回相應(yīng)屬性的值。一個(gè)對象的不同屬性可以有完全不同的類型,咱們甚至不知道obj是什么樣子的。
那么如何在 TypeScript 中編寫這個(gè)函數(shù)呢?先嘗試一下:
有了這兩個(gè)類型注釋,obj必須是對象,key必須是字符串。咱們現(xiàn)在已經(jīng)限制了兩個(gè)參數(shù)的可能值集。然而,TS 仍然推斷返回類型為any:
const todo = { id: 1, text: "Buy milk", due: new Date(2016, 11, 31) }; const id = prop(todo, "id"); // any const text = prop(todo, "text"); // any const due = prop(todo, "due"); // any
如果沒有更進(jìn)一步的信息,TypeScript 就不知道將為key參數(shù)傳遞哪個(gè)值,所以它不能推斷出prop函數(shù)的更具體的返回類型。咱們需要提供更多的類型信息來實(shí)現(xiàn)這一點(diǎn)。
keyof 操作符號
在 JS 中屬性名稱作為參數(shù)的 API 是相當(dāng)普遍的,但是到目前為止還沒有表達(dá)在那些 API 中出現(xiàn)的類型關(guān)系。
TypeScript 2.1 新增加keyof操作符。輸入索引類型查詢或keyof,索引類型查詢keyof T產(chǎn)生的類型是T的屬性名稱。假設(shè)咱們已經(jīng)定義了以下Todo接口:
interface Todo { id: number; text: string; due: Date; }
各位可以將keyof操作符應(yīng)用于Todo類型,以獲得其所有屬性鍵的類型,該類型是字符串字面量類型的聯(lián)合
type TodoKeys = keyof Todo; // "id" | "text" | "due"
當(dāng)然,各位也可以手動(dòng)寫出聯(lián)合類型"id" | "text" | "due",而不是使用keyof,但是這樣做很麻煩,容易出錯(cuò),而且維護(hù)起來很麻煩。而且,它應(yīng)該是特定于Todo類型的解決方案,而不是通用的解決方案。
索引類型查詢
有了keyof,咱們現(xiàn)在可以改進(jìn)prop函數(shù)的類型注解。我們不再希望接受任意字符串作為key參數(shù)。相反,咱們要求參數(shù)key實(shí)際存在于傳入的對象的類型上
function prop <T, K extends keyof T>(obj: T, key: K) { return obj[key] }
TypeScript 現(xiàn)在以推斷prop函數(shù)的返回類型為T[K],這個(gè)就是所謂的索引類型查詢或查找類型。它表示類型T的屬性K的類型。如果現(xiàn)在通過prop方法訪問下面todo的三個(gè)屬性,那么每個(gè)屬性都有正確的類型:
const todo = { id: 1, text: "Buy milk", due: new Date(2016, 11, 31) }; const id = prop(todo, "id"); // number const text = prop(todo, "text"); // string const due = prop(todo, "due"); // Date
現(xiàn)在,如果傳遞一個(gè)todo對象上不存在的鍵會(huì)發(fā)生什么
編譯器會(huì)報(bào)錯(cuò),這很好,它阻止咱們試圖讀取一個(gè)不存在的屬性。
另一個(gè)真實(shí)的示例,請查看與TypeScript編譯器一起發(fā)布的lib.es2017.object.d.ts類型聲明文件中Object.entries()方法:
interface ObjectConstructor { // ... entries<T extends { [key: string]: any }, K extends keyof T>(o: T): [keyof T, T[K]][]; // ... }
entries方法返回一個(gè)元組數(shù)組,每個(gè)元組包含一個(gè)屬性鍵和相應(yīng)的值。不可否認(rèn),在返回類型中有大量的方括號,但是我們一直在尋找類型安全性。
以上就是詳解TS對象擴(kuò)展運(yùn)算符和rest運(yùn)算符的詳細(xì)內(nèi)容,更多關(guān)于TS對象擴(kuò)展運(yùn)算符和rest運(yùn)算符的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
js模式化窗口問題![window.dialogArguments]
這篇文章主要介紹了js模式化窗口問題![window.dialogArguments],需要的朋友可以參考下2016-10-10gameboy網(wǎng)頁闖關(guān)游戲(riddle webgame)--仿微信聊天的前端頁面設(shè)計(jì)和難點(diǎn)
本文講如何在網(wǎng)頁端實(shí)現(xiàn)一個(gè)仿微信的聊天窗口界面, 以及其中涉及到的一些技術(shù)點(diǎn). 對gameboy闖關(guān)游戲相關(guān)知識感興趣的朋友參考下2016-02-02Bootstrap modal 多彈窗之疊加顯示不出彈窗問題的解決方案
Bootstrap modal 多彈窗之疊加顯示不出彈窗問題,今天小編抽時(shí)間給大家分享下解決方案,需要的朋友參考下2017-02-02強(qiáng)大的JavaScript響應(yīng)式圖表Chartist.js的使用
本篇文章主要介紹了強(qiáng)大的JavaScript響應(yīng)式圖表Chartist.js的使用,具有一定的參考價(jià)值,有興趣的可以了解一下2017-09-09Javascript創(chuàng)建Silverlight Plugin以及自定義nonSilverlight和lowSilverl
我們在使用Visual Studio IDE創(chuàng)建Silverlight工程時(shí),默認(rèn)情況下都會(huì)自動(dòng)生成一個(gè)用于調(diào)試和預(yù)覽Silverlight的Web工程,該工程包含了html和aspx頁面,以及Silverlight.js腳本文件。2010-06-06