Writing for objects within objects

I need help accessing specific data from a nested object using a combination of two keys. I am struggling with typing the key(s) correctly to access the nested objects.

Consider this object structure:

const movies = {
  "Shawshank Redemption": {
    rating: 9,
    versions: {
      "Directors Cut": {
        length: 111,
      },
      Cinema: {
        length: 113,
      },
    },
  },
  "The Dark Knight": {
    release: 2008,
    versions: {
      Standard: {
        rating: 9,
        length: 113,
      },
    },
  },
};
type MovieKey = keyof typeof movies;

How can I accurately type the VersionKey in the following function? Is it feasible?

function getMovieVersion(movie: MovieKey, version: VersionKey)

Answer №1

If you desire getMovieVersion() to function as a generic method where the type of movie is a generic type parameter K that is restricted to MovieKey.

By doing this, you can access typeof movies using K as the key type, then access the result with "versions" as the key type, and finally utilize keyof on the result to retrieve version. Therefore, if movie is of type K, then version will be of type

keyof (typeof movies)[K]["versions"]
:

declare function getMovieVersion<K extends MovieKey>(
    movie: K,
    version: keyof (typeof movies)[K]["versions"]
): void;

You can confirm that this functions as intended:

getMovieVersion("Shawshank Redemption", "Cinema"); // valid
getMovieVersion("The Dark Knight", "Standard"); // valid
getMovieVersion("Shawshank Redemption", "Standard"); // error!
// -----------------------------------> ~~~~~~~~~~
// Argument of type '"Standard"' is not assignable 
// to parameter of type '"Cinema" | "Directors Cut"'

If you also require knowing the exact literal type of version in order to acquire the specific type of the output, then you can use two generic type parameters as shown below:

declare function getMovieVersion<
    MK extends MovieKey,
    VK extends keyof (typeof movies)[MK]["versions"]
>(
    movie: MK,
    version: VK
): (typeof movies)[MK]["versions"][VK];

getMovieVersion("Shawshank Redemption", "Cinema").rating; // error
getMovieVersion("The Dark Knight", "Standard").rating; // valid

Link to Playground for code execution

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

Mistakenly Typing React Hook with Firestore

I've implemented a custom hook for fetching data from a specific Firebase Firestore collection/document. import { useContext, useEffect, useState } from 'react'; import { FirebaseContext } from 'providers/Firebase/FirebaseContextProvid ...

What could be causing TypeScript to not parse my `react-native-web` code? (Excluding the `create-react-native-app` option)

Checked out the discussion at https://github.com/necolas/react-native-web/issues/832 Reviewed: https://i.sstatic.net/ZsZFM.png in comparison to: https://i.sstatic.net/IZL23.png I suspected that the problem might be related to the linter error I encoun ...

What are the steps for incorporating TypeScript into a project created with Vue CLI@3?

td;dr How can I integrate vue-apollo into an existing TypeScript project? I initialized a new Vue project using vue cli@3 with TypeScript. Afterwards, I installed the vue-apollo plugin which automatically updated my main.ts file to include apolloProvide ...

Issue with Angular 10 Web Worker: Unable to locate the main TypeScript configuration file 'tsconfig.base.json'

Every time I attempt to run: ng g web-worker canvas I consistently encounter the error message: Cannot find base TypeScript configuration file 'tsconfig.base.json'. After thorough examination of my files, it appears that I am indeed missing a ...

What are the steps to incorporate a 3D scene into a React website?

Can I get some advice on how to create a React web application using TypeScript? I want to be able to click a button and have it show a new page with a scene of a town. What is the best way to achieve this in my React project? I've heard about using R ...

Unsubscribing from a nested observable - a step-by-step

In our Angular component, we leverage the ngOnDestroy() method to handle canceling http requests that are still pending when navigating away from a page. To avoid reloading data that has already been fetched, we utilize a custom generic cache helper on cer ...

Struggling with TypeScript and JsObservable? Let us assist you!

Having previous experience with JSRender, JSViews, and JSObservables, I recently embarked on a new project using TypeScript. Unfortunately, I am struggling to understand how to properly utilize TypeScript in my project, especially when it comes to referenc ...

Unexpected behavior: Axios post still enters catch block despite successful completion of Rest API call

Having an issue with my axios post request not returning the value from the API in a non-success scenario (401 error). It works fine for successful scenarios. When using Postman to test the output of my reset password API by providing an incorrect current ...

fresh perspective on the syncfusion schedule angular component

In customizing the Schedule component in Angular, I am interested in finding out if there is a way to specify the start time and end time for each day. I would like to set the start and end times for each individual day rather than having the same times a ...

Convert an array with three dimensions into a two-dimensional array that includes tuples with two immutable string values

Consider the array below with multiple dimensions: type ParsedLine = [string, string]; type ParsedLines = [ParsedLine, ParsedLine] const myArray: (ParsedLine | ParsedLines)[] = [ ['something', 'somethingElse'], [['foo', & ...

What is the best way to retrieve the name of a static method within a class?

In my code, I am logging multiple messages in a static method and I want to use the method name as context. However, I do not want to create a separate variable called `context` and assign the function/method name to it. I would like to be able to access ...

Tips for sending a timestamp as input to a stored procedure in TypeScript with the mssql module

Currently, I am utilizing the mssql npm package to communicate with SQL server. I have encountered a dilemma where the variable (which is of type TIMESTAMP in sql server) fetched from a stored procedure is returned as a byte array. Now, I need to pass this ...

How can you reposition a component within the dom using Angular?

Just started learning Angular, so I'm hoping this question is simple :) Without getting too specific with code, I could use some guidance to point me in the right direction. I'm currently developing a small shopping list application. The idea i ...

How to programmatically generate buttons with click functionality in Angular 2 and above

Is there a way to dynamically create a button in Angular using innerHtml? I have managed to create the button, but unfortunately, its click event is not functioning properly. Can anyone provide guidance on how to resolve this issue? Below is my HTML code ...

Abbreviation for ensuring type safety when combining properties from one object with another

Imagine we have an object x representing type X and an object y representing type Y. Is there a way to combine (assign all properties) of y into x in such a way that if Y is not a proper subset of X, the compiler raises an error? NOTE: While Object.assig ...

Struggling with establishing connection logic between two database tables using Prisma and JavaScript

I'm facing a perplexing logic problem that is eluding my understanding. Within the context of using next-connect, I have a function designed to update an entry in the database: .put(async (req, res) => { const data = req.body; const { dob ...

Transform nested properties of an object into a new data type

I created a versatile function that recursively converts nested property values into numbers: type CastToNumber<T> = T extends string ? number : { [K in keyof T]: CastToNumber<T[K]> }; type StringMap = { [key: string]: any }; const castOb ...

What is the best way to refresh content in a secondary component when a websocket event is received by the primary component?

My Component A has a websocket logic that looks like this: this.socketService.connect('/socket_url'); this.statusSubscription = this.socketService.messages .subscribe(result => { if (result !== 'pong') { ...

Node.js HTTP requests abruptly ceasing after a few seconds

Everything is running smoothly with the code as I initiate the request. It progresses and launches multiple requests consecutively, just as intended. However, after a few moments, the script abruptly halts—this is definitely not the desired outcome. I ...

Issues encountered while attempting to convert HTML Image and Canvas Tags to PDF within Angular 2

I am currently facing an issue with my code. My requirement is to download HTML content as a PDF file. I have been successful in downloading text elements like the <p> tag, but I am encountering difficulties when trying to download images and canvas ...