Automatic type deduction with TypeScript types/interfaces

Attempting to create a function with a return type called UnpackedValuesOnly, which can dynamically ascertain the type of a "packed" value K without requiring explicit user input for defining what K is.

Here's my closest attempt so far:

//assume this class has practical use cases
class PackedValue<T> {
  value: T
  constructor(value: T) {
    this.value = value
  }
}

//This code snippet represents my effort to unpack the type of a PackedValue dynamically
type UnpackedValuesOnly<T, K = any, K2 = any, K3 = any, K4 = any, K5 = any> = {
  [P in keyof T]: T[P] extends PackedValue<K>
    ? K
    : T[P] extends PackedValue<K2>
    ? K2
    : T[P] extends PackedValue<K3>
    ? K3
    : T[P] extends PackedValue<K4>
    ? K4
    : T[P] extends PackedValue<K5>
    ? K5
    : UnpackedValuesOnly<T[P], K, K2, K3, K4, K5>
}

const unpackObj = <T, K = any, K2 = any, K3 = any, K4 = any, K5 = any>(toUnpack: T): UnpackedValuesOnly<T, K, K2, K3, K4, K5> => {
  //implementation details are not important, assumes non-packed values remain unchanged and packed values are unpacked
  return {} as any as UnpackedValuesOnly<T, K, K2, K3, K4, K5>
}


const foo = {
  a: 'hello',
  b: new PackedValue([ 1, 3 ]),
  c: new PackedValue('asdf')
}

const bar =  unpackObj<typeof foo, number[]>(foo)

//string type
bar.a

//number[] type
bar.b

//any type
bar.c

The specified approach presents a few significant drawbacks:

  1. There is a limited number of allowed PackedValue types, currently set at 5
  2. Users need to explicitly define all used PackValue types when calling unpackObj; otherwise, those types will default to an any type and lose compiler validation

Is there a method to write UnpackedValuesOnly such that the following example code would enable the compiler/linter to report the correct types by automatically determining the PackedValue type?

const bar = unpackObj(foo) // or perhaps unpackObj<typeof foo>(foo)

//string type
bar.a

//number[] type
bar.b

//string type
bar.c

Answer №1

A method to achieve this is by using the infer keyword:

type UnpackedValueOnly<T> = {
    [key in keyof T]: T[key] extends PackedValue<infer U> ? U : T[key]
}

To see an example of this in action, visit this TS sandbox and hover over the Test to view how the variable foo's type changed from an initial structure of:

{
  a: string
  b: PackedValue<number[]>
  c: PackedValue<string>
}

to:

{
  a: string
  b: number[]
  c: string
}

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

What could be causing the Moment function to return the error message 'not a function'?

I encountered an issue where my code works perfectly in localhost but fails in production, displaying the error ERROR TypeError: n.endOf is not a function import * as moment from 'moment'; changeMaxDate(maxTime: moment.Moment) { if (maxTime ...

Eliminate text from template literals in TypeScript types

I have successfully created a function that eliminates the 'Bar' at the end of a string when using foo. However, is there a way to achieve the same result using the type statement? (refer to the code snippet below) declare function foo<T exten ...

Setting up a Typescript class for seamless use in both Browser and Node applications

I developed a web app consisting of two separate projects, each housed in different folders with their own set of unique files. The client component is built using Angular 2 (RC-4) with SystemJS Typescript 1.8.10 (as per instructions found here). The serv ...

What could be causing the errors I'm encountering in my TypeScript component within AngularJS?

I am working with an AngularJS component written in TypeScript called news.component.ts. This component makes a call to a service named google.service.ts in order to fetch news RSS using a service that converts XML to JSON. Within the NewsComponent, I hav ...

Troubleshooting why the Angular innerHTML function is failing to render the specified

I'm encountering this problem where I am receiving a string const str = '<p>Please ensure Process Model diagram represents Functions adequately (boxes that represent an activity or group of activities that produce an outcome):</p>< ...

CoteJS encounters issues when attempting to generate multiple services

Creating multiple services using cote.js has been a challenge for me. I have around 40 services, each in its own file. The issue arises when I try to start a third service or all of them at once; they stop working, including the two that were functioning p ...

What is the best method for retrieving GET parameters in an Angular2 application?

Is there a way in Angular2 to retrieve GET parameters and store them locally similar to how sessions are handled in PHP? GET Params URL I need to obtain the access_token before navigating to the Dashboard component, which makes secure REST Webservice cal ...

Aggregate the data chunks in the antd table into groups

I've been struggling to find a solution for this specific issue. My goal is to group the data in my table based on a particular field, but I need it to be styled as depicted in the image linked below. https://i.stack.imgur.com/OsR7J.png After looking ...

How to capture a screenshot of the current screen using Nativescript programmatically

After taking a screenshot in a NativeScript app, is there a way to display a popup asking if the user wants to save the picture? I attempted using the 'nativescript-screenshot' plugin, but it only copies elements within the application: nat ...

Customizing event typings for OpenTok in Typescript

Currently, I am working on integrating chat functionality using the 'signal' events with the OpenTok API. Here is my event listener that successfully receives the signal: // Listen for signal CHAT_MESSAGE sess.on('signal:CHAT_MESSAGE', ...

What prevents TypeScript from allowing an async function to return a combination of type T or Promise<T>?

During the development of my API in typescript, I encountered a situation where some controller actions can be synchronous while others cannot. To address this issue, I decided to specify a response type as follows: type ActionResult =IHttpActionResult | ...

Ways to restrict users from inputting alphabets in TextField using material ui

I've set up a TextField where users can only input positive digits. Currently, I'm using the following onKeyDown event: <TextField label={distanceError} error={!!distanceError} defaultValue={kpoints.distance} on ...

Properties for a standard React component

Currently, I am developing a form component in react with typescript that requires a 'fieldStructures' and an 'onSubmit' prop. type FieldStructure { type: 'text'; name: string; label?: string; helpText?: string ...

Combining declarations with a personalized interface using TypeScript

My goal is to enhance the express.Request type by adding a user property so that req.user will be of my custom IUser type. After learning about declaration merging, I decided to create a custom.d.ts file. declare namespace Express { export interface ...

TypeScript is unable to locate the identifier 'async' within the code

While working with TypeScript, I encountered an error: [ts] Cannot find name 'async' Here is the code snippet causing the issue: async someAsyncCode() { let asyncFn = () => { return new Promise((resolve: Function) => { resolv ...

Define a distinct routing parameter that can be accessed through the ActivatedRoute instance

While working on setting up a router in my application, I encountered the need to define a query parameter that must be retrievable through the ActivatedRoute for compatibility reasons. Recently, I had to create some new sub-routes that do not follow the s ...

What is the best way to set up a property in a service that will be used by multiple components?

Here is an example of how my service is structured: export class UserService { constructor() {} coords: Coordinates; getPosition() { navigator.geolocation.getCurrentPosition(position => { this.coords = [position.coords.latitude, posit ...

Nested arrays in an Angular interface

As a newcomer to Angular with a background in Java, I am accustomed to setting up classes as data structures for my information. However, after doing some research, I have learned that interfaces should be used instead. I am facing an issue understanding ...

Trouble with Mui theme not being applied when inside a wrapper component

In my project using React with typescript and MUI version 5.4.2, I have been attempting to manage all styles in a single file by enclosing everything inside my App.tsx component. Problem: The custom MUI theme is not being applied throughout my application ...

Example of TypeScript Ambient Namespace Usage

The Namespaces chapter provides an example involving D3.d.ts that I find puzzling. Here is the complete example: declare namespace D3 { export interface Selectors { select: { (selector: string): Selection; (element: ...