<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>

          10 個關(guān)于 TypeScript 的小技巧

          共 5467字,需瀏覽 11分鐘

           ·

          2020-12-13 09:13

          英文 |?https://www.sangle7.com/


          1、?TypeScript 和 DOM


          當(dāng)你開始使用 TypeScript 時,你會發(fā)現(xiàn)在瀏覽器環(huán)境中使用它,你需要非常了解它。假設(shè)我想在頁面搜索框里找到一個元素:


          const textEl = document.querySelector('inpot');console.log(textEl.value);// ? Property 'value' does not exist on type 'Element'.


          Oops…… 拋出了一個錯誤,因為我把 ‘input’ 打成了 ‘inpot’
          它怎么知道的?答案在于 lib.dom.d.ts 文件,該文件是 TypeScript 庫的一部分,并且基本上描述了瀏覽器中發(fā)生的所有事情(對象,函數(shù),事件)。?
          該定義的一部分是在 querySelector 方法的輸入中使用的接口,并將特定的字符串文字(例如’div’, ‘table’或’input’)映射到相應(yīng)的 HTML 元素類型:


          interface HTMLElementTagNameMap {  a: HTMLAnchorElement;  abbr: HTMLElement;  address: HTMLElement;  applet: HTMLAppletElement;  area: HTMLAreaElement;  article: HTMLElement;  /* ... */  input: HTMLInputElement;  /* ... */}


          這不是一個完美的解決方案,因為它僅適用于基本元素選擇器,但總比沒有好,對吧?
          這種’智能’TypeScript 行為的另一個示例是在處理瀏覽器事件時:


          textEl.addEventListener('click', (e) => {  console.log(e.clientX);});


          上面的示例中的.clientX 在任何給定事件上都不可用-僅在 MouseEvent 上可用。然后 TypeScript 根據(jù)作為 addEventListener 方法中第一個參數(shù)的“click”文字確定事件的類型。


          2、期望泛型


          因此,如果您使用其他任何東西而不是元素選擇器:


          document.querySelector('input.action')


          那么 HTMLELementTagNameMap 將不再有用,TypeScript 只會返回一個相當(dāng)基本的 Element 類型。
          與 querySelector 一樣,函數(shù)通常可以返回各種不同的結(jié)構(gòu),而 TypeScript 不可能確定將是哪種結(jié)構(gòu)。在那種情況下,您可以非常期待,該函數(shù)也是通用的,并且可以使用方便的通用語法提供該返回類型:


          textEl = document.querySelector < HTMLInputElement > 'input.action';console.log(textEl.value);// ? 'value' is available because we've instructed TS// about the type the 'querySelector' function works with.

          3、“我們真的找到了嗎?”


          該 document.querySelector(…)方法實(shí)際上并不總是返回一個對象,是嗎?與選擇器匹配的元素可能不在頁面上-函數(shù)將返回 null 而不是對象。因此,默認(rèn)情況下,訪問.value 屬性可能不會保存所有內(nèi)容。
          默認(rèn)情況下,類型檢查器認(rèn)為 null 和 undefined 可分配給任何類型。您可以通過在 tsconfig.json 中添加嚴(yán)格的 null 檢查來使其更加安全并限制這種行為:


          {  "compilerOptions": {    "strictNullChecks": true  }}


          使用該設(shè)置后,如果您嘗試訪問可能為 null 的對象上的屬性,TypeScript 將會報錯,并且你將不得不確保該對象的存在,例如 通過用 if(textEl){...}?條件包裝該部分。
          除了 querySelector 之外,另一個流行的例子是 Array.find 方法,其結(jié)果可能是不確定的。
          您并非總能找到想要的東西:-)
          4、“TS,我告訴你,在這里!”
          正如我們已經(jīng)確定的那樣,通過嚴(yán)格的 null 檢查,TypeScript 將更加懷疑我們的價值觀。另一方面,有時您僅從外部就知道將設(shè)置該值。在這種特殊情況下,您可以使用“后綴表達(dá)式運(yùn)算符”:


          const textEl = document.querySelector('input');console.log(textEl!.value);// ? with "!" we assure TypeScript// that 'textEl' is not null/undefined

          5、當(dāng)遷移到 TS…


          通常,當(dāng)您具有要遷移到 TypeScript 的舊版代碼庫時,更大的麻煩之一就是使 id 遵守您的 TSLint 規(guī)則。您可以做的是通過添加以下內(nèi)容來編輯所有這些文件


          // tslint:disable


          在每個文件的第一行中,這樣 TSLint 不會真正檢查它們。然后,僅當(dāng)開發(fā)人員處理舊文件時,他才會刪除此注釋并僅修復(fù)該文件中的所有掉毛錯誤。這樣一來,我們就不會進(jìn)行革命,而只會進(jìn)行進(jìn)化-代碼庫會逐漸但安全地得到改善。
          至于將實(shí)際類型添加到舊的 JavaScript 代碼中,實(shí)際上通常可以不這樣做。只有在您有一些令人討厭的代碼(例如, 為同一變量分配不同類型的值,您可能會遇到問題。如果重構(gòu)不是一個小問題,您可以使用這個方法解決問題:


          let mything = 2;mything = 'hi';// ? Type '"hi"' is not assignable to type 'number'mything = 'hi' as any;// ? if you say "any", TypeScript says ˉ\_(ツ)_/ˉ


          但是真的,真的,真的將其用作最后的手段。我們不喜歡TypeScript中的 any。


          6、更多限制


          有時TypeScript無法推斷類型。最常見的情況是一個函數(shù)參數(shù):


          function fn(param) {    console.log(param);}


          在內(nèi)部,它需要在此處為param分配某種類型,因此它可以分配任何類型。由于我們希望將any限制為絕對最小值,因此通常建議使用另一個tsconfig.json設(shè)置來限制該行為:


          {    "compilerOptions": {        "noImplicitAny": true    }}


          不幸的是,我們不能在函數(shù)返回類型上使用這種安全帶(需要明確輸入)。因此,如果改為使用函數(shù)fn(param):string {我會忘記該類型(函數(shù)fn(param){),TypeScript將不會關(guān)注我返回的內(nèi)容,即使我從該函數(shù)返回了任何內(nèi)容。更準(zhǔn)確地說:它將根據(jù)您退回或未退回的商品推斷出退貨價值。
          幸運(yùn)的是,TSLint可以為您提供幫助。使用typedef規(guī)則,您可以使返回類型成為必需:


          {    "rules": {        "typedef": [            true,            "call-signature"        ]    }}


          這看起來是個好主意!


          7、類型保護(hù)


          當(dāng)值具有多種類型時,必須在算法中將其考慮在內(nèi),以區(qū)分一種類型與另一種類型。關(guān)于TypeScript的事情是它了解這種邏輯。


          type BookId = number | string;function returnFormatterId(id: BookId) {    return id.toUpperCase();    // ? 'toUpperCase' does not exist on type 'number'.}function returnFormatterId(id: BookId) {    if (typeof id === 'string') {        // we've made sure it's a string:        return id.toUpperCase(); // so it's ?    }    // ? TS also understands that it    // has to be a number here:    return id.toFixed(2)}

          8、再談泛型


          假設(shè)我們具有這種相當(dāng)通用的結(jié)構(gòu):


          interface Bookmark {    id: string;}class BookmarksService {    items: Bookmark[] = [];}


          您想在不同的應(yīng)用程序中使用它,例如 用于存儲書籍或電影。
          在這樣的應(yīng)用程序中,您可以執(zhí)行以下操作:


          interface Movie {    id: string;    name: string;}class SearchPageComponent {    movie: Movie;    constructor(private bs: BookmarksService) {}    getFirstMovie() {        // ? types are not assignable        this.movie = this.bs.items[0];        // ? so you have to manually assert type:        this.movie = this.bs.items[0] as Movie;    }    getSecondMovie() {        this.movie = this.bs.items[1] as Movie;    }}


          在該類中可能需要多次這種類型聲明。
          我們可以做的是將 BookmarksService 類定義為通用類:


          class BookmarksService {    items: T[] = [];}


          好吧,不過現(xiàn)在它太通用了……我們要確保此類使用的類型能夠滿足Bookmark接口(即具有id:string屬性)。這是改進(jìn)的聲明:


          class BookmarksService {    items: T[] = [];}


          現(xiàn)在,在我們的SearchPageComponent中,我們只需指定一次類型:


          class SearchPageComponent {    movie: Movie;    constructor(private bs: BookmarksService) {}    getFirstMovie() {        this.movie = this.bs.items[0]; // ?    }    getSecondMovie() {        this.movie = this.bs.items[1]; // ?    }}


          對于該通用類,還有一項可能是有用的改進(jìn)-如果您以這種通用身份在其他地方使用它,而又不想編寫B(tài)ookmarksService?的話。
          您可以在泛型的定義中提供默認(rèn)類型:


          class BookmarksService {    items: T[] = [];}const bs = new BookmarksService();// I don't have to provide the type for the generic now// - in that case 'bs' will be of that default type 'Bookmark'

          9、路由參數(shù)

          export interface DashboardRouteParams {  countryId: string;  deviceId: string;}
          const routes: Routes = [{ path: 'country/:countryId/device/:deviceId/dashboard'}]

          10、根據(jù) API 響應(yīng)創(chuàng)建 Interface


          如果您收到來自API的大量嵌套響應(yīng),那么手動鍵入相應(yīng)的接口確實(shí)很麻煩。這是應(yīng)該由機(jī)器處理的任務(wù)!?
          有兩種選擇:


          • http://www.json2ts.com
          • http://www.jsontots.com


          是其中的一些,但是坦率地說,它們的服務(wù)器通常不可用。由于URL的記憶力很強(qiáng),我通常只是從它們開始:-)為了獲得最佳結(jié)果和一些其他選項,請使用


          • https://app.quicktype.io/


          它還提供了一個方便的Visual Studio Code插件~
          - END -




          分享前端好文,點(diǎn)亮?在看


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

          手機(jī)掃一掃分享

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

          手機(jī)掃一掃分享

          分享
          舉報
          <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>
                  99视频在线播放观看精品 | 久热精品视频在线 | 影音先锋一区二区三区视频特色 | 久久久少妇 | 国产成人精品小电影 |