何時(shí)用enum類型
當(dāng)前端遇到這種需求的時(shí)候:
前端需要顯示后端返回的狀態(tài) 1,2嚼吞,3盒件,4,還要傳輸這個(gè)值回去舱禽,
但是我們經(jīng)常會(huì)忘記這個(gè)值是什么意思炒刁,這個(gè)時(shí)候就可以使用 enum
??:二進(jìn)制權(quán)限
enum Permission {
None = 0,
Read = 1 << 0, // 0001 // 這里的 << 是左移操作,1在二進(jìn)制表示為 00..001誊稚,那么左移一位就是 00..010
Write = 1 << 1, // 0010
Delete = 1 << 2, //0100
Manage = Read | Write | Delete, // 0111 // 這個(gè)的 | 是并操作翔始,取二進(jìn)制各個(gè)位置的 1 為結(jié)果
}
const user1: { permission: Permission } = { permission: 0b0101 };
// 這里的 & 是與操作,取二進(jìn)制各個(gè)位置同時(shí)為 1的為結(jié)果
if ((user1.permission & Permission.Write) === Permission.Write) {
console.log("擁有寫權(quán)限")
}
if ((user1.permission & Permission.Manage) === Permission.Manage) {
console.log("擁有管理權(quán)限")
}
何時(shí)不用 enum
并不是說不能用里伯,而是這時(shí)候用會(huì)顯得很呆
enum Fruit {
apple = 'apple',
banana = 'banana',
pineapple = 'pineapple',
watermelon = 'watermelon',
}
let f = Fruit.apple; // 這里甚至不能寫 'apple'
f = Fruit.pineapple
幾乎等價(jià)于
type Fruit = 'apple' | 'banana' | 'pineapple' | 'watermelon'
let f = 'apple'
f = 'pineapple'
結(jié)論
- number enum √
- string enum ×
- other enum ×
個(gè)人也覺得在 JS 中不太實(shí)用城瞎,在沒有 enum 的時(shí)候 JS 程序員就在用對(duì)象表示了,而且還比不上對(duì)象好用:
const PERMISSION = {
0: 'read',
1: 'write',
2: 'delete',
3: 'manage'
}
也幾乎是一樣的效果疾瓮,無論有沒有 enum脖镀,也能用的好好的,最多可能性能上沒有 enum 好狼电,又不是不能用认然,建議是能不用就不用
type與interfacer的區(qū)別
何時(shí)用 type补憾?
答案是什么時(shí)候都可以,幾乎沒有不能用的場(chǎng)合
type 又叫類型別名卷员,英文 Type Alias盈匾,簡(jiǎn)單來說就給其他類型取個(gè)名字
比如說我們可以給 string 換個(gè)名字,以下這樣幾乎是等價(jià)的:
type Name = string;
const a: Name = 'hi'
等等其他復(fù)雜類型都可以用 type毕骡,這里只說一種特殊情況削饵,帶有屬性的函數(shù):
type Fn = (a: number) => void // 純函數(shù),沒有屬性
type FnWithProp = {
(a: number): void; // 這里來聲明函數(shù)未巫,語法很奇怪把~
prop: string;
}
為何要叫做類型別名窿撬,不叫做類型聲明
因?yàn)?ts 一開始并沒有想要記住這個(gè)名字,比如說:
type A = string;
type B = A
請(qǐng)問此時(shí) B 的類型是什么叙凡,應(yīng)該是 A 把劈伴,
但是其實(shí)是 string,A 沒有被記住
何時(shí)用 interface
interface 又叫聲明接口握爷,
接口是什么跛璧?你翻過的 JS 教程中,從來沒有提到過這個(gè)單詞新啼,那是那個(gè)理論講到這個(gè)呢追城?是面向?qū)ο蟆s 為了滿足這些人燥撞,搞了一個(gè)接口出來座柱。
此接口非彼接口,還是對(duì)象物舒,描述對(duì)象的屬性(declare the shapes of objects)
// 描述普通對(duì)象
interface A {
name: string;
age: number;
}
// 描述數(shù)組
interface A extends Array<string>{
name: string;
}
// 如何用 type 實(shí)現(xiàn)上述效果
type A2 = Array<string> & { name: string; }
// 描述函數(shù)
interface Fn {
(a: number): void;
}
// 描述帶成員的函數(shù)
interface Fn {
(a: number): void;
prop: string;
}
// 描述日期對(duì)象
interface D extends Date {}
type 不可重新賦值
這個(gè)既是優(yōu)點(diǎn)也是缺點(diǎn)
type A = number;
A = string // 報(bào)錯(cuò)色洞,沒有這種語法
好處是提升效率,聲明什么就是什么冠胯,不用管以后你還會(huì)變火诸,當(dāng)然帶來的缺點(diǎn)則是不好拓展
interface 能自動(dòng)合并
比如在我們經(jīng)常使用的 axios 上:
// custom.d.ts
import { AxiosRTequestConfig } from 'axios'
declare module 'axios' {
export interface AxiosRequestConfig {
_autoLoading?: boolean;
}
}
axios.get('/list', {
_autoLoading: true // 拓展出來的
})
比如拓展 String:
declare global {
interface String {
newFn(x: string): void
}
}
const s = 'string'
s.newFn('xxx') // 此時(shí)不會(huì)報(bào)錯(cuò)
小結(jié)
- 區(qū)別1:
- interface 只描述對(duì)象
- type 則描述所有數(shù)據(jù)
- 區(qū)別2:
- type 只是別名
- interface 則是類型聲明
- 區(qū)別3:
- 對(duì)外 API 盡量用 interface,方便拓展
- 對(duì)內(nèi) API 盡量用 type涵叮,防止代碼分散
看起來 type 的應(yīng)用范圍更廣惭蹂,且包括 interface,看起來 interface 沒有必要出現(xiàn)割粮。其實(shí)是原因之一為了迎合面向?qū)ο蠓劢z的需求
聽說 type 不能繼承盾碗?
瞎說!
繼承的本質(zhì)是什么舀瓢?就是一個(gè)東西擁有另一個(gè)東西的屬性
這個(gè)東西很容易實(shí)現(xiàn)廷雅,比如說復(fù)制
那 type 怎么拓展?
type MyAxiosRTequestConfig = AxiosRTequestConfig & { _autoLoading?: boolean; }
幾乎是一樣的效果,而且更安全航缀,不會(huì)修改到原先的類型商架。