摘要:斷言官方文檔中給出了這樣的解釋引入了一個名為斷言的字面值的新構造。在中,標準做法是從名為的函數創建操作。如果我們有一個用于設置小時數組的類型,它可能看起來像這樣在之前,擴展會使上述操作的字面量屬性更加通用,因為它們是可以修改的。
翻譯:瘋狂的技術宅
blog.logrocket.com/const-asser…
我發現官方的 TypeScript 文檔非常有用,但是總覺得有點過于學術化并且枯燥無味。每當我發現一個新功能時,我想要知道這個功能究竟能夠解決什么問題而不是長篇大論。
在我看來,const assertions 是 TypeScript 3.4 的殺手級新功能,正如我稍后將要解釋的,我們可以用這個新功能省略很多繁瑣的類型聲明。
const 斷言const x = { text: "hello" } as const;
官方文檔中給出了這樣的解釋:
TypeScript 3.4 引入了一個名為 const 斷言的字面值的新構造。它的語法是一個類型斷言,用 const 代替類型名稱(例如 123 as const)斷言構造新的文字表達式時,我們可以向語言發出以下信號:
該表達式中的字面類型不應被擴展(例如:不能從“hello”轉換為字符串)
對象字面量獲取只讀屬性
數組文字成為只讀元組
感覺有點枯燥,還有點混亂。讓我們來各個擊破。
沒有類型擴展的字面類型并不是每個人都知道類型擴展,并且由于某些意外行為而首次發現它時都會覺得意外。
當我們使用關鍵字 const 聲明一個字面量時,類型是等號右邊的文字,例如:
const x = "x"; // x has the type "x"
const 關鍵字確保不會發生對變量進行重新分配,并且只保證該字面量的嚴格類型。
但是如果我們用 let 而不是 const, 那么該變量會被重新分配,并且類型會被擴展為字符串類型,如下所示:
let x = "x"; // x has the type string;
以下是兩個不同的聲明:
const x = "x"; // has the type "x"
let y = "x"; // has the type string
y 被擴展為更通用的類型,并允許將其重新分配給該類型的其他值,而變量 x 只能具有 "x"的值。
用新的 const 功能,我可以這樣做:
let y = "x" as const; // y has type "x"`
對象字面量獲取只讀屬性
在 Typescript 3.4 之前,類型擴展發生在對象字面量中:
const action = { type: "INCREMENT", } // has type { type: string }
即使我們將 action 聲明為 const,仍然可以重新分配 type 屬性,因此,該屬性被擴展成了字符串類型。
這看上去令人覺得不是那么有用,所以讓我們換一個更好的例子。
如果你熟悉 Redux,就可能會發現上面的 action 變量可以用作 Redux action。如果你不知道 Redux 我來簡單解釋一下,Redux 是一個全局不可變的 state 存儲。通過向所謂的 reducers 發送動作來修改狀態。 reducers 是純函數,它在調度每個 action 后返回全局狀態的新更新版本,以反映 acion 中指定的修改。
在 Redux 中,標準做法是從名為 action creators 的函數創建操作。 action creators 只是純函數,它返回 Redux操作對象字面量以及提供給函數的所有參數。
用一個例子可以更好地說明這一點。應用程序可能需要一個全局 count 屬性,為了更新這個 count 屬性,我們可以調度類型為 "SET_COUNT" 的動作,它只是將全局 count 屬性設置為一個新的值,這是一個字面對象屬性。這個 action 的 action creator 將是一個函數,它接受一個數字作為參數,并返回一個具有屬性為 type、值為 SET_COUNT 和類型為 number 的 payload 屬性的對象,它將指定 count 的新值:
const setCount = (n: number) => {
return {
type: "SET_COUNT",
payload: n,
}
}
const action = setCount(3)
// action has type
// { type: string, payload: number }
從上面顯示的代碼中可以看出,type 屬性已經被擴展為 string 類型而不再是 SET_COUNT。這不是很安全的類型,我們可以保證的是 type 是一個字符串。 redux 中的每個 action 都有一個 type 屬性,它是一個字符串。
這不是很好,如果我們想要利用 type 屬性上的可區分聯合的話,那么在 TypeScript 3.4 之前,則需要為每個 action 聲明一個接口或類型:
interface SetCount {
type: "SET_COUNT";
payload: number;
}
const setCount = (n: number): SetCount => {
return {
type: "SET_COUNT",
payload: n,
}
}
const action = setCount(3)
// action has type SetCount
這確實增加了編寫 Redux action 和 reducers 的負擔,但我們可以通過添加一個 const assertion 來解決這個問題:
const setCount = (n: number) => {
return <const>{
type: "SET_COUNT",
payload: n
}
}
const action = setCount(3);
// action has type
// { readonly type: "SET_COUNT"; readonly payload: number };
你會注意到從 setCount 推斷的類型已經在每個屬性中附加了 readonly 修飾符,正如文檔的項目符號所述。
這就是所發生的事情:
{
readonly type: "SET_COUNT";
readonly payload: number
};
action 中的每個字面量都被添加了 readonly 修飾符。
在 redux 中,我們創建了一個接受 action 的聯合,reducer 函數可以通過這種操作來獲得良好的類型安全性。在 TypeScript 3.4 之前,我們會這樣做:
interface SetCount {
type: "SET_COUNT";
payload: number;
}
interface ResetCount {
type: "RESET_COUNT";
}
const setCount = (n: number): SetCount => {
return {
type: "SET_COUNT",
payload: n,
}
}
const resetCount = (): ResetCount => {
return {
type: "RESET_COUNT",
}
}
type CountActions = SetCount | ResetCount
我們創建了兩個接口 RESET_COUNT 和 SET_COUNT 來對兩個 resetCount 和 setCount 的返回類型進行歸類。
CountActions 是這兩個接口的聯合。
使用 const assertions,我們可以通過使用 const、 ReturnType 和 typeof 的組合來消除聲明這些接口的需要:
const setCount = (n: number) => {
return <const>{
type: "SET_COUNT",
payload: n
}
}
const resetCount = () => {
return <const>{
type: "RESET_COUNT"
}
}
type CountActions = ReturnType<typeof setCount> | ReturnType<typeof resetCount>;
我們從 action creator 函數 setCount 和 resetCount 的返回類型中推斷出一個很好的 action 聯合。
數組字面量成為只讀元組在 TypeScript 3.4 之前,聲明一個字面量數組將被擴展并且可以修改。
使用 const,我們可以將字面量鎖定為其顯式值,也不允許修改。
如果我們有一個用于設置小時數組的 redux action 類型,它可能看起來像這樣:
const action = {
type: "SET_HOURS",
payload: [8, 12, 5, 8],
}
// { type: string; payload: number[]; }
action.payload.push(12) // no error
在 TypeScript 3.4 之前,擴展會使上述操作的字面量屬性更加通用,因為它們是可以修改的。
如果我們將 const 應用于對象字面量,那么就可以很好地控制所有內容:
const action = <const>{
type: "SET_HOURS",
payload: [8, 12, 5, 8]
}
// {
// readonly type: "SET_HOURS";
// readonly payload: readonly [8, 12, 5, 8];
// }
action.payload.push(12); // error - Property "push" does not exist on type "readonly [8, 12, 5, 8]".
這里發生的事情恰恰是文檔的要點:
payload 數組確實是 [8,12,5,8] 的“只讀”元組(不過我并沒有從文檔中看到這方面的說明)。
結論我用以下代碼總結以上所有內容:
let obj = {
x: 10,
y: [20, 30],
z: {
a:
{ b: 42 }
}
} as const;
對應于:
let obj: {
readonly x: 10;
readonly y: readonly [20, 30];
readonly z: {
readonly a: {
readonly b: 42;
};
};
};
在這里,我可以推斷出類型,而不是去編寫多余的樣板類型。這對于 redux 特別有用。
歡迎關注前端公眾號:前端先鋒,獲取「前端工程化實用工具包」
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/6967.html
摘要:通常會定義為函數的返回值一個類型的變量是沒有生命用處的,因為類型的變量只能賦值為。和有一些區別的,函數沒有返回值時返回類型為的方法,即使沒有寫明語句,也會在函數執行完的時候,隱式地返回一個類型。中新增加的變量聲明方式。 類型注解 類型注解使用 :TypeAnnotation 語法。類型聲明空間中可用的任何內容都可以用作類型注解。 const num: number = 123; fun...
摘要:版本記錄針對版本的特性作專門的實例,希望能加深理解。這種情況下添加類型屬性被間接初始化了例如構造函數中調用一個方法,更改了屬性的值。這種情況下我們可以使用顯式賦值斷言修飾符號來幫助類型系統識別類型。 TypeScript 2.7版本記錄 針對ts 2.7版本的特性作專門的實例,希望能加深理解。實例github地址 官方日志文檔 增加常量聲明的屬性的支持(Constant-named ...
摘要:比如或者都會導致函數返回值類型時。和特性一樣,等于是函數返回值中的或。注意對比下面的寫法對于,它的返回值是可迭代的對象,并且每個類型都是或者。首先是不支持方法重載的,是支持的,而類型系統一定程度在對標,當然要支持這個功能。 1 引言 精讀原文是 typescript 2.0-2.9 的文檔: 2.0-2.8,2.9 草案. 我發現,許多寫了一年以上 Typescript 開發者,對 T...
摘要:聯合類型,指賦值的時候可以是聯合類型中的某一個。任意屬性允許創建對象的時候,定義接口中沒有的屬性。常見的類型推論,還提現在函數表達式中。 typeScript是什么? TypeScript 是 JavaScript 的一個超集,主要提供了類型系統和對 ES6 的支持 安裝typeScript npm install -g typeScript 安裝完成查看版本: tsc -v typ...
摘要:怎么影響了我的思考方式對前端開發者來說,能強化了面向接口編程這一理念。使用的過程就是在加深理解的過程,確實面向接口編程天然和靜態類型更為親密。 電影《降臨》中有一個觀點,語言會影響人的思維方式,對于前端工程師來說,使用 typescript 開發無疑就是在嘗試換一種思維方式做事情。 其實直到最近,我才開始系統的學習 typescript ,前后大概花了一個月左右的時間。在這之前,我也在...
閱讀 2953·2021-11-23 09:51
閱讀 1006·2021-09-26 09:55
閱讀 3935·2021-09-22 14:58
閱讀 1468·2021-09-08 09:35
閱讀 1078·2021-08-26 14:16
閱讀 882·2019-08-23 18:17
閱讀 2054·2019-08-23 16:45
閱讀 700·2019-08-23 15:55