How can I designate inner schemas as optional in Ajv?

Here is a sample schema using ajv (v8.11.2)

import Ajv, { JSONSchemaType } from "ajv";

interface MyType {
    myProp?: OtherType;
}

interface OtherType {
    foo: string;
    bar: number;
}

const otherSchema: JSONSchemaType<OtherType> = {
    type: 'object',
    properties: {
        foo: { type: 'string', minLength: 1 },
        bar: { type: 'number' },
    },
    required: ['foo', 'bar'],
    additionalProperties: false
};

const mySchema: JSONSchemaType<MyType> = {
    type: 'object',
    properties: {
        myProp: otherSchema,
    },
    required: [],
    additionalProperties: false,
};

An error occurs:

Types of property '$ref' are incompatible. Type 'string | undefined' is not assignable to type 'string'. Type 'undefined' is not assignable to type 'string'.

The issue may be due to TypeScript not recognizing that myProp in mySchema could be undefined even though it is not in the required list.

Any suggestions on how to resolve this schema error?

Answer №1

Follow these steps for success:

import { JSONSchemaType } from "ajv";

interface DifferentType {
  cat: string;
  dog: number;
}

interface YourType {
  yourProp?: DifferentType;
}

export const differentSchema: JSONSchemaType<DifferentType> = {
  type: "object",
  properties: {
    cat: { type: "string", minLength: 1 },
    dog: { type: "number" }
  },
  required: ["cat", "dog"],
  additionalProperties: false
};

export const yourSchema: JSONSchemaType<YourType> = {
  type: "object",
  properties: {
    // Place your objects inside "properties"
    yourProp: {
      ...differentSchema,
      nullable: true // Don't forget this nullable parameter!
    }
  },
  required: [],
  additionalProperties: false
};

Check out this live example:

https://codesandbox.io/s/ajv-schema-json-nested-qu9e7q?file=/src/schemas.ts

Answer №2

The issue seems to stem from the discrepancy between the type declared for myProp in your MyType and the object type set for that property in your schema. TypeScript is pointing out the type mismatch because OtherType is not the same as JSONSchemaType<OtherType>.

To resolve this, you can update your MyType as follows:

interface MyType {
  myProp?: JSONSchemaType<OtherType>;
}

While I may not be familiar with the ajv package or the JSONSchemaType type, I believe this adjustment should address the error you've encountered.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

How is it that TypeScript still expects a valid return from an overridden method, even when it cannot be reached?

After creating a generic RESTClient with some abstract functions, I encountered an issue where not all REST actions are implemented. In these cases, I wanted to throw an error. The problem arose when trying to override the TypeScript method to both return ...

Creating a unique user interface for VSCode extension

Recently, I've delved into the world of developing extensions for Visual Studio. Unfortunately, my expertise in TypeScript and Visual Studio Code is quite limited. My goal is to create an extension that mirrors the functionality of activate-power-mod ...

Why is my Angular Reactive form not retrieving the value from a hidden field?

I've encountered a problem where the hidden field in my form is not capturing the product id unless I manually type or change its value. It consistently shows as "none" when submitting the form. TS https://i.stack.imgur.com/W9aIm.png HTML https://i. ...

Error TS2322: The specified type Login cannot be assigned to the given type

I've been facing an issue while working on my app in react native. The error message I keep encountering is as follows: TS2322: Type 'typeof Login' is not assignable to type ScreenComponentType<ParamListBase, "Login"> | undefined Type ...

Refreshing the Mat Dialog content when removing items in Angular Material

I have successfully implemented a mat dialog table with 3 columns - name, email, and delete icon. When the user clicks on the delete icon, it prompts a confirmation message to confirm the deletion. Upon confirming, the item is removed from the database. Ho ...

Exploring the versatility of Vue.js through props and scoped slots

Coming from a React background, I am used to being able to easily alter children components before they render. However, after spending hours reading the VueJS documentation and searching forums, I have not been able to find a straightforward way to do thi ...

Where is the best place to import styles in NextJS?

I have an existing project with a file importing the following function import theme from 'src/configs/theme' However, when I created a new Next.js project and replicated the same folder structure and imported the same function, it is showing "m ...

What is the best way to shorten text in Angular?

I am looking to display smaller text on my website. I have considered creating a custom pipe to truncate strings, but in my situation it's not applicable. Here's what I'm dealing with: <p [innerHTML]="aboutUs"></p> Due to t ...

Delivering a static Angular app through an Express Server

In my current setup, I have an Angular app being served as static content in an Express Server. When Express serves static files, it automatically adds an ETag to them. Subsequent requests will then check if the ETag matches before sending the files agai ...

Input value not being displayed in one-way binding

I have a challenge in binding the input value (within a foreach loop) in the HTML section of my component to a function: <input [ngModel]="getStepParameterValue(parameter, testCaseStep)" required /> ... // Retrieving the previously saved v ...

Compiling errors arise due to TypeScript 2.4 Generic Inference

Experiencing issues with existing TypeScript code breaking due to changes in generic inference. For instance: interface Task { num: number; } interface MyTask extends Task { description: string; } interface Job {} type Executor<J> = <T ...

The 'innerHTML' property is not present in the 'EventTarget' type

Currently, I am working with React and Typescript. My goal is to store an address in the localStorage whenever a user clicks on any of the available addresses displayed as text within p elements. <div className="lookup-result-container& ...

What is the best method for replacing the current page in an Ionic app?

I am facing an issue with the following navigation flow: User lands on the Contacts page -> clicks on a button to navigate to the NewContact page using navController.push() method -> from there, user is directed to the ContactCreated page. How can ...

Retrieve an additional 10 items from the API when the button in the Angular list is clicked

I need to display 10 items each time the button is clicked. Below is the code snippet for the services: import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http' @Injectable({ providedIn: ' ...

I attempted to unsubscribe from an observable in Angular, but I encountered an error stating that the unsubscribe function does not exist

Here is the code snippet from a components.ts file in an Angular project. I encountered the following error during compilation: ERROR merge/merge.component.ts:75:12 - error TS2551: Property 'unsubscribe' does not exist on type 'Observable& ...

The member 'email' is not found in the promise type 'KindeUser | null'

I'm currently developing a chat feature that includes PDF document integration, using '@kinde-oss/kinde-auth-nextjs/server' for authentication. When trying to retrieve the 'email' property from the user object obtained through &apo ...

Issues with Cross-Origin Resource Sharing (CORS) have been identified on the latest versions of Android in Ionic Cordova. However, this problem does not

I am encountering an issue with my TypeScript Ionic code. It works well in browsers and some older mobile devices, but it fails to function on newer Android versions like 8+. I need assistance in resolving this problem. import { Injectable } from '@an ...

What is the process for extracting dates in JavaScript?

I need help extracting the proper date value from a long date string. Here is the initial date: Sun Aug 30 2020 00:00:00 GMT+0200 (Central European Summer Time) How can I parse this date to: 2020-08-30? Additionally, I have another scenario: Tue Aug 25 ...

Deliver router services for central Angular 2 elements

I am working on an ng2 app where I have the app/app.module and core/core.module. In the core modules, there are some modules that are used at the app top level and only once as mentioned in the official documentation. However, one of these modules requires ...

Comparing TypeScript's `return;` with `return undefined;`: which is better?

I encountered a strange behavior that is puzzling to me, and I'm not sure if there's a logical explanation for it. In TypeScript, the following code works perfectly: type UndefinedFunction = () => undefined; let uf: UndefinedFunction = funct ...