Selecting string properties in TypeScript

Trying to solve the puzzle of accurately coding a show function that requires an object T and a key K where T[K] definitely has a method named toString().

Here's my approach using mapped types

type ToStringablePropertyKeys<T> = keyof {
    [K in keyof T]: { toString(): string }
}

function show<T, K extends ToStringablePropertyKeys<T>>(t: T, k: K): string {
    return t[k].toString()
}

However, the compiler is giving me an error -

Property 'toString' does not exist on type 'T[K]'.

What could I be overlooking here? How can I assure tsc that toString certainly exists due to definition of K?

Answer №1

Consider another method:

function display<A extends string, B extends {[item in A]:{toString(): string}}>
(entry: B, key: A ): string {
return entry[key].toString()
}

Answer №2

Behold, a solution that comes close to perfection. While TypeScript can mandate that the keys are limited to those expanding on {toString():string}, it lacks the intelligence to automatically deduce that all instances of T[k] will possess toString():string...

type ToStringable = { toString(): string };

type ToStringablePropertyKeys<T> = {
    [k in keyof T]: T[k] extends ToStringable ? k : never
}[keyof T];

function display<T, K extends ToStringablePropertyKeys<T>>(t: T, k: K): string {
    return (t[k] as any).toString(); // TypeScript seems unable to infer that all t[k] will have toString method
}

const sampleObject = {
    string: 'example',
    number: 456,
    null: null,
    undefined: undefined,
};

display(sampleObject, 'number');
display(sampleObject, 'string');
display(sampleObject, 'invalid-property'); // this will fail
display(sampleObject, 'null'); // this will fail
display(sampleObject, 'undefined'); // this will fail

Link for interactive demo

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

The non-nullable field Mutation.create in typegraphql with bcrypt must not be null, cannot be returned as null

Recently, I have been experimenting with typegraphql alongside apollo-server, typeorm, and bcrypt in typescript. I encountered a peculiar issue when running the mutation query using the resolver below. The error 'Cannot return null for non-nullable fi ...

Discover the method for extracting a value from an interface and incorporating it into a separate function

I need help accessing the value of userType for a conditional statement. UserType: const RadioForm = (props) => { return ( <div> <label>Customer</label> <input type="radio&qu ...

How to Modify a Module that was Imported in Typescript

Apologies for my inexperience in this language. I've been working on a custom Discord bot and encountered a problem. I implemented the feature to load commands dynamically from a folder, with each command as a module. However, when trying to create a ...

Ensure the JSON file aligns with the TypeScript Interface

I am working with a config.json file. { "profiler": { "port": 8001, "profilerCache": { "allowedOriginsRegex": ["^http:\/\/localhost:8080$", "i"] } }, "database": { "uri": "mongodb+srv://...", "dbName": "profiler", ...

Create a consolidated HTML file by integrating all components of a Typescript website

I have a custom HTML page that utilizes CSS and TypeScript to enhance the appearance of logs. I want to create a single file containing all the files (CSS, HTML, JavaScript generated from TypeScript) so that the styled logs are self-contained and easily sh ...

What is the best way to restrict the number of iterations in ngFor within Angular HTML

I want to use ngFor to display a maximum of 4 items, but if the data is less than 4, I need to repeat the loop until there are a total of 4 items. Check out this example <img *ngFor="let item of [1,2,3,4]" src="assets/images/no-image.jpg" styl ...

Using Puppeteer to send messages on Discord without the use of a bot or application

Currently, I am coding a Puppeteer script to automate actions on Discord Web. Specifically, I need the script to open Discord Web, log in (including manual captcha and authorization steps), navigate to a channel, enter a message into the chat input field, ...

Monitor the behavior of a function that is provided as an argument to a simulated node package

Currently, I am in the process of creating a custom client that integrates the robust SignalR library: export class RealTimeCommunicator { /** SignalR hub connection */ private hubConnection: HubConnection | null = null; private buildConnection(ur ...

I am struggling to understand how to work with constrained generic functions

function calculateMinimumLength<T extends {length : number}>(arg1: T, arg2: T) : T { if (arg1.length >= arg2.length) { return arg2; } else { return arg1; } } let str = "Hello world"; const result0 = calculateMinimumLe ...

Converting typescript path aliases into local file paths

Just dipping my toes into typescript and grappling with module resolution. The problem seems straightforward (or so I think), but there's something off about my tsconfig.json. If my folder structure looks like this: + release + definitions + ...

Uploading an image in Typescript on IE11 using Angular 4

I'm having an issue uploading an image to my web application using Angular 4. I convert the input file using readAsBinaryString() and extract the ASCII code using btoa() before passing it to a backend service. While this process works smoothly on Chro ...

Angular navigation paths directing to incorrect components

For my blog application, I have set up separate routing modules for the admin and user sides. However, I am facing an issue where the client side routes are not being recognized after importing the routing module into app.module.ts. Instead of navigating t ...

Set up your Typescript project to transpile code from ES6 to ES5 by utilizing Bable

Embarking on a new project, I am eager to implement the Async and Await capabilities recently introduced for TypeScript. Unfortunately, these features are currently only compatible with ES6. Is there a way to configure Visual Studio (2015 Update 1) to co ...

Troubleshooting Node TypeScript with Visual Studio Code using webpack bundling

(In a similar context to this query, but more focused on VsCode) I am attempting to debug the AngularU starter kit with Visual Studio Code. However, it is combining the TypeScript output into one bundle.js along with a side bundle.js.map: ↳web ↳dis ...

"Obtaining data from a JSON response: A step-by-step

After receiving a JSON result, which contains only one array as shown below: { id: "5", client: "8", } id: 5 client: 8 I am trying to access it using the following function: getClient(url: string){ this.clientService.client(this.clientUrl).subsc ...

What is the best way to specify a type for an object without altering its underlying implicit type?

Suppose we have a scenario where an interface/type is defined as follows: interface ITest { abc: string[] } and then it is assigned to an object like this: const obj: ITest = { abc: ["x", "y", "z"] } We then attempt to create a type based on the valu ...

Tips on Showing a Unique List in Mat-Table?

Here's what I'm trying to accomplish: I have a list and I want to display it without any duplicates. I attempted using the code (this.model.map(x => x.map), but it resulted in an error. Can anyone help me fix this? model: myModel[]; myObj:any; ...

What is the best way to combine two functions for the "value" attribute in a TextField?

How can I make a TextField force all uppercase letters for the user when they type, while also storing the text inputted by the user? I have managed to make the TextField display all uppercase letters, but then I can't submit to Excel. On the other ha ...

Creating a Fixed HeaderToolbar in FullCalendar React

I am currently working on customizing the FullCalendar React component and I am looking to incorporate a sticky headerToolbar. My main objective is to have the header along with its toolbar remain fixed at the top of the calendar, even when users scroll th ...

How to utilize ngModel for binding to radio buttons in Angular 2

When the value is "N" for Non Rule Based and "R" for Rule based, I need to dynamically select the corresponding Radio button in the UI. In ts. this.vGroup = this.arr.vzGroup; // the value of vGroup is either "R" or "N" To accomplish this, I must create ...