<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          TypeScript高級的用法Partial、Required、Readonly

          共 3933字,需瀏覽 8分鐘

           ·

          2021-09-14 11:23


          來源 | https://segmentfault.com/a/1190000040663155


          如何讓一個(gè)類的屬性全部可選?

          比如我有下面這樣一個(gè)類型:
          type User = {  username: string;  gender: 'male' | 'female';  age: number;  bio: string;  password: string;}

          User 類型要求所有屬性都必須有值,所以:

          const user: User = {  username: 'awesomeuser',};

          是不可行的,會(huì)提示:

          類型“{ username: string; }”缺少類型“User”中的以下屬性: gender, age, bio

          如何讓它可行?使用 Partial 即可:

          const user: Partial<User> = {  username: 'awesomeuser'}

          Partial 內(nèi)置內(nèi)型的作用就是讓一個(gè)已定義了的類型的所有屬性變得可選,具體實(shí)現(xiàn)如下:

          /** * Make all properties in T optional */type Partial<T> = {    [P in keyof T]?: T[P];};

          如何讓一個(gè)類型的屬性全部必填?

          假設(shè)我們有下面這樣一個(gè)類型定義:

          type User = {  username: string;  age?: number;  gender?: 'male' | 'female'  bio?: string;  password?: string;}

          然后從服務(wù)器后端拿到了一系列用戶數(shù)據(jù)的結(jié)果:

          const users: User[] = await api.users.list();

          此時(shí)我們嘗試去訪問用戶的 age 進(jìn)行比較,想要取出 age > 18 的用戶:

          const filteredUsers = users.filter(user => user.age > 18);

          此時(shí)你的 IDE 是不是提示你:對象可能為“未定義”。?為什么?因?yàn)槲覀兌x了 age 本身就是可選的屬性,未定義該屬性時(shí),它的值就是 undefined,而在 typescript 中, undefined 是不允許與 number 類型進(jìn)行比較的。

          但是此時(shí)其實(shí)我們是能很確定 api.users.list 接口返回給我的,要么是拋出錯(cuò)誤,要么給到我的就一定是帶了 age 值的 User 類型數(shù)據(jù),所以,我是完全可以去比較的,但是由于 TypeScript 并不知道你加載的數(shù)據(jù)是 User 還是所有屬性都已經(jīng)有值的特殊的 User,那怎么辦?什么 Required 即可。

          const users: Required<User>[] = [];

          或者讓 api.users.list() 的返回類型就是 Required<User>[] 即可。

          如何自己實(shí)現(xiàn) Required:

          /** * Make all properties in T required */type Required<T> = {    [P in keyof T]-?: T[P];};

          如何讓一個(gè)類型的所有屬性變成只讀?

          假設(shè)我們現(xiàn)在在寫一個(gè)系統(tǒng),當(dāng)用戶登錄之后,會(huì)共享一個(gè) User 對象給所有組件,但是只允許他人讀取其值,不允許他人修改,但是我們定義的 User 是整個(gè)系統(tǒng)共用的,有編輯功能的頁面也在使用這個(gè)類型定義,它們是需要能修改用戶數(shù)據(jù)的,那怎么辦?

          使用 Readonly 即可:

          const user = {  username: "awesomeuser",  gender: "male",  age: 19,  bio: "Aha, insight~",};
          const sharedUser = user as Readonly<User>;
          sharedUser.username = "new Name";

          此時(shí),IDE 就會(huì)告訴你無法分配到 "username" ,因?yàn)樗侵蛔x屬性。

          注意:TypeScript 只作靜態(tài)類型校驗(yàn),但是并不表示這些值真的不能被修改了,如果真的要?jiǎng)?chuàng)建一個(gè)真正從程序上都不能被修改的對象,請問怎么解決?

          我想有一個(gè)類,只具有另一個(gè)類的部分屬性定義

          還是那個(gè) User,我想定義一個(gè) Login 類型,它專門用于登錄時(shí)的類型,但是我又不想重新去寫一遍 username 與 password 的類型定義(雖然在本例中,重新寫一遍也很簡單,但保不齊哪天就會(huì)遇到一個(gè)十分復(fù)雜的類型定義呢?),怎么辦?使用 Pick 即可。

          type User = {  username: string;  gender?: "male" | "female";  age?: number;  bio?: string;  password?: string;};
          type Login = Pick<User, "username" | "password">;
          const login: Login = { username: "pantao",};

          你們也看到了,Login 類型還是只有 username 是必填的,password 是可選的,這與我們的要求不符,怎么辦?加上 Required 啊。

          type User = {  username: string;  gender?: "male" | "female";  age?: number;  bio?: string;  password?: string;};
          type Login = Required<Pick<User, "username" | "password">>;
          const login: Login = { username: "pantao",};

          此時(shí)就會(huì)要求你必須輸入 password 了。

          如何自己實(shí)現(xiàn) Pick?

          /** * From T, pick a set of properties whose keys are in the union K */type Pick<T, K extends keyof T> = {    [P in K]: T[P];};

          如果快速定義一個(gè)類型中,具有相同數(shù)據(jù)類型的屬性?

          假設(shè)我們現(xiàn)在在開發(fā)一個(gè)商城系統(tǒng),每一個(gè) Store 都有一個(gè)店長,一個(gè)倉庫管理員,一個(gè)收銀員,他們都關(guān)聯(lián)到了 User 上面,此時(shí)你可以這樣定義 Store 這個(gè)類型:

          type User = {  username: string;  gender?: "male" | "female";  age?: number;  bio?: string;  password?: string;};
          type Store = { name: string; location: string; leader: User; warehouseKeeper: User; cashier: User;};

          當(dāng)然,你還可以這樣定義:

          type Store = Record<'leader' | 'warehouseKeeper' | 'cashier', User> & {  name: string;  location: string;}

          兩種方式,哪種更好,當(dāng)然各有優(yōu)劣,但是假設(shè)我們遇到下面這樣的一個(gè)情況:

          type User = {  username: string;  gender?: "male" | "female";  age?: number;  bio?: string;  password?: string;};
          const users: User = [ { username: "awesomeuser", }, { username: "baduser", }, { username: "gooduser", },];

          為了訪問方便,我想將 users 變量轉(zhuǎn)換成一個(gè)屬性名稱為 users 數(shù)組索引,值為 users 數(shù)組元素(即 User 類型)的對象,怎么定義這樣的一個(gè)類型?

          你可以這樣:

          type UserSet = { [key: number]: User };
          const userSet: UserSet = users.reduce( (set, user, index) => ({ ...set, [index]: user }), {} as UserSet);

          你也可以這樣:

          type UserSet = Record<number, User>;

          如何自己實(shí)現(xiàn) Record?

          /** * Construct a type with a set of properties K of type T */type Record<K extends keyof any, T> = {    [P in K]: T;};

          本文完~

          學(xué)習(xí)更多技能

          請點(diǎn)擊下方公眾號

          瀏覽 33
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  成人久久影音 | 黄色一级片在线免费观看 | 先锋影音精品三级 | 国产精品视频一区二区三区 | 日本人妻精品 |