Home > Web Front-end > JS Tutorial > Dynamically Generating Interfaces and Validation Schemas in TypeScript with Yup

Dynamically Generating Interfaces and Validation Schemas in TypeScript with Yup

DDD
Release: 2025-01-24 16:35:11
Original
964 people have browsed it

Dynamically Generating Interfaces and Validation Schemas in TypeScript with Yup

In a recent project, I ran into a problem where I needed to validate an object whose keys were dynamically defined by a constant map and enforce that at least one key had a valid value.

Challenge

We have a MetadataMap object that defines the valid keys and their corresponding types:

<code class="language-typescript">const MetadataMap = {  
 userId: Number,  
 utmSource: String,  
 utmMedium: String,  
 utmCampaign: String,  
} as const;</code>
Copy after login

According to this mapping, we need:

  1. Dynamicly generate a TypeScript interface to enforce type safety.
  2. Create a Yup validation schema to validate objects based on mapping.
  3. Make sure at least one key in the object has a valid value (not undefined).
  4. Avoid hardcoding keys to improve the maintainability of the solution.

However, TypeScript enforces static typing at compile time, while Yup handles runtime verification.

Step 1: Generate interface To generate a TypeScript interface from a MetadataMap, we use keyof and map types. Here's how we define it:

<code class="language-typescript">type Metadata = {  
 [K in keyof typeof MetadataMap]: typeof MetadataMap[K] extends NumberConstructor  
  ? number  
  : string;  
};</code>
Copy after login

This approach ensures that any updates to the MetadataMap are automatically reflected in the Metadata interface. For example:

// Generated Metadata interface:

<code class="language-typescript">interface Metadata {  
 userId?: number;  
 utmSource?: string;  
 utmMedium?: string;  
 utmCampaign?: string;  
}</code>
Copy after login

Step 2: Dynamically generate Yup pattern

We need to dynamically create a Yup schema that matches the keys and types in the MetadataMap. Using Object.keys and reduce, we map each key to its corresponding Yup validator:

<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>
Copy after login

This approach eliminates hardcoding and ensures that changes in the MetadataMap are reflected in the schema without the need for manual updates.

Step 3: Add the "at least one key" rule

The next challenge is to ensure that at least one key in the object has a defined value. We added a .test method in Yup mode:

<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>
Copy after login

This logic:

  1. Make sure the object is valid.
  2. Dynamically extract valid keys from MetadataMap.
  3. Verify that at least one key has a non-undefined value.

Results Here's how the final mode behaves:

<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>
Copy after login

In this example, the validation succeeds because utmSource is a valid key with a non-undefined value, even though userId is undefined and extraField is not part of the MetadataMap.

The above is the detailed content of Dynamically Generating Interfaces and Validation Schemas in TypeScript with Yup. For more information, please follow other related articles on the PHP Chinese website!

source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template