Why is Typescript converting my keyof type to a never type and what steps can I take to resolve this issue?

Apologies if this question is repetitive, as I am new to TypeScript and struggling to identify related issues due to the complexity of some questions. The issue I'm facing involves TS coercing a type to never, which is confusing me. Here's the scenario:

interface BigObject {
  foo: {
    a?: string
    b?: string
  }
  bar: {
    c?: string
    d?: string
  }
}

const instance: BigObject = {
  foo: {
    a: "a",
    b: "b",
  },
  bar: {
    c: "c",
    d: "d",
  }
}

function metafunction(bigObjProp: keyof BigObject) {
  type LittleObject = BigObject[typeof bigObjProp]

  return function (littleObjProp: keyof LittleObject) { 
    return function (bigObject: BigObject) {
      const littleObject = bigObject[bigObjProp]
      return littleObject ? littleObject[littleObjProp] : "fallback value"
    }
  }
}

const firstClosure = metafunction("foo")
const secondClosure = firstClosure("a") 
const value = secondClosure(instance)

I expect the value of value to be "a".

The confusion arises from littleObjProp resolving to never. My intuition was that since LittleObject is derived from the argument passed into metafunction, TypeScript would determine which "sub interface" to use for each invocation. However, it always defaults to thinking that keyof LittleObject equals never.

If anyone could help clarify why this is happening and provide guidance on achieving my goal, I would greatly appreciate it. Due to constraints with React libraries, I need to maintain the same structure of nested functions seen in the example. Please keep explanations simple, as I am still learning TypeScript. Thank you!

Answer №1

Modify the metafunction to be generic.

The current implementation lacks a generic type. As it stands, firstClosure will only accept a key that is common between foo and bar, but since they have no common key, the only valid parameter would be never. Adding a shared key between them would allow firstClosure to accept that key.

interface BigObject {
  foo: {
    a?: string
    b?: string
    f?: string   // Added
  }
  bar: {
    c?: string
    d?: string
    f?: string   // Added
  }
}

const instance: BigObject = {
  foo: {
    a: "a",
    b: "b",
    f: "f",
  },
  bar: {
    c: "c",
    d: "d",
    f: "f",
  }
}

const secondClosure = firstClosure("f")   // Only "f" is a valid value

typescript playground

Introduce generics in your functions to retain the type information within metafunction and firstClosure, thereby achieving the desired closure type.

function metafunction<T extends keyof BigObject>(bigObjProp: T) {
  type LittleObject = BigObject[T]

  return function (littleObjProp: keyof LittleObject) {
    return function (bigObject: BigObject) {
      const littleObject = bigObject[bigObjProp]
      return littleObject[littleObjProp] ?? "fallback value"
    }
  }
}

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

Error: Attempting to access the 'tokenType' property of an undefined object is not allowed

We encountered an error while attempting to embed a report using the Power BI Angular library. TypeError: Cannot read properties of undefined (reading 'tokenType') at isSaaSEmbedWithAADToken (reportEmbed?navContentPaneEnabled=false&uid=am ...

Using jQuery with Angular 4 allows for powerful front-end development

To include jQuery in an Angular4 project, I follow these steps: npm install --save jquery npm install --save-dev @types/jquery In the app.component.ts file import $ from 'jquery'; or import * as $ from 'jquery'; When running "ng se ...

Does Vetur have additional undefined types in the type inference of deconstructed props?

When reviewing the code below, Vetur concluded that x,y are of type number | undefined. The presence of undefined is leading to numerous warnings when using x,y further in the code. Is there a way to eliminate the undefined from the type inference? <s ...

Develop a cutting-edge TypeScript library that allows for seamless resolution of optional dependencies by the application

One of my recent projects involved creating a library that I published to a private npm repository. This library consisted of various utilities and had dependencies on other libraries, such as @aws-sdk/client-lambda. However, not all applications utilizin ...

Issue with dependencies: Incorrect value passed to `ts.resolveTypeReferenceDirective` causing a problem

This issue is really frustrating me. I'm currently working on this repository. Everything seems to be fine on the client side, but when it comes to the server side, I encountered the following problem: MacBook-Pro$ yarn dev yarn run v1.22.19 warning . ...

Mistakenly importing the incorrect version of Angular

While working on my Angular 1 app in typescript, I faced an issue when importing angular using the following syntax: import * as angular from 'angular'; Instead of importing angular from angular, it was being imported from angular-mocks. Thi ...

Remember to always call "done()" in Typescript + Mocha/Chai when dealing with async tests and hooks. Additionally, when returning a Promise, make sure it resolves correctly

It seems like I'm facing an old issue that I just can't seem to resolve, despite trying everything in my power. The error message reads: Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Pro ...

Navigating the diverse types of React HTML DOM events within a function concatenation

Question: Is it possible to merge different HTML DOM event types in Typescript? (I am aware of the option to split my function into two separate functions to avoid this error, but I would like to find another solution) Here is an example of my component ...

Clicking on the React Bootstrap Checkbox within the Nav component does not trigger a rerender of the NavItem component

Encountering an unusual issue while using a Nav and NavItem with a Checkbox from React Bootstrap. What I've noticed is that when clicking directly on the checkbox instead of the NavItem button, the checkbox does not re-render correctly even though my ...

"Exploring the best practice: Defining types in React with Typescript before or after

As a newcomer to typescript, I have noticed that some projects declare the type before the component while others declare it after the component. Can someone explain the differences between these approaches? export type TProps = { item: string; } expor ...

creating a JSON array within a function

I am currently developing an Angular application and working on a component with the following method: createPath(node, currentPath = []){ if(node.parent !==null) { return createPath(node.parent, [node.data.name, ...currentPath]) } else { retu ...

Display React elements on the web page

Seeking assistance from anyone! I've been grappling with a problem and can't seem to figure out a solution. Here's the scenario: My current setup involves a sidebar and a top bar for navigation in React. Check out my app so far in this imag ...

Error encountered in Angular NGRX while accessing the store: Trying to read property 'map' of an undefined variable

I have integrated NGRX effects into my Angular application and encountered the following error. I'm uncertain if I am using the selector correctly in my component to query the store? core.js:6162 ERROR TypeError: Cannot read property 'map' o ...

Why should one bother with specifying types when defining a variable in Typescript?

As someone new to Typescript, I've come to appreciate its many advantages when working on larger applications and with multiple team members :) Imagine you have the following TypeScript code: declare const num = 5: number; Why is this better than: ...

What is the best way to bring in an array from a local file for utilization in a Vue 3 TypeScript project?

Encountering a TS7016 error 'Could not find a declaration file for module '../composables/httpResponses'. '/Users/username/project/src/composables/httpResponses.js' implicitly has an 'any' type.' while attempting to ...

An array variable marked as mat-checked contains the total sum

Currently, I am utilizing mat-checked to calculate a total sum from an Array. The issue arises when the number of items in my array varies, triggering an error: ERROR TypeError: Cannot read property 'isChecked' of undefined Is there a way to ...

Exploring the Relationship Between Redux and ImmutableJS in Managing Nested State and Understanding the Computational Complexity of Immutable

Trying to grasp the concept of Immutability for my debut Redux (NGRX/Store) endeavor has been quite the challenge. Avoiding state mutation has been a struggle, especially while dealing with Object.assign({}) and state mutation errors. Thankfully, I stumble ...

Convert the union into a mapped structure

Starting with the given Union type: type Union = { type: 'A', a: string } | { type: 'B', b: number } The end goal is to transform it into this MappedUnion type: type MappedUnion = { A: { type: 'A', a: string } B: { ...

What are the distinctions between generic and discriminated types?

Hi there, I've been thinking of an idea but I'm not sure how to implement it or if it's even possible. Is there a way to create a type SomeType where the first property can be any value from the set T, but the second property cannot be the ...

Trouble with styling the Ngx-org-chart in Angular

I integrated the ngx-org-chart library into my Angular project, but I'm facing issues with the styles not applying correctly. Here are the steps I followed: I first installed the package using: yarn add ngx-org-chart Then, I added the ngx-org ...