Is it possible to create a TypeScript type that matches the structure of a prop?

I have a list of different types:

type A = 1
type B = 2
type X = 'x'
type Y = 'y'

An object will be received in the format Record<string, A | B>. For example: { test1: A, test2: B, test3: A}. The goal is to create a function that returns this type: { test1: X, test2: Y, test3: X }

There is an attempt at achieving this using TypeScript with mapping A to X and B to Y, but the desired outcome has not been achieved:

function transform <U extends string> (p: Record<U, A | B>): Record<U, Result<A | B>> {
  const result = {} as Record<U, Result<A | B>>
  (Object.keys(p) as U[]).forEach(k => (result[k] = p[k] === 1 ? 'x' as const : 'y' as const))
  return result
}

const a = transform({ test1: 1 as const, test2: 2 })
// a: Record<"test2" | "test1", "x" | "y">
// So a.test1 is of type 'x' | 'y' and not 'x'

It is uncertain if this approach is feasible in TypeScript when the exact input shape is unknown...

Examples:

input type result type
{ foo: A; bar: B } { foo: X; bar: Y }
{ test1: A; test2: B; test3: A } { test1: X; test2: Y; test3: X }
{ test1: A; test2: A; test3: A } { test1: X; test2: X; test3: X }
{ stuff: A } { stuff: X }

The objective is for the transform function to ensure that:

  • If a key is not present in the input, it should not appear in the output.
  • If input[key] was of type A, then output[key] should be inferred as type X.

Is this achievable?

Answer №1

I believe achieving this is possible using conditional types. Below is a potential solution incorporating a helper type called MapResult.

type MapResult<T> = {
    [K in keyof T]:
        T[K] extends A ? X
        : T[K] extends B ? Y
        : unknown
}

function transform <U extends Record<string, A | B>>(p: U): MapResult<U> {
    const result: Record<string, X | Y> = {};
    Object.keys(p).forEach(k =>
        result[k] = p[k] === 1 ? 'x' : 'y'
    )
    return result as MapResult<U>;
}

This solution should meet your needs. Check it out on the TypeScript Playground here.

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

Using TypeScript to automatically deduce the output type of a function by analyzing the recursive input type

I am currently working on developing an ORM for a graph database using TypeScript. Specifically, I am focusing on enhancing the "find" method to retrieve a list of a specific entity. The goal is to allow the function to accept a structure detailing the joi ...

Is there a method to implement retries for inconsistent tests with jest-puppeteer?

Currently, I am struggling with an issue where there is no built-in method to retry flaky tests in Jest. My tech stack includes Jest + TypeScript + Puppeteer. Has anyone else encountered this problem or have any suggestions for possible solutions? I attem ...

Encountered an issue while resolving symbol values statically within my exclusive set of modules

Encountered an error while resolving symbol values statically. The function 'DataModule' is not supported. Consider using a reference to an exported function instead of a function or lambda, resolving the symbol DataModuleRoot in E:/shopify-clien ...

react-vimeo not firing onPause and onPlay events

I am facing an issue with triggering props when playing a Vimeo video on my webpage. Here's a snippet of my code: import Vimeo from '@u-wave/react-vimeo'; const handleVimeoProgress = (data: any) => { console.log('Progress:' ...

Show a Toast in React without relying on useEffect to manage the state

I have successfully implemented the Toast functionality from react-bootstrap into my application using the provided code. However, I am unsure if it is necessary to utilize useEffect to set show with setShow(items.length > 0);. Would it be simpler to ...

There seems to be an issue with the response type in the node.js environment

I am currently working on node.js and typescript, but I am encountering a minor issue. Below is the routeController I have created: public allUsers = (req: Request, res: Response) => { res.status(500).json({ status: "ERROR", ...

Executing React's useEffect hook twice

As I work on developing an API using express.js, I have implemented an authentication system utilizing JWT tokens for generating refresh and access tokens. During testing with Jest, Supertest, and Postman, everything appears to be functioning correctly. O ...

Is it possible to close a tab while the chrome extension popup is still active?

I am currently developing a Chrome extension that reads the content of the current tab and performs a heavy task on the backend. If I were to close the tab while the process is ongoing, how can I allow the user to do so without waiting for the task to fi ...

What is the correct way to access $auth in Nuxt with TypeScript?

<script lang="ts"> import LoginAdmin from '@/components/LoginAdmin.vue' import { Component, Vue } from 'nuxt-property-decorator' import Auth from "@nuxtjs/auth"; export default class MyStore extends Vue { pub ...

Making a decision on the appropriate data type

When creating a column in my Table where the values should be limited to Yes, No, or Optional, what data type should I use? ...

Using TypeScript with Vue in a non-component-based architecture

Recently, I've been facing a challenge while developing an application. I'm using Vue + Vuetify with typescript, but I'm trying to steer clear of creating a single-page application or using webpack to handle .vue components. My goal is to cr ...

The object assigned in the Facebook login method cannot be utilized

I'm working on integrating Facebook login with Angular 2. Here's the button for logging in: <button ion-button (click)="fbLogin()"><ion-icon name="logo-facebook"></ion-icon>Login using Facebook</button> Below is the clic ...

"Ensure Playwright refreshes the page automatically following navigation when a specific status code is

I find myself in a dilemma where I require my functional browser tests to verify the status code of each page response, and if a 503 error is encountered, try to reload the page a certain number of times before declaring failure. Even though I have experi ...

Exploring Typescript: Uncovering the Secrets of the navigator.connection Property

I am trying to access the NetworkInformation interface by using a simple TypeScript function like the one shown below: private checkNetworkConnection(): void { const connection = Navigator.connection || navigator.mozConnection || navigator.webkitConn ...

Dealing with 'TypeError X is Not a Function' Error in Angular (TypeScript): Occurrences in Certain Scenarios and Absence in Others

Recently, I came across an odd issue in Angular 14 where a type error kept popping up. Although I managed to refactor the code and find a workaround, I'm quite intrigued as to why this issue is happening so that I can prevent it from occurring again i ...

Modify visibility within a subclass

Is there a way to modify property visibility in a child class from protected to public? Consider the following code snippet: class BaseFoo { protected foo; } class Foo extends BaseFoo { foo = 1; } new Foo().foo; It seems that this change is pos ...

Looking for someone to break down this Typescript code snippet for me

As a Javascript developer, I am currently diving into an unfamiliar TypeScript code block within a project. Here is the code snippet: ViewModel newPropertyAddress = new ViewModel(){name, previousPro = oldValue } ...

The JSX element 'HeaderPublic' does not contain any construction or calling signatures

I am currently utilizing nx workspace to build the react ts application. Below is the library component: import { ReactElement } from 'react'; import styles from './header-public.module.scss'; export function HeaderPublic(): ReactElem ...

Typescript error in RxJS: Incorrect argument type used

I came across this code snippet from an example in rxjs: Observable.fromEvent(this.getNativeElement(this.right), 'click') .map(event => 10) .startWith({x: 400, y: 400}) .scan((acc, curr) => Object.assign({}, acc, {x: acc ...

Ways to statically type a function that produces an array from 1 to n

I am working on creating a function that can generate an array of numbers ranging from 0 to n, while ensuring that the returned type matches a known array structure at compile time. const makeFoo = (n: number) => [...Array(n).keys()]; const foo1 = [0, 1 ...