在一個最近的項目中,我遇到一個問題,需要驗證一個對象,其鍵由一個常量映射動態定義,並強制至少一個鍵具有有效值。
挑戰
我們有一個MetadataMap對象,它定義了有效的鍵及其對應的類型:
<code class="language-typescript">const MetadataMap = { userId: Number, utmSource: String, utmMedium: String, utmCampaign: String, } as const;</code>
根據此映射,我們需要:
但是,TypeScript在編譯時強制執行靜態類型,而Yup處理運行時驗證。
步驟1:生成接口
為了從MetadataMap生成TypeScript接口,我們使用了keyof
和映射類型。以下是我們定義它的方式:
<code class="language-typescript">type Metadata = { [K in keyof typeof MetadataMap]: typeof MetadataMap[K] extends NumberConstructor ? number : string; };</code>
這種方法確保了MetadataMap的任何更新都會自動反映在Metadata接口中。例如:
// 生成的Metadata接口:
<code class="language-typescript">interface Metadata { userId?: number; utmSource?: string; utmMedium?: string; utmCampaign?: string; }</code>
步驟2:動態生成Yup模式
我們需要動態創建一個與MetadataMap中的鍵和類型匹配的Yup模式。使用Object.keys
和reduce
,我們將每個鍵映射到其對應的Yup驗證器:
<code class="language-typescript">const metadataSchema = Yup.object( Object.keys(MetadataMap).reduce((schema, key) => { const type = MetadataMap[key as keyof typeof MetadataMap]; if (type === Number) { schema[key] = Yup.number().optional(); } else if (type === String) { schema[key] = Yup.string().optional(); } return schema; }, {} as Record<string, any>) );</code>
此方法消除了硬編碼,並確保了MetadataMap中的更改會在無需手動更新的情況下反映在模式中。
步驟3:添加“至少一個鍵”規則
下一個挑戰是確保對像中至少一個鍵具有定義的值。我們在Yup模式中添加了一個.test
方法:
<code class="language-typescript">metadataSchema.test( "at-least-one-key", "Metadata must have at least one valid key.", (value) => { if (!value || typeof value !== "object") return false; const validKeys = Object.keys(MetadataMap) as (keyof typeof MetadataMap)[]; return validKeys.some((key) => key in value && value[key] !== undefined); } );</code>
此邏輯:
結果 以下是最終模式的行為:
<code class="language-typescript">const exampleMetadata = { userId: undefined, utmSource: "google", extraField: "invalid", // 此键被忽略。 }; metadataSchema .validate(exampleMetadata) .then(() => console.log("Validation succeeded")) .catch((err) => console.error("Validation failed:", err.errors));</code>
在此示例中,驗證成功,因為utmSource是一個具有非undefined值的有效鍵,即使userId未定義且extraField不是MetadataMap的一部分。
以上是用yup動態生成界面和驗證模式的詳細內容。更多資訊請關注PHP中文網其他相關文章!