When utilizing a combination of generics in a Typescript mapped type, the resulting property type is not computed

In an attempt to create a versatile method that can handle a Mapped Type named QueryParamObject and partially read its properties:

QueryParamObject can handle any type and returns a type where all properties are either string[] or string:

export type QueryParamObject<TInput> = {
    [key in keyof TInput]: TInput[key] extends Array<string | number> ? string[] : string;
};

Everything functions perfectly when using specific types:

type Concrete = {
    numberProp: number;
    numberArray: number[];
    stringArray: string[];
}

function read(arg: QueryParamObject<Concrete>): void {
    const arr1: string[] = arg.numberArray;
    const prop1: string = arg.numberProp;

    // const arr2: number[] = arg.numberArray; //will have type error
}

However, everything breaks down and each property's resulting type becomes string[] | string when adding a Generic:

function read<TExtra>(arg: QueryParamObject<TExtra & Concrete>): void {
    const arr1: string[] = arg.numberArray; //Type 'string | string[]' is not assignable to type 'string[]'
}

https://i.sstatic.net/j7Eev.png

Example

What is the issue with this notation? How can I get TypeScript to correctly infer those properties even with the use of Generics?

Answer №1

QueryParamObject deals with the intersection of a generic type TExtra and a specific type Concrete. When utilizing generic types to derive other types through mapped types or conditionals, the compiler may struggle to fully comprehend the overall implications of those types.

Typically, the compiler avoids computing the result of these generic types, resulting in obscure types that offer limited utility. However, in the case of a mapped type like the one shown here, the compiler demonstrates some level of intelligence by recognizing that a property of QueryParamObject can be either string[] | number.

To achieve a more satisfactory outcome, it is advisable to shift the intersection.

function read<TExtra>(
  arg: QueryParamObject<Concrete> & QueryParamObject<TExtra>
): void {
    const arr1: string[] = arg.numberArray;
}

The compiler can now effectively analyze and understand QueryParamObject<Concrete>, enabling access to the three properties with the correct types. The intersection with QueryParamObject<TExtra> serves as a type constraint for the function's caller.


Playground

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 an import is included, a Typescript self-executing function will fail to run

Looking at this Typescript code: (()=> { console.log('called boot'); // 'called boot' })(); The resulting JavaScript is: (function () { console.log('called boot'); })(); define("StockMarketService", ["require", "exp ...

Removing HTML Tags in Ionic - A How-To Guide

After utilizing Ionic 3 to retrieve data from a WordPress API, I am encountering an issue with displaying the content on the app UI. The problem arises from the presence of HTML tags within the content being printed along with the text. While seeking solut ...

Getting into a dynamic named property inside another object in angular can be achieved by utilizing bracket notation

I encountered an issue in my Angular 8 project where I create an object from a JSON, but there is a dynamic property whose name is unknown until runtime. This causes problems when trying to access the value of that dynamic property within another object, l ...

Encountered an issue when attempting to include a model in sequelize-typescript

I've been attempting to incorporate a model using sequelize-typescript: type AppMetaDataAttributes = { id: string; name: string; version: string; createdAt: string; updatedAt: string; }; type AppMetaDataCreationAttributes = Optional<App ...

Ways to determine the number of duplicate items in an Array

I have an array of objects that contain part numbers, brand names, and supplier names. I need to find a concise and efficient way to determine the count of duplicate objects in the array. [ { partNum: 'ACDC1007', brandName: 'Electric&apo ...

Utilizing a string variable as a property name for dynamic typing

I am looking to dynamically create a type with a property name based on specified parameters. Although I can successfully create the object, I am facing challenges when trying to create the actual type. This dynamic type creation is essential for compositi ...

Generating React Components Dynamically using TypeScript

Attempting to generate an element in React using Typescript based on the given tagName passed as props, along with additional relative element properties depending on that particular tagName. Take a look at the code snippet below: type ElementProps<Tag ...

What is the best way to transfer image files into a specific folder?

I am currently in the process of developing a ReactJS web application. My goal is to upload images to a specific folder and then store the file name in the database for future use. Everything seems to be working smoothly up to this point, but I am facing ...

What is the best way to determine the final letter of a column in a Google Sheet, starting from the first letter and using a set of

My current approach involves generating a single letter, but my code breaks if there is a large amount of data and it exceeds column Z. Here is the working code that will produce a, d: const countData = [1, 2, 3, 4].length; const initialLetter = 'A&a ...

Creating circular artwork with PixiJS: A step-by-step guide

I am trying to create a circular image with specific height and width dimensions, but have not found a satisfactory solution. Currently, I can achieve this using a texture, however it is drawn multiple times in the same position. const test = new Graphic ...

Checking for unnecessary properties in Typescript with vue-i18n

Let's consider two different languages represented in JSON format: jp.json { "hello": "こんにちは" } ge.json { "hello": "hallo", "world": "welt" } Now, we are going to com ...

Creating a unique Elastic IP address for a single EC2 instance with the AWS CDK

I'm having an issue with my AWS CDK Stack where multiple Elastic IPs are being created for each public subnet in my VPC instead of just one. I only want one Elastic IP to be associated with a single EC2 instance. My simplified code snippet is as foll ...

Unable to locate the specified environment variable in the current nest

Currently, I am referring to the official documentation on the NestJs website that provides a guide on using config files: https://docs.nestjs.com/techniques/configuration Below is the code snippet I am working with: app.module import { Module } from &ap ...

Elastic_Frame | "Error: Unable to process action as property 'toLowerCase' is not defined"

Attempting to create a personal and project portfolio using Vu Khanh Truong's "elastic_grid" jQuery plugin for the actual portfolio. You can access it here. However, encountering some issues on my page: 1) The header for the portfolio section disappe ...

Best practices for safely handling dynamic keys in Typescript

I am searching for a secure method to create keyed objects in this manner: interface Types { RED: 'RED'; BLUE: 'BLUE'; GREEN: 'GREEN'; } type TypeKeys = keyof Types; const COLORS: Types = { RED: 'RED', B ...

Incorporating aws-sdk into Angular 2 for enhanced functionality

I'm currently working on integrating my Angular2 application with an s3 bucket on my AWS account for reading and writing data. In the past, we used the aws-sdk in AngularJS (and most other projects), so I assumed that the same would apply to Angular2 ...

The data type 'string' cannot be assigned to the type '(url: string) => string'.ts(2322)

I am working with a Material UI copyright component: export default function Copyright(link: string, text: string) { return ( <Typography variant="body2" color="textSecondary" align="center"> {'Copyright © '} <Link co ...

Sorting TypeScript types by required properties first

Can anyone recommend a plugin or ESLint rule that can automatically sort types by assuming required fields come first, followed by optional fields? Here's an example before: type TExampleSorting = { title?: string; value?: number; text: string; ...

When a webpage is moved, the globalProperties variable of "vue3 typescript" is initialized to null

main.ts const app = createApp(App) .use(router) .use(createPinia()) .use(vuetify) .use(vue3GoogleLogin, googleLogin) const globalProps = app.config.globalProperties; globalProps.isDebugMode = true; vue-shim declare ...

Tips for converting text input in a textbox to a Date value

My knowledge of Angular is limited, and we are currently using Angular 10. In our application, there is a textbox where users need to input a date in the format 10202020. This value should then be reformatted as 10/20/2020 and displayed back in the same ...