Specialized type referring to a specific attribute with an alternate data type

I am looking to create a Columns<T> type which will reference itself in one of its properties but with a different T type.

Columns<T> is an array of ColumnDefinitionType<T> union type.

type Columns<T> = ColumnDefinition<T>[];

type ColumnDefinition<T> = SubgridColumn<T> | Column<T>;

Column<T> is an object type with one property

type Column<T> = {
    render: (item: T, rowIndex: number) => React.ReactNode;
};

SubgridColumn<T> has two properties

type SubgridColumn<T> = {
    subgridItems: ((item: T, rowIndex: number) => any[]) | any[];
    subgridColumns: Columns<any>;
};

Currently, the subgridItems can be an array of any type or a function that returns an array of any type, and subgridColumns is of type Columns<any>.

I want to define the type Subgrid<T, N> where N replaces any type

type SubgridColumn<T, N> = {
    subgridItems: ((item: T, rowIndex: number) => N[]) | N[];
    subgridColumns: Columns<N>;
};

The usage of this type would be as follows:

type Cargo = { locationFrom: string; models: Model[] };
type Model = { modelName: string; parts: Part[] };
type Part = { partName: string; partPrice: number };
type UsageCountry = { countryName: string; continent: string };

const countries: UsageCountry[] = [
    { countryName: 'Ireland', continent: 'Europe' },
    { countryName: 'USA', continent: 'North America' },
];

const cargos: Cargo[] = [
    {
        locationFrom: 'London',
        models: [
            {
                modelName: 'Audi',
                parts: [
                    { partName: 'Spoiler', partPrice: 599 },
                    { partName: 'Wheel', partPrice: 199 },
                ],
            },
            { modelName: 'Subaru', parts: [{ partName: 'Tint', partPrice: 99 }] },
        ],
    },
    { locationFrom: 'Paris', models: [{ modelName: 'VW', parts: [{ partName: 'Muffler', partPrice: 159 }] }] },
];

Below are the columns with type Columns<Cargo>. It is an array of ColumnDefinition<Cargo> which can be either a Column<Cargo> or a SubgridColumn<Cargo>. In case of the latter type, I want the type of subgridColumns to be inferred from the type of subgridItems.

const columns: Columns<Cargo> = [
    { render: cargo => cargo.locationFrom },
    {
        subgridItems: cargo => cargo.models,
        subgridColumns: [
            { render: model => model.modelName },
            {
                subgridItems: model => model.parts,
                subgridColumns: [{ render: part => part.partName }, { render: part => part.partPrice }],
            },
            {
                subgridItems: model => (model.modelName === 'Subaru' ? countries : []),
                subgridColumns: [
                    {
                        render: country => country.countryName,
                    },
                ],
            },
        ],
    },
];

You may notice that the function subgridItems, when using the type Columns<Model>, returns an array of countries of type UsageCountry which is not related to the types Model or Cargo, hence the return type of subgridItems should not depend on the properties of type T in Columns<T>

How can we achieve this as the issue with the current setup is that the return type of subgridItems is always any and unsafe to use.

Answer №1

Your type is like this:

type SubgridColumn<T, N> = ⋯
. Now you want to create another type like this:

type ColumnDefinition<T> = SomeSubgridColumn<T> | Column<T>;

In the above code, SomeSubgridColumn<T> represents a SubgridColumn<T, N> for some unspecified type N that you are not concerned about.


If you come across a situation where you need a type like F<N> for an unknown type N, then you are looking at what's known as existential generics. However, TypeScript doesn't directly support existential types, and only has universally-quantified generics which work for all types of N.

To simulate an existential type, you can simply use the any type in place of the unknown generic:

type SomeSubgridColumn<T> = SubgridColumn<T, any>

While this method is straightforward, it may sacrifice type safety and does not accurately represent existential types.


An alternative approach involves encoding existential generic types using universal generic types through a structure similar to a Promise. This way, you can handle existential types by working around the limitation of TypeScript.

The concept behind encoding existential types with universal types relies on passing a callback function to capture the required hidden value. Here is how it can be done:

type SomeSubgridColumn<T> =
    <R>(cb: <N>(sc: SubgridColumn<T, N>) => R) => R;

This implementation allows you to extract the desired value by applying a callback to the concealed type within the existential construct.

Managing existential types necessitates handling them carefully, such as wrapping the data appropriately when needed. Consuming and interacting with existential types requires additional steps compared to typical universally-quantified generics.


By considering the nature of the unknown type

N</code, if it pertains to a limited set of possibilities, unions might serve as a viable replacement for existential types. In instances where <code>N
can only assume specific values, unions could offer a simpler solution without needing to simulate existential generics.

In situations where N is constrained to a finite set of types, unions might be more suitable for your requirements. By delineating the possible alternatives for N, unions can provide a clearer representation of the types involved without resorting to existential generics.

Exploring potential alternatives based on the constraints of your unknown types can help determine the most appropriate strategy for handling existential scenarios efficiently.

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

I am interested in updating the content on the page seamlessly using Angular 6 without the need to reload

As a newcomer to Angular, I am interested in dynamically changing the page content or displaying a new component with fresh information. My website currently features cards, which you can view by following this Cards link. I would like to update the page ...

After pressing the login button, my intention is to transition to a different page

I am relatively new to web development and working with angular. I have a login component that, upon hitting the LOGIN button, should redirect to another component on a different page. However, currently, when I click the button, it loads the data of the o ...

Whenever I attempt to bring in AngularFireModule, an error promptly appears

I am experiencing some errors when trying to import AngularFireModule and initialize the app with environment.firebaseConfig. I have tried to solve the problem but without success. Can anyone provide guidance on what steps I should take? @NgModule({ decl ...

Ionic - Smooth horizontal tab scrolling for sorted categories

Currently, we are developing a web/mobile application that includes horizontal scroll tabs to represent Categories. While this feature works well on mobile devices, it requires additional functionality for web browsers. Specifically, we need to add two arr ...

Ways to access a nested property within an array

I'm having an issue when trying to access a sub property of an array. Here's the snippet in question: ngOnInit() { this.menus = this.navService.defaultMenu; console.log(this.getMenusItem()); this.registerChangeInProjects(); } T ...

Iterate over Observable data, add to an array, and showcase all outcomes from the array in typescript

Is there a way to iterate through the data I've subscribed to as an Observable, store it in an array, and then display the entire dataset from the array rather than just page by page? Currently, my code only shows data from each individual "page" but ...

Learn how to utilize the "is" status in Postma within your code, even when this particular status is not included in the response

Service.ts Upon invoking this function, I receive a JSON response similar to the following: public signupuser(user: Users): Observable<boolean> { let headers = new Headers(); headers.append('Content-Type', 'application/json&a ...

The introduction of an underscore alters the accessibility of a variable

When working in Angular, I encountered a scenario where I have two files. In the first file, I declared: private _test: BehaviorSubject<any> = new BehaviorSubject({}); And in the second file, I have the following code: test$: Observable<Object& ...

Is there an improved method for designing a schema?

Having 4 schemas in this example, namely Picture, Video, and Game, where each can have multiple Download instances. While this setup works well when searching downloads from the invoker side (Picture, Video, and Game), it becomes messy with multiple tables ...

Unable to utilize the forEach() function on an array-like object

While I generally know how to use forEach, I recently encountered a situation that left me puzzled. Even after searching online, I couldn't find any new information that could help. I recently started delving into TypeScript due to my work with Angul ...

Tips for creating a thorough type guard strategy

Here is the type structure I am working with: type Child = { foo: number | null } type Parent = { child: Child | null } I am looking to create a type-guard function that takes in a Parent object as a parameter and checks if foo is a number. Somethin ...

The user model cannot be assigned to the parameter of type Document or null in a mongoose with Typescript environment

While working with Typescript, I encountered an error related to mongoose. The issue arises from the fact that mongoose expects a promise of a mongoose document (in this case, the user's document) or "null" to be resolved during a search operation. Ho ...

Display array elements in a PDF document using pdfmake

Upon reaching the final page of my Angular project, I have an array filled with data retrieved from a database. How can I utilize pdfmake to import this data into a PDF file? My goal is to display a table where the first column shows interv.code and the ...

What distinguishes Angular directives as classes rather than functions?

When using Ng directives within HTML tags (view), they appear to resemble functions that are called upon rather than instances of a class. It almost feels like they could be static methods that can be invoked without an instance of a class. Comin ...

Instructions on how to sign up for a worldwide technique that is known as

I have a file called globalvars.ts where I added a global method. How can I subscribe to this method in the ts page where it is being called? globalvars.ts; httpgetmethod(url:string) { var veri; var headers = new Headers(); headers.append(' ...

Adding a Key Value pair to every object within an Array using TypeScript

I have two arrays - one contains dates and the other contains objects. My goal is to include the dates as a key value pair in each object, like this: {"Date": "10-12-18"}. dates: ["10-12-18", "10-13-18", 10-14-18"] data: [ {"name":"One", "age": "4"} ...

Adjust the tally of search results and modify the selection depending on the frequency of the user's searches within an array of objects

Seeking assistance with adding a new function that allows users to navigate to the next searched result. Big thanks to @ggorlen for aiding in the recursive search. https://i.stack.imgur.com/OsZOh.png I have a recursive search method that marks the first ...

Nextjs build: The specified property is not found in the type 'PrismaClient'

I have a NextJS app (TypeScript) using Prisma on Netlify. Recently, I introduced a new model named Trade in the Prisma schema file: generator client { provider = "prisma-client-js" } datasource db { provider = "postgresql" url ...

Exploring Angular 4.0: How to Loop through Numerous Input Fields

I am looking to loop through several input fields that are defined in two different ways: <input placeholder="Name" name="name" value="x.y"> <input placeholder="Description" name="description" value"x.z"> <!-- And more fields --> or lik ...

Angular 2+ enables the creation of dynamic folders and allows for uploading multiple files to the server in a seamless

Can an Angular application be developed similar to FileZilla or Core FTP for uploading files and folders to the server via FTP? I need a way to upload files and folders through the admin panel instead of relying on external applications like FileZilla. ...