In Typescript, is it possible to utilize the value from a particular key in a type declaration as the type for another key within the same declaration?

Consider a scenario where I am designing a Variable type that includes a key named type with a value of type string. Is there a method to extract the value from the type key and utilize it as the type for another key within the declaration, without resorting to Generic Types?

For instance,

type Variable = {
  name: string;
  required: boolean;
  type: string;
  defaultValue: Variable["type"];
}

const newWorkingVar: Variable = {
  name: "count",
  required: true,
  type: "number",
  defaultValue: 22 // This should work
}

const newErrorVar: Variable = {
  name: "count",
  required: true,
  type: "number",
  defaultValue: "test" // This should error
}

Answer №1

In the absence of using generics, you would be required to create a combination of all possible pairings between type and defaultValue.

type Pair = 
  | { type: "number", defaultValue: number }
  | { type: "string", defaultValue: string }
  | { type: "user", defaultValue: User }

type Variable = {
  name: string;
  required: boolean;
} & Pair;

This approach will result in an error when trying to assign

{type: "number", defaultValue: "test"}
because it does not match any member of the Pair union.

The type '{ name: string; required: true; type: "number"; defaultValue: string; }' cannot be assigned to the 'Variable' type.

Different types for property 'defaultValue' are causing the issue.

String type cannot be assigned to a number type.

Regrettably, there is currently no known method to associate types with their corresponding string names automatically, hence, manual construction of the Pair union is necessary.

Explore Typescript Playground here

Answer №2

This response is quite similar to a previous one by @LindaPaiste, but with a slight tweak in the approach where the mapping from names to types is stored in its own dedicated type. This separate type is then manipulated to generate Variable. For instance, your mapping structure might resemble this:

type TypeMapping = {
  number: number;
  string: string;
  boolean: boolean
  // add more here as needed
}

Subsequently, the definition of Variable could be formed as follows:

type Variable = { [K in keyof TypeMapping]: {
  name: string;
  required: boolean;
  type: K;
  defaultValue: TypeMapping[K];
} }[keyof TypeMapping]

The concept behind this design involves taking each key K from TypeMapping, and changing the property type from TypeMapping[K] to the subtype of Variable for that particular key K (where type corresponds to the key, and defaultValue denotes the property type). The resulting mapped type doesn't align exactly with what is sought because it retains the same keys as TypeMapping. By indexing into it, we obtain the union of its properties.

Outcome:

/* type Variable = {
    name: string;
    required: boolean;
    type: "string";
    defaultValue: string;
} | {
    name: string;
    required: boolean;
    type: "number";
    defaultValue: number;
} | {
    name: string;
    required: boolean;
    type: "boolean";
    defaultValue: boolean;
} */

With this in place, you can observe the desired functionality:

const newWorkingVar: Variable = {
  name: "count",
  required: true,
  type: "number",
  defaultValue: 22 // valid
}

const newErrorVar: Variable = {
  name: "count",
  required: true,
  type: "number",
  defaultValue: "test" // error!
}

Playground link for code

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

Navigating API data conversion on the frontend using Object-Oriented Programming

Currently, I am facing a challenge while developing the frontend of a web application using TypeScript. The dilemma revolves around efficiently converting a data object from an API response into a format suitable for the application. Let's consider r ...

There seems to be an issue with locating a differ that supports the object '[object Object]' of type 'object'. NgFor is only compatible with binding to Iterables like Arrays

My route.js const express = require('express'); const router = express.Router(); const University = require('../models/university'); var mongo = require('mongodb').MongoClient; var assert = require('assert'); va ...

What can be done to fix the issue of a missing value accessor for a form control name in Angular

I am on a mission to wrap <app-test-field> components within the confines of the <form> tag, where I can dynamically bind in formControlName and formGroup to TestField input using Angular with StorybookJS. Alas, I have stumbled upon the follow ...

Do const generics similar to Rust exist in TypeScript?

Within TypeScript, literals are considered types. By implementing const-generics, I would have the ability to utilize the value of the literal within the type it belongs to. For example: class PreciseCurrency<const EXCHANGE_RATE: number> { amount ...

The connection to Socket IO was refused due to a network error (net::

As I work on integrating socket.io into my application hosted on Azurewebsites, webapp I have the following server.js setup: var app = require('express')(); var server = require('http').createServer(app); server.listen(process.env.PO ...

Using Typescript to create an asynchronous function without explicitly declaring a Promise

When you examine TypeScript's async function, you may notice the redundancy with "async" and "Promise<type>". public async test(): Promise<string> { return "Test"; } Is there a way to configure TypeScript to handle async types ...

Passing parameters in React classes is a crucial aspect of creating

Within a project I am currently working on, there is a const defined for the page header which takes in parameters and utilizes the information: interface UserProps { user?: { name: string, image: string }, loading?: boolean, error?: E ...

Guide on importing npm packages without TypeScript definitions while still enabling IDE to provide intelligent code completion features

I am currently utilizing an npm package that lacks type definitions for TypeScript. Specifically, I'm working with the react-google-maps library. Following their recommended approach, I have imported the following components from the package: import ...

Issue with NgRx Testing: Callback in subscribe method fails to update during testing

I am currently working on testing a component that is responsible for editing shopping list items. Upon first loading, the component receives state values through store.select, which are: editedIngredient: null, editedIngredientIndex: -1 Based on these ...

How to fix the TS4090 error regarding conflicting definitions for a node in Visual Studio 2017

My TypeScript project is building and running, but I'm encountering a multitude of build errors all originating from one issue: TS4090: (TS) Conflicting definitions for 'node' found at 'C:/[projectpath]/node_modules/@types/node/index ...

Tips for tidying up the AppModule in Angular2

After following online tutorials, I managed to create a functional SPA data entry application, although it's just 'ok'. The connection to my WEB API is working fine, but as I've only built out one Model, my AppModule is already quite l ...

Grab a parameter from the URL and insert it into an element before smoothly scrolling down to that

On a button, I have a URL that looks like this: www.mywebsite.com/infopage?scrollTo=section-header&#tab3 After clicking the button, it takes me to the URL above and opens up the tab labeled tab3, just as expected. However, I would like it to direct m ...

The 'in' operator is unable to find 'colour' within true (function return type)

Here's the TypeScript code I'm working with: let a: unknown = true; if(hasColour(a)) { console.log(a.colour); // Using a.colour after confirming a has the colour property } I've created a function to check if the color property exist ...

Incorporate a typescript library into your Angular application

Recently, I added a text editor called Jodit to my angular application and faced some challenges in integrating it smoothly. The steps I followed were: npm install --save jodit Inserted "node_modules/jodit/build/jodit.min.js" in angular.json's bui ...

What is the proper way to verify a condition in Angular?

I have encountered an issue with my Angular code coverage. I am attempting to test a conditional statement, but I am unsure of the proper approach. The resources I have found online have not provided much assistance. The text ""response.id != -1" appears ...

Ways to display the initial letter of the surname using Angular

I need help displaying the full first name and first letter of the last name. For example, if the name is John Doe, I want it to show as John D. Currently, my code is not displaying all the letters from the last name. Here is what I have tried: <div cl ...

Using RxJS pubsub to transform an Observable<any> into a string or object

My current pubsub service implementation is as follows: export class PubSubService { subjects: Map<string, Subject<any>> = null; constructor() { this.subjects = new Map<string, Subject<any>>(); } publish(data: { key: ...

Guide to adjusting the color of Fluent UI icon when hovering with mouse?

I've been implementing Fluent UI in my current project. When initializing my button, I use this straightforward JavaScript code: iconProps: { iconName: 'NewFolder', styles: { root: { color: 'orang ...

What could be causing this error for my NPM module in a .NET Core project using Typescript?

My Typescript configuration seems to be causing some issues, even though everything works fine without TS. Could the problem lie in my .d.ts file? And do I really need it for webpack? I have a basic NPM module: index.js: var MyMathTS = function(a, b){ ...

What steps should I follow to activate Ivy in Angular 8 or 9?

Can you guide me through the process of enabling Ivy on an Angular 8 or 9 project? Ivy is the exciting new rendering engine designed for Angular that brings a wealth of useful features while still maintaining compatibility with existing Angular projects. ...