Using Typescript to extract/calculate types with limitations without the need to explicitly extend or broaden them

I have a function called build that constructs a User object using the provided parameters. I want to define the function in such a way that it recognizes which parameters are being passed and incorporates them into the return value.

Initially, I thought of capturing the type of params and utilizing it for the return type:

type User = { name: string; admin: boolean };

const build = <T extends User>(params: T): T => params

This approach works effectively since now I can use it like this:

build({ name: 'Jan', admin: true });
// the return type is: { name: string, admin: true } as intended (noting admin: true, not boolean)

However, by capturing the type with the <T extends User> constraint, it unintentionally widens the type. Now, the following scenario is allowed without any errors:

build({ name: 'Jan', admin: true, foo: 'shouldnt be allowed' });
// the return type becomes: { name: string, admin: true, foo: string }

If I opt for a simpler approach where I don't capture the type and just return a User, then I do get the expected behavior where passing parameters that do not exist in User leads to an error, but the function only returns a User without additional information from the parameters:

const build = (params: User): User => params

// Type error as expected: Object literal may only specify known 
// properties, and 'foo' does not exist in type 'User'
build({ name: 'Jan', admin: true, foo: 'sdf' })

My query is whether there is a method to capture the type of params for usage in the return type without causing the type to widen unnecessarily.

Answer №1

Although Typescript does not have built-in support for exact types, you can set up custom constraints on argument types. Take a look at this example in the playground:

type User = { name: string; admin: boolean };

const build = <T extends User>(
    params: keyof T extends keyof User ? T : never
): T => params

// const user1: { name: string; admin: true; }
const user1 = build({ name: 'Jan', admin: true, });

// ERROR
const user2 = build({ name: 'Jan', admin: true, x: 1});

Expanding on the same concept, here's a slightly more detailed approach with improved error handling:

const build = <T extends User>(
    params: keyof T extends keyof User ? T : User
): Pick<T, keyof User> => params

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

The element 'commit' cannot be found within the property

I am facing an issue when transitioning from using Vuex in JavaScript to TypeScript. The error message Property 'commit' does not exist appears in Vuex's mutations: const mutations = { methodA (): none { this.commit('methodB' ...

Eliminating empty elements from arrays that are nested inside other arrays

I am facing a challenge with the array structure below: const obj = [ { "description": "PCS ", "children": [ null, { "name": "Son", ...

Is it considered beneficial to use Observable as a static class member?

Lately, I have been diving into a new Angular project and noticed that the common way to share state between unrelated components is by using rxjs Subject/BehaviorSubject as static members within the class. For instance: export class AbcService { privat ...

Access the most up-to-date information through the API URL

Objective: Whenever the 'Test' Button is clicked, new data must be fetched from the backend using the API link and displayed on the modal form. Issue: If text in the input box is changed or deleted, then the modal is closed and the 'Tes ...

The promise chain from the ngbModal.open function is being bypassed

I'm currently working on implementing data editing within a component. My task involves checking if any of the data fields have been altered, and if so, prompting a confirmation pop-up to appear. If the user confirms the change, the data will then be ...

Experiencing an issue with mui/material grid causing errors

An error occurred in the file Grid2.js within node_modules/@mui/material/Unstable_Grid2. The export 'createGrid' (imported as 'createGrid2') could not be found in '@mui/system/Unstable_Grid' as the module has no exports. Desp ...

The implementation of getStaticPaths was done independently of getStaticProps - TypeScript

I am currently in the process of setting up a new blog using a combination of nextJS, TypeScript, and sanity CMS. The homepage is already set up to display posts perfectly. Next on my list is to display the details of each post when it is clicked, based on ...

Transformer Class: An object containing properties that are instances of another class

class ClassA { x: number; y: number; sum(): number { return this.x + this.y; } } class ClassB { @Type(() => ClassA) z: {[key: string]: ClassA}; } const b = transformObject(ClassB, obj); const z = b.z[key]; const s = z.s ...

The property 'toLowerCase' cannot be accessed as it is undefined or null

Scenario: A textbox is present with a list of data below it. Upon typing in the textbox, the list gets filtered based on the text entered. Code: Pipe: @Pipe({ name: 'search' }) export class SearchPipe implements PipeTransform { transform( ...

Utilizing external JavaScript libraries in Typescript for integration with nodeJS

We've recently made the switch to using Typescript + Electron for developing a browser-based desktop application. However, we often encounter delays when loading external Javascript libraries. While typings helps with most of our needs, there are stil ...

Leveraging TypeScript to call controller functions from a directive in AngularJS using the "controller as"

I've encountered an issue while trying to call a controller function from a directive, specifically dealing with the "this" context problem. The logService becomes inaccessible when the function is triggered by the directive. Below is the code for th ...

What is the best way to test the SSM getParameter function using Jasmine?

Is there a way to effectively test this? const ssmParameterData = await ssm.getParameter(params, async (error, data) => { if (error) throw error; return data; }).promise(); I have attempted mocking the method by doing: spyOn(ssm, 'getParameter& ...

Issue with detecting window resize event in Angular 7 service

I have a unique service that utilizes a ReplaySubject variable for components, but strangely the WindowResize event isn't triggering. import { Injectable, HostListener } from '@angular/core'; import { ReplaySubject } from 'rxjs'; ...

Implementing Asynchronous context tracking within a Remix application utilizing Express as the server

Utilizing Remix with Express as the server, I aim to develop an Express middleware that establishes an async context to grant all downstream functions (especially those in the "backend" Remix code) access to this context within the scope of a single reques ...

In Angular, the data retrieved from the API will only appear on the page once it has been manually

Recently, I started working on an Angular project and encountered a problem with data display after each component routing. Initially, the data is not displayed until the page is reloaded. You can see the issue in the screenshots: [![After reload][2]][2]. ...

Is there a way to invoke a client-side function from the server?

Is there a way to display an alert at the top of the browser if the SQL query returns empty results? I tried using the "alert" function, but I'm struggling with customizing its appearance. I have a function in my HTML code that triggers an alert, but ...

What are effective strategies for troubleshooting Dependency Injection problems in nest.js?

Can someone explain the process of importing a third-party library into NestJS using Dependency Injection? Let's say we have a class called AuthService: export class AuthService { constructor( @Inject(constants.JWT) private jsonWebToken: any, ...

Button in Angular gets stuck when a touchscreen is long pressed

In my Angular2 application, I am facing an issue with a button when running on a Windows 10 touchscreen PC in Chrome. Normally, the button works fine and executes the click function. However, if the button is held for 1-2 seconds, it gets stuck and fails t ...

Accessing the state from a child functional component and then adding it to an array of objects in the parent component

I'm facing a challenge with a parent component that needs to manage the data of its child components stored in an array of objects. My goal is to add new child components and maintain their information within the parent's state as an array of obj ...

Issue encountered in TypeScript: Property 'counter' is not found in the specified type '{}'.ts

Hey there, I'm currently facing an issue while trying to convert a working JavaScript example to TypeScript (tsx). The error message I keep encountering is: Property 'counter' does not exist on type '{}'.ts at several locations wh ...