Tips for choosing a string property of an object

I have come across this particular definition:

interface IAutoCompleteInputProps<T> {
    textMember: keyof T;
    imageMember: keyof T;
    data: T[];
}

However, I also need to ensure that the value of T[textMember] is a string. How can this be accomplished?

=== Update: Upon implementing @R Pasha's solution, an issue arises when attempting to access the textMember using a.data[a.textMember]. The IDE reports:

(property) value: T[{ [K in keyof T]: T[K] extends string ? K : never; }[keyof T]]
Type 'T[{ [K in keyof T]: T[K] extends string ? K : never; }[keyof T]]' is not assignable to type 'string'.
  Type 'T[T[keyof T] extends string ? keyof T : never]' is not assignable to type 'string'.
    Type 'T[keyof T]' is not assignable to type 'string'.
      Type 'T[string] | T[number] | T[symbol]' is not assignable to type 'string'.
        Type 'T[string]' is not assignable to type 'string'.ts(2322)

The situation can be mitigated by casting it to a string, but the root cause remains unclear. Any insights would be much appreciated.

Please note the snippet of code where the error occurs:

function Application<T>(props: IAutoCompleteInputProps<T>) {
  const x = props.data[0][props.textMember]; // At this point, x is not a string
}

For more details and experimentation, you may click on this Playground Link.

Answer №1

Utilize Conditional types

type StringProperties<T> = Pick<T, { 
    [K in keyof T]: T[K] extends string ? K : never 
}[keyof T]>;

interface IAutoCompleteInputProps<T>{
    textMember: keyof StringProperties<T>;
    imageMember: keyof T;
    data: T[];
}

interface Type1 {
  field1: number; // <- is number
  field2: string;
}

let x : IAutoCompleteInputProps<Type1> = {
  textMember : 'field1', // <- field1 must be string
  imageMember: 'field2',
  data: []

}

Answer №2

Retrieve string value properties with the help of this function:

type PropertyOfValue<T, V> = {
  [K in keyof T]-?: T[K] extends V
    ? K
    : never
}[keyof T];

Example of how to use it:

interface Type1 {
  field1: number; 
  field2: string;
}

const props: IAutoCompleteInputProps<Type1> = {
  data: [
    { field1: 42, field2: 'foo' }
  ],
  imageMember: 'field1',
  textMember: 'field2'
}

props.textMember; // "field2"
props.data[0][props.textMember]; // string

Explore TypeScript 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

Guide on setting the focus of an input in a form field using ngIf

I am currently facing an issue where I need to focus on a specific input in my code based on certain conditions derived from an observable. In this scenario, I have initialized a boolean to true inside the ngOnInit() method. export class InputOverviewExamp ...

What techniques can be employed to dynamically modify Typescript's AST and run it while utilizing ts-node?

Below is my approach in executing a TypeScript file: npx ts-node ./tinker.ts In the file, I am reading and analyzing the Abstract Syntax Tree (AST) of another file named sample.ts, which contains the following line: console.log(123) The goal is to modify ...

The string variable in the parent app is resetting to empty after being populated by the service call

I am facing an issue with my app components where AppComponent acts as the parent and ConfigComponent as the child. In the constructor of AppComponent, a service call is made to set a variable but I encounter unexpected behavior when trying to access this ...

Error TS2315: Invalid Type Assignment for Angular 6 ModuleWithProviders

Hey there, I'm encountering an issue that's got me scratching my head. I've shared some of my code in the hopes that it might shed some light on the problem. The problem cropped up as soon as I started working on a Reactive Form. Let me s ...

Check if a value is present in the array with *ngIf

I'm curious about how to use the ngIf directive in a specific scenario. In my Angular application, I have dynamically generated angular material toggles, each with a unique id. I'm familiar with using ngIf to conditionally display elements on the ...

Having trouble with implementing custom checkboxes in a d3 legend?

My attempt at creating checkboxes in d3 has hit a snag. Upon mouse click, the intention is for them to be filled with an "x". Strangely, using d3.select() inside the click-function doesn't seem to work as expected, although adding the letter U for the ...

Error encountered during the deployment of Ionic 3 with TypeScript

After completing the development of my app, I ran it on ionic serve without any issues. However, when compiling the app, I encountered the following error message. Any assistance in resolving this matter would be greatly appreciated. [15:40:08] typescri ...

Importing images in Typescript is a simple and effective

I came across a helpful solution at this Stackoverflow thread However, I encountered an error: [ts] Types of property 'src' are incompatible. Type 'typeof import("*.png")' is not assignable to type 'string | undefined& ...

The Observable<Response> type cannot be assigned to an Observable<List<Todo>> type

I'm currently working on a project that is somewhat inspired by this example, but I've encountered a TypeScript error and I would appreciate some guidance on what might be causing it. As far as I can tell, I am following the correct procedures. ...

What is the best way to display the complete text or wrap a menu item in an Angular Material menu?

Is it possible to display the full text of a menu item instead of automatically converting it to ellipses or breaking the word? I've tried various CSS methods without success. Any suggestions? https://i.stack.imgur.com/3l7gE.png #html code <mat-m ...

What is the reason behind RematchDispatch returning a `never` type when a reducer and an effect share the same name?

Recently, I made the switch from TypeScript 4.1.2 to 4.3.2 with Rematch integration. Here are the Rematch packages in use: "@rematch/core": "2.0.1" "@rematch/select": "3.0.1" After the upgrade, a TypeScript error p ...

Is there a way to replicate the tree structure of an array of objects into a different one while modifying the copied attributes?

Is there a way to replicate the tree structure of an array of objects to another one in TypeScript, with different or fewer attributes on the cloned version? Here's an example: [ { "name":"root_1", "extradata&qu ...

When working with environment variables in Node.js, everything runs smoothly within the console log. However, an error occurs when attempting to pass a parameter to

In my current project setup with nx monorepo and TypeScript for handling environment variables in Node.js, I encountered a peculiar issue. I am able to access the variables using console.log, but when I pass the variable as a parameter to the mongoose.conn ...

Issue: Unable to locate module ' Stack trace: - /var/runtime/index.mjs when running Lambda function generated using Terraform and Node.js version 18 or higher

My Terraform setup involves a Lambda function with a Node.js version of >= 18, following the steps outlined in this helpful article. However, upon attempting to invoke the Lambda function, CloudWatch throws the following error: "errorType" ...

Troubleshooting Issue with Mongoose Virtual Field Population

I am currently facing an issue with my database due to using an outdated backend wrapper (Parse Server). The problem arises when dealing with two collections, Users and Stores, where each user is associated with just one address. const user = { id: &q ...

When attempting to start npm, Angular2 fails to recognize a specific module

I recently installed a new module and added it to my system JS configuration as follows: // specifying where to look for things using the map object var map = { 'angular2-notifications': 'node_modules/angular2-notifications', } ...

Set a field to mandatory or optional depending on a condition in serenity-platform

Currently, I am tackling a project on the serenity platform. Does anyone have suggestions on how to dynamically change the field's required status based on a condition within the AbcDialog.ts file? Thank you! ...

When invoking a JavaScript method, the context variable 'this' is lost

I have developed a basic pointer to a method like this: export class SmbwaService { getExistingArsByLab(labId: number): Observable<SmwbaAr[]> { this.otherMethod(); } otherMethod(): void { } } let method: (x: number) => ...

Having trouble running Jest tests with three objects in my Vite Vue TypeScript project

Here is a snippet of code that I am testing: import {Line} from "../src/modules/objs/line"; import {SceneWrapper} from "../src/modules/scene/sceneWrapper"; import * as THREE from "three"; import {Dr ...

typescript error: referencing a variable before assigning a value to it in function [2454]

I am currently in the process of creating a store using nextJS I have two variables that are being assigned values from my database through a function let size: Size let ribbonTable: Ribbon async function findSizeCategory(): Promise<v ...