Typescript field by name

Typescript field by name

Last updated: Jan 20, 2023
Reading time · 2 min

banner

# Dynamically access an Object’s Property in TypeScript

To dynamically access an object’s property:

  1. Use keyof typeof obj as the type of the dynamic key.
  2. Use bracket notation to access the object’s property, e.g. obj[myVar] .
Copied!
const obj = name: 'Bobby Hadz', country: 'Chile', >; type ObjectKey = keyof typeof obj; const myVar = 'name' as ObjectKey; console.log(obj[myVar]); // 👉️ Bobby Hadz

The keyof typeof syntax allows us to get a union type of the object’s keys.

Copied!
const obj = name: 'Bobby Hadz', country: 'Chile', >; // 👇️ type ObjectKey = "name" | "country" type ObjectKey = keyof typeof obj; const myVar = 'name' as ObjectKey;

This way, we can inform TypeScript that the myVar variable will only ever store a string that is equal to one of the keys in the object.

Now we can access the object’s property dynamically.

Copied!
const obj = name: 'Bobby Hadz', country: 'Chile', >; // 👇️ type ObjectKey = "name" | "country" type ObjectKey = keyof typeof obj; const myVar = 'name' as ObjectKey; console.log(obj[myVar]); // 👉️ Bobby Hadz

This is needed because TypeScript is not always able to determine the type of a string to be as narrow as necessary.

If you try to set the type of the variable to be a union of the object’s keys, you would get an error.

Copied!
const obj = name: 'Bobby hadz', country: 'Chile', >; // 👇️ type ObjectKey = "name" | "country" type ObjectKey = keyof typeof obj; // ⛔️ Error: Type 'string' is not assignable to type '"name" | "country"'. const myVar: ObjectKey = 'na' + 'me';

# Using a type assertion to dynamically access an object property

The easiest way to get around this is to use a type assertion.

Copied!
const obj = name: 'Bobby Hadz', country: 'Chile', >; // 👇️ type ObjectKey = "name" | "country" type ObjectKey = keyof typeof obj; // 👇️ const myVar: "name" | "country" const myVar = ('na' + 'me') as ObjectKey; console.log(obj[myVar]); // 👉️ Bobby Hadz

You can also use a type assertion directly in the square brackets.

Copied!
const obj = name: 'Bobby Hadz', country: 'Chile', >; // 👇️ const myVar: string const myVar = 'na' + 'me'; // 👇️ type ObjectKey = "name" | "country" type ObjectKey = keyof typeof obj; console.log(obj[myVar as ObjectKey]); // 👉️ Bobby Hadz

However, with this approach, you have to use a type assertion every time you try to dynamically access the property on the object.

# Additional Resources

You can learn more about the related topics by checking out the following tutorials:

  • Change a readonly property to mutable in TypeScript
  • Check if a Property exists in an Object in TypeScript
  • Check if Value with Unknown Type contains Property in TS
  • Make an optional property Required in TypeScript
  • Make all properties optional in TypeScript
  • How to Remove a Property from an Object in TypeScript
  • Remove Null and Undefined from a Type in TypeScript
  • Object is of type ‘unknown’ Error in TypeScript [Solved]
  • Type ‘unknown’ is not assignable to type in TypeScript
  • Type ‘string or null’ is not assignable to type string (TS)
  • Type ‘string’ is not assignable to type in TypeScript

I wrote a book in which I share everything I know about how to become a better, more efficient programmer.

Источник

How to Access Object Properties Dynamically Using Bracket Notation in Typescript

Screenshot of Typescript code

Javascript allows you to access the properties of an object using dot notation or bracket notation. The latter can be quite useful if you want to search for a property’s values dynamically.

For example, let’s say we are building a video page for a video website and our users want buttons to resize the given video for their convenience. As the page loads, we fetch the video metadata from the server which includes the link to the video and a selection of available sizes.

We want to associates a button to each possible dimension for the given video. One option is to hard code each object containing the dimensions to a different callback function. Then assign each function to the onclick event of their respective buttons. The result will be three hardcoded onclick callbacks, one for each button and video.

Instead, we will assign the value of the button to the respective property name of the relevant dimensions. When we click on a button, triggering our callback function, we can get the given event’s target value and use it as a property accessor. For example:

// let us imagine the videos object was received // from a server let videos = < name: "Dear Diary", large: < url: "https://www.youtube.com/embed/Xw1C5T-fH2Y", width: 1280, height: 720, >, medium: < url: "https://www.youtube.com/embed/Xw1C5T-fH2Y", width: 950, height: 540, >, small: < url: "https://www.youtube.com/embed/Xw1C5T-fH2Y", width: 640, height: 360, > >; // we have a series of buttons for toggling video sizes. const buttons = Array.from(document.getElementsByClassName('button')); // lets make the active video small by default let activeVideo = videos.small; // We create a function that takes an event and uses the // event target's value as the property accessor of our // videos object. function setActiveVideo(event) < activeVideo = videos[event.target.value]; > // We assign setActiveVideo as the onclick callback to all // the relevant buttons. buttons.forEach(button => < button.onclick = setActiveVideo; >) 

On the face of it, recreating this functionality with Typescript should be simple.

function setActiveVideo(event): void < activeVideo = videos[event.target.value]; >

However, attempting to access the property using its name, in the same way, will result in as error:

Element implicitly has an ‘any’ type because expression of type ‘any’ can’t be used to index type.

Note, it is important to remember that simply accessing the property using a string accessor, e.g videos[‘large’] will work but we want to access properties dynamically.

To achieve the same functionality in typescript, we need to make use of the languages’ Index type using the keyof keyword. Index types tell the compiler that the given property or variable is a key representing a publicly accessible property name of a given type. With the keyof keyword we can cast a given value to an Index type or set a variable to the property name an object. In both cases, this is contingent on the value matching a publicly accessible property name of the given object’s type. For more information on Index types and the keyof keyword, check out the Typescript documentation.

Knowing this, we can create the same functionality using Typescript:

// We want to take advantage of Typescript's types so create // a couple of interfaces that model out data. interface IVideoSize < url: string, width: number, height: number, > interface IVideoData < name: string, large: IVideoSize, medium: IVideoSize, small: IVideoSize > // In our fetch functionality, we would assign the returned data // to an object of out model type. let videos: IVideoData = < name: "Dear Diary", large: < url: "https://www.youtube.com/embed/Xw1C5T-fH2Y", width: 1280, height: 720, >, medium: < url: "https://www.youtube.com/embed/Xw1C5T-fH2Y", width: 950, height: 540, >, small: < url: "https://www.youtube.com/embed/Xw1C5T-fH2Y", width: 640, height: 360, > >; // we have a series of buttons for toggling video sizes. const buttons: HTMLButtonElement[] = Array.from(document.getElementsByClassName('button')) as HTMLButtonElement[]; // lets make the active video small by default let activeVideo: IVideoSize = activeVideo.small; function setActiveVideo(event: Event): void < // we are expecting the event target to be a button element. We need to cast it to the expected type in order to access the property let target: HTMLButtonElement = event.target as HTMLButtonElement; //We set the activeVideo to the given value ensuring that it is cast as an Index type. activeVideo = videos[target.value as keyof IVideoData]; > // We assign setActiveVideo as the onclick callback to all the relevant buttons. buttons.forEach(button => < button.onclick = setActiveVideo; >)

We can take this a step further and use Typescript generics to create a function that returns a given object.

// credit: Typescript documentation, src // https://www.typescriptlang.org/docs/handbook/advanced-types.html#index-types function getPropertyT, K extends keyof T>(o: T, propertyName: K): T[K] < return o[propertyName]; // o[propertyName] is of type T[K] >

This function infers the type of the object T and casts the property name to the key type K , returning the property of the object using the given key T[K] . The original source and a detail explanation of the function can be found in the Typescript documentation.

In conclusion, the ability to access properties via their name and bracket notation is a powerful and flexible feature of Javascript. As demonstrated in the example above, it allows us to work dynamically with objects. Typescript is a superset of javascript that offers static type checking at compile time. This is powerful feature that helps us to build robust apps using Typescript. This, however, means that we need to play by the compilers rules. In this case it means ensuring that we tell the compiler that the dynamic value we are using to access an object’s property, using bracket notation, is actually an index type of the object. We say that this can be achieved by casting the given value using the keyof keyword.

Copyright © 2019 Nader Al-Shamma

Source code licensed MIT.
Website content licensed CC BY-NC-SA 4.0

Источник

Читайте также:  Php mysql get query error
Оцените статью