Create an object type with string keys and corresponding value types by combining a tuple type of string constants and another tuple type of different types

Contemplating how to define types for a concept similar to daggy, where a list of property names in an array leads to the creation of constructors.

Thinking of something along these lines:

[A, B] with [X, Y] => { [A]: X, [B]: Y }

In this scenario, A and B represent arbitrary string-constant-types while X and Y are any types. For instance:

['x', 'y'] with [string, number] => { x: string, y: number }

Considering the target use case of daggy, the anticipated interface would likely resemble:

<K0 extends string, K1 extends string>(keys: [K0, K1])
  => <V0, V1>(v0: V0, v1: V1)
    => { [K0]: V0, [K1]: V1 }

An interesting observation is that TypeScript seems to accept [K in NS[number]: ... and [K in K0|K1] as valid constructs. The following snippet functions as intended:

function point<
  A extends string,
  B extends string
>(names: [A, B]): { [K in A|B]: number };
function point(names: any[]): { [x: string]: number } {
  return {
    [names[0]]: 0,
    [names[1]]: 0,
  };
}

const p0 = point(['a', 'b']);
// :: { a: number, b: number }

However, there are limitations in terms of union member iteration order and merging with members of another union when opting for a direct K extends string type:

function createZip2Object<
  K0 extends string,
  K1 extends string
>(names: [K0, K1]): <V0, V1>(v0: V0, v1: V1) => { [K0]: V0, [K1]: V1 };
function createZip2Object(names: [string, string]): { [x: string]: any } {
  return (...args) => ({
    [names[0]]: args[0],
    [names[1]]: args[1],
  });
}

const point = createZip2Object(['x', 'y']);
const p0 = point(10, 945);

Encountering messages like

A computed property name in a type literal must refer to an expression whose type is a literal type or a 'unique symbol' type.
and
'K0' only refers to a type, but is being used as a value here.
.

Similar errors persist even in simpler examples not involving nested function parametrizations:

function boxValue<K extends string, V>(k: K, v: V): { [K]: V } {
  return { [k]: v };
}

const bv = boxValue('v', 42);
// :: {}

These issues arise on the Typescript playground and in VSCode using Typescript 2.9.1.

While explicitly defining the returned type from daggy's constructor creators is an option, exploring a more comprehensive approach is desired.

Answer №1

To generate the desired objects, you can utilize an intersection type and a mapped type as shown in the following code snippet:

function createZipObject<
    Key1 extends string,
    Key2 extends string
    >(keys: [Key1, Key2]): <Value1, Value2>(value1: Value1, value2: Value2) => { [Prop in Key1]: Value1 } & { [Prop in Key2]: Value2 };
function createZipObject(keys: [string, string]): { [key: string]: any } {
    return (...input: any[]) => ({
        [keys[0]]: input[0],
        [keys[1]]: input[1],
    });
}

const coordinates = createZipObject(['latitude', 'longitude']);
const locationA = coordinates(34.0522, -118.2437);

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

Typescript's default string types offer a versatile approach to defining string values

Here is an example code snippet to consider: type PredefinedStrings = 'test' | 'otherTest'; interface MyObject { type: string | PredefinedStrings; } The interface MyObject has a single property called type, which can be one of the ...

Eliminate the usage of JSON.stringify in the Reducer function

I have a system where I store chat messages in a dictionary with the date as the key and a list of messages as the value. Whenever a new message is added, the following code snippet is executed. Is there a way to enhance the existing code to eliminate the ...

Increase by 30 minutes from the minimum value and decrease by 30 minutes from the maximum value in Ionic date time

Looking to add a customized Ionic date time picker with min and max capabilities. If the minimum time is selected, it should automatically add 30 minutes, while selecting the maximum time should subtract 30 minutes. Any suggestions on how to achieve this? ...

Importing from source code instead of a file in TypeScript: How to do it

I found this code snippet to help with dynamic component loading: loadComponent(name) { var url = this.configurationService.configuration.api_url+"/generator/dynamic-loading/component/"+name; this.http.get(url, {responseType: 'text'}). ...

Gatsby struggles with generating Contentful pages using TypeScript

I have been working on creating dynamic pages with Contentful in Gatsby + Typescript. While I am able to fetch data successfully using GraphQL in a browser, I encounter issues when trying to fetch data in gatsby-node.ts. The pages seem to be generated part ...

Why is it that my TypeScript isn't permitting the definition of Tuple Types?

When attempting to define a tuple type in my code, an error is being thrown. Is there a specific configuration within my Node.js application that needs to be adjusted in order to accept tuple types? ...

The combination of Sequelize and TypeScript does not support the usage of the .create method with type attributes

The IDBAttribute - interface IDBAtribute { readonly id: number; readonly createdAt: Date; readonly updatedAt: Date; } User attributes defined as IDBMoviesAttributes - interface IDBMoviesAttributes extends IDBAttribute { readonly title: str ...

Electron and React: Alert - Exceeded MaxListenersWarning: Potential memory leak detected in EventEmitter. [EventEmitter] has 21 updateDeviceList listeners added to it

I've been tirelessly searching to understand the root cause of this issue, and I believe I'm getting closer to unraveling the mystery. My method involves using USB detection to track the connection of USB devices: usbDetect.on('add', () ...

Transforming the velocity template within an API Gateway to be seamlessly integrated into Typescript using AWS CDK

Currently, I'm utilizing typescript in conjunction with AWS CDK to produce a cloudFormation template for an api gateway. The process involves using an Apache Velocity template to assist in converting my response data. However, as I go about creating t ...

Definition for intersecting types

I am trying to define a function that can take two objects of different types but with the same keys: function myFunc(left, right, keys) { // simplified: for (const key of keys) { console.log(key, left[key] === right[key]) } return { left, rig ...

Progress Tracker: Complete all fields in the form prior to advancing

Having trouble with a form stepper that consists of 3 steps. I have included the form fields for step two below. The problem is, even if I leave some REQUIRED fields empty and click on the "Next" button, I am still able to move on to step 3. I would like t ...

What are the steps to executing a function that instantiates an object?

Here is an object with filter values: const filters = ref<filterType>({ date: { value: '', }, user: { value: '', }, userId: { value: '', }, ... There is a data sending function that takes an obje ...

The type 'undefined' cannot be assigned to type 'CartItem'

While running my program, I encountered the error 'Type 'undefined' is not assignable to type 'CartItem'. Unfortunately, I am unable to resolve this issue :(. import { Injectable } from '@angular/core'; import { CartItem ...

Determining in Angular 8 whether a value has been altered by a user or by a method call

Within my select element, the value is currently being assigned through an ngOnInit call. Here is an example of the HTML code: <select name="duration" [(ngModel)]="exercisePlan.duration" (ngModelChange)="onChange($event)"> <option *ngFor="l ...

Angular 2 iframe balked at being shown

Whenever I enter a URL into a text input and press enter, my objective is to have the URL open in an iframe. However, some websites produce an error when trying to do so. Is there a method to successfully display a web page in an iframe? Error message: Th ...

The compilation time of Webpack and Angular 2

My compile time is currently at 40 seconds and I'm looking for ways to speed it up. I attempted setting the isolatedModules flag to true in the configuration but encountered an error: error TS1208: Cannot compile namespaces when the '--isolated ...

Can one specify a conditional return type in TypeScript without resorting to typecasting within the function's implementation?

I'm currently working on a function where the return type is determined by the input values, but I'm finding that typescript is requiring me to use the as keyword to address the issue I'm facing. Is there a more graceful way to handle this a ...

After filling a Set with asynchronous callbacks, attempting to iterate over it with a for-of loop does not accept using .entries() as an Array

Encountering issues with utilizing a Set populated asynchronously: const MaterialType_Requests_FromESI$ = SDE_REACTIONDATA.map(data => this.ESI.ReturnsType_AtId(data.materialTypeID)); let MaterialCollectionSet: Set<string> = new Set<s ...

Retrieving Headers from a POST Response

Currently, I am utilizing http.post to make a call to a .NET Core Web API. One issue I am facing is the need to extract a specific header value from the HTTP response object - specifically, the bearer token. Is there a method that allows me to achieve thi ...

Updating the page dynamically in React/Redux by making API calls based on user submissions

My current task involves calling an API with Redux, triggering the call based on a form submission. If the query is empty, it should return all lists; otherwise, it should only return lists that match the query. // List.tsx import React, { useEffect, useS ...