What is the best way to implement an interface for accurately checking each prop type?

Currently, while working with Typescript, I am looking for a solution to define an interface with specific properties inside my object of marks. At the moment, I am using "any", but I know there must be a better approach. Any guidance or advice on how to proceed would be greatly appreciated. Thank you in advance for your help and suggestions.

Below, I have shared both the error message and my code. As I strive to improve in TS, it would be immensely helpful to understand how to resolve this issue.

Error:

Type '{ highlight: ({ children }: { children: any; }) => Element; buttonLink: ({ text, value }: any) => Element; internalLink: ({ text, value }: any) => Element; link: ({ children, value }: any) => Element; }' is not assignable to type 'marksProps'.
  Object literal may only specify known properties, and 'highlight' does not exist in type 'marksProps'.ts(2322)

Code:

import Link from "next/link";

import { Warning } from "phosphor-react";

interface marksProps {
  children?: any;
}

export const marks: marksProps = {
  highlight: ({ children }) => <mark>{children}</mark>,

  buttonLink: ({ text, value }: any) => {
    const title = value?.colors?.title;
    const path = value?.path;

    /* prettier-ignore */
    const Theme : { [key: string]: any } = {
      neon      : "bg-neon text-navyBlue border-navyBlue hover:bg-offWhite",
      clear     : "bg-transparent text-white border-white hover:bg-offWhite hover:text-navyBlue",
      bubblegum : "bg-bubblegum text-navyBlue border-navyBlue hover:bg-offWhite hover:text-navyBlue",
      sand      : "bg-sand text-navyBlue border-navyBlue hover:bg-offWhite hover:text-navyBlue",
      navyBlue  : "bg-navyBlue text-white border-white hover:bg-offWhite hover:text-navyBlue"
    };

    const Button = () => (
      <>
        {path ? (
          <Link href={value.path}>
            <a
              className={`inline-flex items-center px-4 py-2 mt-6 text-xs font-bold text-center uppercase duration-300 ease-in-out border-2 rounded-full ${Theme[title]}`}
            >
              {text}
            </a>
          </Link>
        ) : (
          <div className="block mt-4">
            <p className="flex gap-2 text-sm font-bold text-sand place-items-center">
              <Warning size={24} color="#ffd662" weight="duotone" />
              <span>Page reference URL is required.</span>
            </p>

            <button
              disabled
              className="inline-flex items-center px-4 py-2 mt-3 text-xs font-bold text-center uppercase duration-300 ease-in-out border-2 rounded-full disabled:bg-gray-700 disabled:opacity-30"
            >
              {text}
            </button>
          </div>
        )}
      </>
    );

    return <Button />;
  },

  internalLink: ({ text, value }: any) => {
    return (
      <Link href={value.path}>
        <a className="underline cursor-pointer text-bubblegum">{text}</a>
      </Link>
    );
  },

  link: ({ children, value }: any) => {
    const blank = value.blank;

    return blank ? (
      <a
        className="underline cursor-pointer text-bubblegum"
        href={value.href}
        rel="noreferrer"
        target="_blank"
      >
        {children}
      </a>
    ) : (
      <a
        className="underline cursor-pointer text-bubblegum"
        href={value.href}
        rel="noreferrer"
      >
        {children}
      </a>
    );
  },
};

Answer №1

In order to make the necessary changes, you should adjust the children property to be an array of React.ReactNode. Additionally, ensure that you assign your type, marksProps, to the props of the marks arrow function props rather than the constant.

import React from "react";
import { Warning } from "phosphor-react";

interface marksProps {
  children?: React.ReactNode[];
}

export const marks = {
  highlight: ({ children }: marksProps) => <mark>{children}</mark>,

  buttonLink: ({ text, value }: any) => {
    const title = value?.colors?.title;
    const path = value?.path;

    /* prettier-ignore */
    const Theme : { [key: string]: any } = {
      neon      : "bg-neon text-navyBlue border-navyBlue hover:bg-offWhite",
      clear     : "bg-transparent text-white border-white hover:bg-offWhite hover:text-navyBlue",
      bubblegum : "bg-bubblegum text-navyBlue border-navyBlue hover:bg-offWhite hover:text-navyBlue",
      sand      : "bg-sand text-navyBlue border-navyBlue hover:bg-offWhite hover:text-navyBlue",
      navyBlue  : "bg-navyBlue text-white border-white hover:bg-offWhite hover:text-navyBlue"
    };

    const Button = () => (
      <>
        {path ? (
          <Link href={value.path}>
            <a
              className={`inline-flex items-center px-4 py-2 mt-6 text-xs font-bold text-center uppercase duration-300 ease-in-out border-2 rounded-full ${Theme[title]}`}
            >
              {text}
            </a>
          </Link>
        ) : (
          <div className="block mt-4">
            <p className="flex gap-2 text-sm font-bold text-sand place-items-center">
              <Warning size={24} color="#ffd662" weight="duotone" />
              <span>Page reference URL is required.</span>
            </p>

            <button
              disabled
              className="inline-flex items-center px-4 py-2 mt-3 text-xs font-bold text-center uppercase duration-300 ease-in-out border-2 rounded-full disabled:bg-gray-700 disabled:opacity-30"
            >
              {text}
            </button>
          </div>
        )}
      </>
    );

    return <Button />;
  },

  internalLink: ({ text, value }: any) => {
    return (
      <Link href={value.path}>
        <a className="underline cursor-pointer text-bubblegum">{text}</a>
      </Link>
    );
  },

  link: ({ children, value }: any) => {
    const blank = value.blank;

    return blank ? (
      <a
        className="underline cursor-pointer text-bubblegum"
        href={value.href}
        rel="noreferrer"
        target="_blank"
      >
        {children}
      </a>
    ) : (
      <a
        className="underline cursor-pointer text-bubblegum"
        href={value.href}
        rel="noreferrer"
      >
        {children}
      </a>
    );
  },
};

TypeScript Playground Link

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

What is the best way to transform this date string into a valid Firestore timestamp?

Currently, I am facing an issue in my Angular application that is integrated with Firebase Firestore database. The problem lies in updating a date field from a Firestore timestamp field. To provide some context, I have set up an update form which triggers ...

Executing npm prepublish on a complete project

I am facing a situation with some unconventional "local" npm modules that are written in TypeScript and have interdependencies like this: A -> B, C B -> C C -> D When I run npm install, it is crucial for all TypeScript compilation to happen in t ...

Select characteristics with designated attribute types

Is there a way to create a type that selects only properties from an object whose values match a specific type? For example: type PickOfValue<T, V extends T[keyof T]> = { [P in keyof (key-picking magic?)]: T[P]; }; I am looking for a solution w ...

Exploring the use of context in managing global state across multiple layouts in Next.js

My approach in next.js involves using two different layouts based on the per page layout structure. I have one layout designed for unauthenticated pages And another layout specifically for authenticated pages Inside _app.js file: import GlobalContext fro ...

Error message 2339 - The property 'toggleExpand' is not recognized on the specified type 'AccHeaderContextProps | undefined'

When utilizing the context to share data, I am encountering a type error in TypeScript stating Property 'toggleExpand' does not exist on type 'AccHeaderContextProps | undefined'.ts(2339). However, all the props have been declared. inter ...

I am unable to utilize ts-node-dev for launching a TypeScript + Express + Node project

When I try to execute the command npm run dev, I am unable to access "http://localhost:3000" in my Chrome browser. Task Execution: > npm run dev <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="fe90919a9bd3988c9f939b89918c9 ...

Is there a TypeScript rule called "no-function-constructor-with-string-args" that needs an example?

The description provided at this link is concise: Avoid using the Function constructor with a string argument to define the function body This might also apply to the rule missing-optional-annotation: A parameter that comes after one or more optiona ...

Is there a way to display an array of data in separate mat-form-field components?

I am dealing with an array that stores 4 data points: [onHour, onMinute, offHour, offMinute]. I also have 4 elements that are not in an array and need to be repeated. <div class="on"> <mat-form-field appeara ...

The Angular AJAX call was unsuccessful due to the Content-Type request header field being forbidden by the Access-Control-Allow-Headers in the preflight response

Here is the code I am using to send a post request from Angular 6 to my web service. const headers = new HttpHeaders({ 'Content-Type': 'application/json' }); const headeroptions = { headers: headers }; return this.http.post(this. ...

The error message "@graphql-eslint/eslint-plugin: problem with the "parserOptions.schema" configuration"

Our team is currently working on developing micro-services using NestJS with Typescript. Each of these services exposes a GraphQL schema, and to combine them into a single graph, we are utilizing a federation service built with NestJS as well. I recently ...

The functionality of MaterializeCSS modals seems to be experiencing issues within an Angular2 (webpack) application

My goal is to display modals with a modal-trigger without it automatically popping up during application initialization. However, every time I start my application, the modal pops up instantly. Below is the code snippet from my component .ts file: import ...

Issue encountered while attempting to access query parameter using useRouter in Next.js

Encountering a problem with accessing query parameters in Next.js 13 using the useRouter hook. Upon running the code snippet below 'use client' import { useRouter } from 'next/navigation'; const Post = () => { const router = us ...

What is the reason behind receiving a 401 unauthorized error during the login process?

Currently, I am utilizing the NextAuth.js credentials provider for managing the login process. While attempting to log in, I have implemented error handling using a try-catch block to set the appropriate error state; however, I haven't incorporated di ...

Angular compilation encounters errors

While following a tutorial from Angular University, I encountered an issue where running ng serve/npm start would fail. However, simply re-saving any file by adding or removing a blank space would result in successful compilation. You can view the screensh ...

Notifying users when a document is nearing its expiration date in the most effective manner

In my calendar app, I set appointments to automatically delete after 5 minutes. Now, I want to retrieve all appointments that are about to expire within 1 minute and send a notification to the front-end indicating their impending expiration. Although I at ...

Is there a feature similar to Nuxt.js' auto-register in Next.js?

My Journey as a Beginner Being a beginner in the tech world, specifically in full-stack development (although I'm about 8 years behind), I find myself grappling with the decision of what to focus on learning. Vue and Nuxt.js are fantastic technologi ...

Is it possible to eliminate additional properties from an object using "as" in Typescript?

I am looking for a way to send an object through JSON that implements an interface, but also contains additional properties that I do not want to include. How can I filter out everything except the interface properties so that only a pure object is sent? ...

Best practices for correctly parsing a date in UTC format using the date-fns library

My log file contains timestamps in a non-ISO format: 2020-12-03 08:30:00 2020-12-03 08:40:00 ... The timestamps are in UTC, as per the log provider's documentation. I am attempting to parse them using date-fns: const toParse = "2020-12-03 08:40 ...

NgFor is designed to bind only to Iterables like Arrays

After exploring other questions related to the same error, I realized that my approach for retrieving data is unique. I am trying to fetch data from an API and display it on the page using Angular. The http request will return an array of projects. Below ...

Unusual conduct exhibited by a 16th version Angular module?

I've created a unique component using Angular 16. It's responsible for displaying a red div with a message inside. import { ChangeDetectionStrategy, Component, Input, OnInit, } from "@angular/core"; import { MaintenanceMessage } ...