重建 Angular 應用程式可能是一把雙面刃。一方面,它允許您提高程式碼庫的可維護性和可擴展性。另一方面,如果您沒有採取必要的預防措施來保護您的功能免受意外更改,則可能會導致路由中斷。編寫廣泛的測試或為路由實現可靠的類型概念可以幫助減輕這種風險,但這些方法可能非常耗時,而且可能並不總是可行。在本文中,我們將探索一種更有效的解決方案,該解決方案可以在編譯時自動檢測損壞的路由,而無需手動測試工作或編寫自訂類型註解。我們將透過實作具有巢狀元件的範例 Angular 應用程式並使用 typesafe-routes 函式庫來示範此方法,以改善開發人員體驗並促進參數解析。
為了說明在編譯時自動偵測損壞的路由的好處,我們將實作一個具有三個巢狀元件的範例Angular 應用程式:DashboardComponent (/dashboard)、OrgsComponent (/orgs/:orgId) 和LocationsComponent (/ orgs) /:orgId/locations/:locationId)。要設定此範例,我們需要安裝 typesafe-routes 函式庫並使用其 createRoutes 函數來定義我們的路由樹,如下列程式碼片段所示。
// app.routes.ts import { createRoutes, int } from "typesafe-routes"; export const r = createRoutes({ dashboard: { path: ["dashboard"], // ~> "/dashboard" }, orgs: { path: ["orgs", int("orgId")], // ~> "/orgs/:orgId" children: { locations: { path: ["locations", int("locationId")], // ~> "locations/:locationId" query: [int.optional("page")], // ~> "?page=[number]" }, }, }, });
讓我們仔細看看程式碼片段。我們從 typesafe-routes 匯入 createRoutes 並將我們的路由作為其第一個參數傳遞。這些路由被定義為一個嵌套對象,在根層級具有兩個屬性:儀表板和組織。每個屬性都指派一個路徑,以陣列的形式指定段。例如,[“dashboard”]陣列對應於路徑/dashboard。 orgs 路徑更複雜,因為它包含一個名為 orgId 的整數類型參數。請注意,整數不是原生 JavaScript 類型,而是使用 int 函數定義的自訂類型,它在背景使用數字來模仿整數的特徵。 orgs 路由有一個children 屬性,它指定一個名為locations 的子路由。 Locations 路由與 orgs 路由類似,但它指定了一個額外的可選 int 類型的搜尋參數頁面。
createRoutes 使用有關路由的資訊來建立包裝在 Proxy 物件中的上下文。您不需要了解有關該代理對象的詳細信息,但必須了解,由於該對象,您可以訪問應用程式中任何位置的所有路由規範來渲染和解析路由和參數。
我們將createRoutes傳回的Proxy物件指派給r。這意味著您可以使用 r.dashboard 存取儀表板路徑,使用 r.orgs.locations 存取位置路徑,等等。
定義了路由後,我們現在可以繼續下一步:使用 Angular-router 註冊它們。
// app.routes.ts import { createRoutes, int } from "typesafe-routes"; export const r = createRoutes({ dashboard: { path: ["dashboard"], // ~> "/dashboard" }, orgs: { path: ["orgs", int("orgId")], // ~> "/orgs/:orgId" children: { locations: { path: ["locations", int("locationId")], // ~> "locations/:locationId" query: [int.optional("page")], // ~> "?page=[number]" }, }, }, });
程式碼片段顯示了 Angular Router 的巢狀路由的常見設置,它反映了我們先前定義的路由樹。但是,我們沒有使用典型的純字串來指定路徑模板(例如 orgs/:orgId),而是從 typesafe-routes/angular-router 匯入模板函數並使用它來產生路徑模板。對於DashboardComponent和OrgsComponent,我們可以簡單地呼叫template及其對應的路徑r.dashboard和r.orgs來取得模板。然而,剩下的元件LocationsComponent 是OrgsComponent 的子元件,因此需要一個相對路徑,該路徑不能透過使用r.orgs.locations 生成,因為這會導致絕對路徑orgs/:orgId/locations/:locationId,而Angular Router嵌套路由模板時需要相對路徑。
要產生相對路徑,我們可以使用 _ 鏈接,它有效地忽略下劃線字元之前的所有內容。在這種情況下,我們可以使用 template(r.orgs._.locations) 來產生相對路徑。這是一個方便的功能,因為它允許我們在需要渲染絕對路徑的場景以及需要相對路徑的情況下重複使用相同的路由樹。
此時,我們已經在我們最喜歡的 IDE(例如 Visual Studio Code)中利用了自動完成和拼字錯誤預防功能。未來的變更將提醒我們路由路徑中的任何拼字錯誤或拼字錯誤,因為所有類型都可以使用 createRoutes 追溯到初始路由定義。
現在我們已經指定了路線模板,我們要繼續進行連結渲染。為此,我們希望創建一個簡單的元件,利用渲染函數來渲染這些鏈接,包括類型序列化和類型檢查。下一個範例顯示了一個元件,該元件呈現引用我們應用程式中其他元件的錨元素清單。
// app.routes.ts import { Routes } from "@angular/router"; import { template } from "typesafe-routes/angular-router"; export const routes: Routes = [ { path: template(r.dashboard), // ~> "dashboard" component: DashboardComponent, }, { path: template(r.orgs), // ~> "orgs/:orgId" component: OrgsComponent, children: [ { path: template(r.orgs._.locations), // ~> "locations/:locationId" component: LocationsComponent, }, ], }, ];
程式碼範例從 typesafe-routes/angular-router 匯入 render 和 renderPath。 renderPath 渲染路徑,而 render 也序列化連結清單的查詢參數。我們還導入 r,代理對象,它允許我們訪問有關先前定義的路線的資訊並定義要渲染的所需路線。
首先,我們使用 renderPath 函數建立dashboardLink 和orgsLink。作為第一個參數,它採用前面提到的代表要渲染的路線的路徑的代理物件。第二個參數是一筆記錄,其參數值與先前在 app.routes.ts 中使用 createRoutes 定義的參數的名稱和類型相符。傳回值是一個字串,包含屬於對應元件的路徑。
第三個範例中的渲染函數渲染路徑和搜尋參數,因此在參數定義中需要路徑和查詢屬性。這裡的回傳值是一個對象,有path和query兩個屬性。我們將這兩個屬性設定為 [routerLink] 和 [queryParams] 屬性的值。
參數解析是型別安全路由的重要組成部分。在上面的路由定義過程中,我們定義了幾個參數並給它們一個類似整數的類型 int。但是,由於參數值來自各種來源(例如 Location 物件),因此它們是基於字串的。方便的是,typesafe-routes 導出解析這些字串並將其轉換為所需類型的輔助函數。解析是基於我們先前建立的代理物件 r,這意味著我們必須告訴函式庫參數屬於哪個路由。下一個範例透過顯示兩個常見的解析場景來示範這一點。
// app.routes.ts import { createRoutes, int } from "typesafe-routes"; export const r = createRoutes({ dashboard: { path: ["dashboard"], // ~> "/dashboard" }, orgs: { path: ["orgs", int("orgId")], // ~> "/orgs/:orgId" children: { locations: { path: ["locations", int("locationId")], // ~> "locations/:locationId" query: [int.optional("page")], // ~> "?page=[number]" }, }, }, });
給定location.href orgs/1/location/2?page=5,在Angular 中,我們可以使用this.route.snapshot.queryParams 存取基於字串的查詢參數,並且透過此提供基於字串的路徑參數。路線.快照.參數。將 parseQuery 與 r.orgs.locations 和 this.route.snapshot.queryParams 結合使用,我們可以檢索頁面參數為數字的物件。將 parsePath 與 r.orgs._.locations 和 this.route.snapshot.params 一起使用,我們得到解析後的 locationId。在這種情況下,r.orgs._.locations 是相對路徑,並且 _ 連結之前的所有段落都被省略,導致 orgId 不存在於結果物件中。
typesafe-routes 中的解析函數是通用的,我們也可以使用 parse 直接從 location.href 字串中一次提取所有參數。
// app.routes.ts import { Routes } from "@angular/router"; import { template } from "typesafe-routes/angular-router"; export const routes: Routes = [ { path: template(r.dashboard), // ~> "dashboard" component: DashboardComponent, }, { path: template(r.orgs), // ~> "orgs/:orgId" component: OrgsComponent, children: [ { path: template(r.orgs._.locations), // ~> "locations/:locationId" component: LocationsComponent, }, ], }, ];
可以透過 InferQueryParams、InferPathParams 或 InferParams 提取有關參數的類型資訊。這是 InferQueryParams 實用程式類型的示範。
// app.component.ts import { render, renderPath } from "typesafe-routes/angular-router"; import { r } from "./app.routes"; @Component({ selector: "app-root", imports: [RouterOutlet, RouterLink], template: ` <h1>Absolute Links</h1> <ul> <li><a [routerLink]="dashboardLink">Dashboard</a></li> <li><a [routerLink]="orgsLink">Org</a></li> <li> <a [routerLink]="locationLink.path" [queryParams]="locationLink.query"> Location </a> </li> </ul> <router-outlet></router-outlet> `, }) export class AppComponent { dashboardLink = renderPath(r.dashboard, {}); // ~> dashboard orgsLink = renderPath(r.orgs, { orgId: 123 }); // ~> orgs/123 locationLink = render(r.orgs.locations, { path: { orgId: 321, locationId: 654 }, query: { page: 42 }, }); // ~> { path: "orgs/321/location/654", query: { page: "42" }} } // ...
為了結束本教程,我們創建了一個路由樹 r,它是我們路由的唯一事實來源。基於此,我們渲染了用於向 Angular Router 註冊元件的模板。我們使用動態路徑段和查詢參數渲染路徑。我們解析參數,將它們從字串值轉換為對應的類型。我們以類型安全的方式完成了所有事情,甚至沒有編寫一個類型定義。我們建立了一個強大的路由樹,可以在開發新功能時輕鬆防止錯誤,並進一步促進未來的重構。
但是,typesafe-routes 還有更多功能,例如許多不同的內建參數類型、自訂參數類型的輕鬆整合、子路徑的操作、定義自訂模板字串等等。不幸的是,我們無法在本教程中涵蓋所有內容,但您可以透過造訪官方文件來了解更多資訊。
當然,也可以對本教程中所示的範例實施許多潛在的改進。例如,用於連結呈現的自訂指令,它採用基於代理物件的路徑定義,例如 r.orgs.locations。另一個例子是一個為 Angular Router 自動產生 Routes 陣列的函數,有效地消除了重複的程式碼,並且無需使路由與第一個程式碼區塊中使用 createRoutes 建立的路由樹保持同步。
但是,這些只是眾多貢獻方式中的幾種。當然,最常見的方式是在我們的 GitHub 儲存庫中共用、報告錯誤或開啟 PR。如果你使用這個庫並認為它改善了你的開發體驗,你也可以請我喝杯咖啡。我們還有一個 Discord 頻道,您可以在其中留下回饋或提出問題。
以上是使用 Angular 中的類型安全路由消除執行階段錯誤的詳細內容。更多資訊請關注PHP中文網其他相關文章!