Custom "set attribute" feature in TypeScript

One issue I faced was resolved by creating the function shown below :

function setProperty<T extends Record<string, string>>(obj: T, key: keyof T) {
  obj[key] = "hello";
}

However, when I tried to compile the code, I encountered an error with obj[key] highlighted in red and the following message displayed :

Type 'string' is not assignable to type 'T[keyof T]'.ts(2322)

I believe this error is due to the usage of the keyword "extends" but I am unsure how to resolve it.

Any guidance on this matter would be greatly appreciated. Thank you!

Answer №1

If you are facing a problem, there are two different approaches to solve it based on your scenario. If your goal is simply to assign any string as a value to a specific key without the need for generics:

function setProperty(obj: Record<string, string>, key: string) {
  obj[key] = "hello";
}

However, if your object has predefined keys and values, you can utilize generics to ensure type safety in your code:

function setProperty<T extends Record<string, string>, K extends keyof T, V extends T[K]>(obj: T, key: K, value: V) {
  obj[key] = value
}

type ObjectValue = 'foo' | 'bar'

type A = {
  foo: ObjectValue,
  baz: 'baz'
}

const a: A = {
  foo: 'foo',
  baz: 'baz'
}

setProperty(a, 'foo', 'bar') // works
setProperty(a, 'foo', 'baz') // type error

This approach also provides the advantage of InteliSense suggestions.

EDIT:

As per the OP's request for type checking the key and setting an arbitrary string, this revised solution should be more suitable:

function setProperty<K extends string>(obj: Record<K, string>, key: K) {
  obj[key] = "hello";
}

Answer №2

Simply utilize the Object.assign method.

type StringValue<Obj> = {
    [Prop in keyof Obj]: Obj[Prop] extends string ? Prop : never
}[keyof Obj]

/**
 * Retrieve all keys with string values
 * Only these keys are permitted
 */
type Result = StringValue<{ age: number, name: string }> // name

function setProperty<
    Value,
    Obj extends Record<string, Value>
>(obj: Obj, key: StringValue<Obj>) {
    Object.assign(obj, { [key]: 'hello' })
}

const user = {
    age: 42,
    name: 'John',
    surname: 'Doe'
}

setProperty(user, 'name') // okay
setProperty(user, 'surname') // alright alright

setProperty(user, 'age') // expected error, as age is a number

By utilizing the StringValue utility type, TS will only permit keys with string values.

Playground

Please attempt to avoid mutations in TS. Refer to this article for more information.

Answer №3

Not entirely certain if this method will yield the desired outcome for your particular situation, but if your goal is simply to ensure compilation, a type assertion can be used.

function setProperty<T extends Record<string, string>>(obj: T, key: keyof T) {
  obj[key] = "hello" as T[keyof T];
}

The literal value "hello" has a specified type of hello. By explicitly asserting this in TypeScript, it indicates to the compiler that you intend to assign a value to obj, which contains keys of type keyof T. Without this assertion, the compiler may not recognize hello as the correct type.

For setting the value of obj[key] to hello, following Michael Vrana's initial suggestion would be my preferred approach.

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

It's possible that the "device.interfaces" variable has not been defined

I am currently working on creating a USB driver in TypeScript using the libusb library to adjust my keyboard lighting. However, I encountered an issue where I received a 'possibly undefined' error when trying to retrieve the interface number. The ...

Implementing data waiting strategy in Vue component using TypeScript for rendering

When working with the first component, I encountered a scenario where I needed to open a new page using the router functionality: In Component_1.vue: let route = this.$router.resolve({ name: 'Schedule', params : { id: (this.schedule[0].schedule ...

What could be causing my React Redux state to not trigger a re-render?

Having trouble with my redux state not triggering a re-render when using a selector. I'm new to react-redux and typescript, and despite following advice online about returning a new object from the reducer, my object is still not re-rendering even tho ...

Looking for a JavaScript (Angular) event listener to trigger when closing pages and tabs

I am looking for an event that will only work when closing a page or tab, but should not be triggered when the page is refreshed. I am aware of the "beforeunload" event, but it also gets activated on page refresh. Below is the code snippet I am currently ...

Avoid accessing members in Vue 3 using TypeScript that may be unsafe

Recently, we initiated the process of upgrading from Quasar v1 to Quasar v2 (moving from Vue 2 to Vue 3). In the past, this code functioned without any issues: // src/pages/myComponent.vue <script lang="ts"> import { defineComponent } from ...

Utilizing ternary operators in Angular 6 tables

I need to dynamically display certain amounts based on the comparison of two interest values. Here is the logic: <td *ngIf="subTable.flexitaxMaxPaymentDate"> subTable.flexitaxMaxInterest > subTable.IRDInterest ? {{subTable.maxAmou ...

Out of nowhere, encountering TS2322 Typescript errors, causing type mismatches during the compilation phase

I am facing an issue with AWS Codebuild while deploying APIs written in lambda and exposed via API Gateway using Koa. The build process is throwing an error related to type assignment. src/components/chart-color-settings/chart-color-settings.ts(11,13): err ...

Troubleshooting image loading issues when updating the base URL in an Angular JS project

I am trying to update the base URL for my application. Currently, when I load the application, the URL shows up as http://localhost:4200/#/, but I want it to be http://localhost:4200/carrom/ instead. To accomplish this, I modified the base URL and now th ...

Comprehending the concept of TypeScript type assertion

Currently, I'm learning TypeScript and I came across a code snippet that is causing some confusion. var str = '1' var str2:number = <number> <any> str //str is now of type number console.log(typeof(str2)) log: String From m ...

Find out if a dynamically imported component has finished loading in Nextjs

Here is a simplified version of my current situation import React, { useState } from 'react'; import dynamic from 'next/dynamic'; const DynamicImportedComponent = dynamic(() => import('Foo/baz'), { ssr: false, loading ...

Error message stating: "The 'MktoForms2' property is not recognized within the scope of 'Window & typeof globalThis'."

Encountering the following error message: (Property 'MktoForms2' does not exist on type 'Window & typeof globalThis') while working with react and typescript useEffect(() => { window.MktoForms2.loadForm("//app-sj11.marke ...

Visual Studio 2017, ASP.NET framework, Typescript programming language, and node package manager

My ASP.net application in Visual Studio used to only utilize JavaScript, but now I am looking to incorporate Typescript. While the installation and transpiling process went smoothly, I encountered an issue when attempting to import modules. I decided to u ...

Creating, editing, and deleting data in Ng2 smart table is a seamless process that can greatly enhance

While working on my Angular 2 project, I utilized [ng2 smart table]. My goal was to send an API request using the http.post() method. However, upon clicking the button to confirm the data, I encountered the following error in the console: ERROR TypeErro ...

Guide to setting up a Cordova and TypeScript project using the command line interface

For my mobile application development, I rely on Cordova and execute cordova create MyApp in the command-line to initiate a new project. I am familiar with JavaScript but now require TypeScript for my project. Please assist me in setting up a Cordova pro ...

Is it correct to implement an interface with a constructor in TypeScript using this method?

I am completely new to TypeScript (and JavaScript for the most part). I recently came across the article discussing the differences between the static and instance sides of classes in the TypeScript handbook. It suggested separating the constructor into an ...

Handlebar files are not compatible with Typescript loading capabilities

I am encountering an issue with my directory structure as follows : src |- server |- myServer.ts |- views |- myView.hbs dist |- server |- myServer.js The problem lies in the fact that the dist folder does not have a views subfolder, where the J ...

Trouble retrieving query parameters from a URL while trying to access URL parameters from a module

I am currently learning angular and facing a small problem that I'm unsure how to solve. My module looks like this: const hostHandler = setContext((operation: any, context: any) => ({ headers: { ...context?.headers, 'X-Location-Hostn ...

Steps for configuring type definitions for an Apollo error response

Apollo's documentation explains that an error response can take the following form: { "data": { "getInt": 12, "getString": null }, "errors": [ { "message": "Failed to get s ...

ExitDecorator in TypeScript

Introduction: In my current setup, I have an object called `Item` that consists of an array of `Group(s)`, with each group containing an array of `User(s)`. The `Item` object exposes various APIs such as `addUser`, `removeUser`, `addGroup`, `removeGroup`, ...

Error with Typescript types when using Styled Components

After successfully setting up styled-components in react-native, I encountered an issue while trying to use it in a simple example with react-native-web: import * as React from 'react'; import styled from 'styled-components'; export d ...