A custom data structure that supports both individual properties and arrays of properties, ideally containing only primitive values

I need to create a custom type that is a partial of a generic type, but also allows an array as a property of the corresponding type. For example, if we have the following interface:

interface DataModel {
  type: string;
  count: number;
}

The resolved type should look like this:

{
  type?: string | string[];
  count?: number | number[];
}

and behave as follows:

{ type: 'foo'} // valid
{ type: ['foo', 'bar'] } // valid
{ type: 1 } // invalid

I initially created this utility type, but it also allows non-corresponding types for the property:

type KeyOf<T> = Extract<keyof T, string>;

type FilterProps<
  T extends object,
  U extends KeyOf<T> = KeyOf<T>
> = Partial<Record<U, T[U] | T[U][]>>;

I have provided a playground which illustrates this further


Ideally, I would like the custom type to also reject properties on the model that are not primitive values, although this is not a strict requirement and I may be able to solve it myself.

Answer №1

To assign different types to each key, you can utilize mapped types:

interface InfoModel {
  category: string;
  quantity: number;
}

type PropertyValues<U> = {
  [P in keyof U]?: U[P] | U[P][]
}

let example1: PropertyValues<InfoModel> = { category: 'example' }
let example2: PropertyValues<InfoModel> = { category: ['example', 'sample'] }
let example3: PropertyValues<InfoModel> = { category: 42 } // Error

Answer №2

Expanding on the response provided by @daylily and implementing a restriction to only allow primitive values from the original object, you can utilize the following approach:

type FilterProps<T> =  {
  [K in keyof T]?: T[K] extends (string | number | boolean)
    ? T[K] | T[K][]
    : never
};

interactive demo

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

When {} = {} is utilized in an Angular constructor, what is its function?

While going through an Angular dynamic forms tutorial, I came across this code snippet and got confused by the {} = {} in the constructor. Here is the complete snippet: export class QuestionBase<T> { value: T; key: string; label: string; re ...

Angular Error TS2339: The property 'car' is missing from type 'Array of Vehicles'

Encountering Angular Error TS2339: Property 'vehicle' is not found on type 'Vehicle[]'. The error is occurring on data.vehicle.results. Any thoughts on what could be causing this issue? Is the problem related to the Vehicle model? I hav ...

Is there a way to modify Font Awesome icon and text based on a specific condition?

component.html <i [title]="CardData.quantity > 1 || _ShippingVariable > 1 ? CannotShip : FreeShipping" [ngClass]="{'fa': true,'fa-youtube': socialMediaLink.socialMediaType === 'YOUTUBE',}"> ...

Dealing with the possibility of an empty array when accessing elements by index in Typescript

What is the best way to handle accessing elements by index in an array in Typescript when the array can be empty, resulting in potentially undefined elements? I am developing a simple game using React and Typescript where I have a variable named game whic ...

"Encountering a problem with Typescript when working with arrays

There are different types that I am working with type Asset = { id: string, name: string, recordedBy: string } type User = { id: string, name: string, dob?: Date } type Device = { id: string, name: string, location: [n ...

Angular 7/8 - A guide to accessing URL parameters within the app component

Currently, I have implemented Single Sign-On feature on my application. However, for testing purposes, I need to extract values from the URL localhost:4200/?id=test&name=testing&<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfe ...

Angular2 - Utilizing the "withCredentials" Request Setting

I encountered a CORS problem while attempting to connect to Neo4j in an Angular2 component: Response to preflight request doesn't pass access control check. A wildcard '*' cannot be used in the 'Access-Control-Allow-Origin' header ...

What is the reason TypeScript struggles to automatically deduce assignments of identical object types?

Imagine a scenario with a simple code snippet to illustrate the issue: interface I { n?: number; s?: string; } const a: I = { n: 1, } const b: I = { n: 2, s: 'b', } const props = ['n', 's'] as const; for (const p ...

Enter the output of a function that includes keys found within a given array of elements

Here's a function I've been working on: type Action = 'doX' | 'doY' function canIPerform(actions: Action[]) : {[action: string]: Boolean} { // Some business logic return {'doX': true} } My goal is to type it ...

Convert an observable into an array so that it can be used to create a Google chart

I've been working with Angular CLI 6 and Angularfire2, and my code is functioning well to display data in the template using a typical ngFor loop and an asynchronous pipe. However, I also need to utilize the data for a Google graph, which requires dat ...

The ongoing ESLint conundrum: Balancing between "Unused variable" and "Unknown type" errors when utilizing imports for type annotations

I've encountered a linting issue and I need some guidance on how to resolve it. Here's the scenario - when running $ yarn lint -v yarn run v1.22.4 $ eslint . -v v6.8.0 With plugins vue and @typescript-eslint, I have the following code in a .ts ...

Tips for handling catch errors in fetch POST requests in React Native

I am facing an issue with handling errors when making a POST request in React Native. I understand that there is a catch block for network connection errors, but how can I handle errors received from the response when the username or password is incorrec ...

How to use sinon to create a mock for an independently imported function

Is there a way to successfully mock the axios import using sinon and then set expectations? Here is my attempted code: import axios from 'axios'; axiosMock = sinon.mock(axios); However, the expectation does not pass: describe('Custom test ...

Tips for populating class attributes from an Angular model

Suppose there is a Class Vehicle with the following properties: public id: number; public modelId: number; public modelName: string; Now consider we have an object that looks like this {id: 1, modelId: 1, modelName: "4"} What is the best way to assign e ...

Achieving Jest integration with Angular 9 in a Storybook setup

We are currently utilizing Storybook 5 alongside Angular 9, with Jest 26 for some of the testing procedures. The issue we're facing arises when using Typescript version below 3.8.0 - a requirement for Angular 9's ng build --prod. This results in ...

Using Node.js, use the `require()` function to bring in external modules

In my development of an application using Typescript that compiles into node code, I find myself favoring import statements over require. When attempting to utilize Lodash with Lodash-Deep, the official documentation suggests using: const _ = require("dee ...

Unable to use global modules in NestJS without importing them

Currently, I am in the process of integrating a global module into my nest.js project I have written a service as shown below: export interface ConfigData { DB_NAME: string; } @Injectable() export class ConfigManager { private static _inst ...

Angular 2: Firebase fails to provide a response

I am facing an issue with retrieving data from my Firebase using Angular 2 and TypeScript. While console.log() works, I am unable to return the value into a variable. My DataService looks like this: import {Injectable} from "angular2/core"; import ' ...

Upon completion of a promise in an express middleware and breaking out of a loop, a 404 error is returned

In my efforts to retrieve an array of object (car) from express using database functions in conjunction with the stolenCarDb object, everything seems to be working fine. However, when attempting the following code snippet, it results in a 404 error w ...

Using typescript with Ramda's filter and prop functions can lead to unexpected errors

I'm new to TypeScript and currently facing the challenge of converting JavaScript functions that use Ramda library into TypeScript functions. The lack of clear TypeScript usage in the Ramda documentation is making this task quite difficult for me. Sp ...