Difficulty encountered when attempting to create a lambda function in TypeScript

I'm having trouble understanding the following lambda function definition in TypeScript. It could be a beginner question.

type P = { id: string }
type F = <T>(x: T) => string
const f: F = (x: P) => x.id
f({ id: 'abc' }

However, I keep getting the error message below:

Type '(x: P) => string' is not assignable to type 'F'.

Types of parameters 'x' and 'x' are incompatible.

Type 'T' is not assignable to type 'P'.

Update #1

I would like to provide some context for why I need a generic function. The purpose is to verify an input object, and each path of the object can be configured for verification as shown below:

type Option = { path: string; isVerified: <T>(t: T) => boolean }

const verify = (obj: any, options: Option[]): boolean => {
  const results = options.map(option => {
    const { path, isVerified } = option
    return isVerified(obj[path])
  })
  return results.every(x => x)
}

type A = number
type B = string
const obj = { a: 1 as A, b: 'abc' as B }

verify(obj, [
  { path: 'a', isVerified: (x: A): boolean => x > 0 },
  { path: 'b', isVerified: (x: B): boolean => x.startsWith('a') }
])

Update #2

Thank you for the initial answer, it resolved the issue mentioned in Update #1. However, the problem described in Update #1 is actually simplified. In reality, the path within the Option type could be either a string or a RegExp, which makes the code using Paths[K] invalid, as seen below:

type Option = { path: string | RegExp; isVerified: <T>(t: T) => boolean }

const verify = (obj: any, options: Option[]): boolean => {
  const results = Object.keys(obj).map(k => {
    const verifiers = options
      .filter(opt =>
        typeof opt.path === 'string' ? opt.path === k : opt.path.test(k)
      )
      .map(x => x.isVerified)
    return verifiers.every(verify => verify(obj[k]))
  })

  return results.every(x => x)
}

type A = number
type B = string
const obj = { a: 1 as A, b: 'abc' as B }

verify(obj, [
  { path: 'a', isVerified: (x: A): boolean => x > 0 },
  { path: /b/, isVerified: (x: B): boolean => x.startsWith('a') }
])

For more details, please refer to the Playground link.

Unfortunately, I'm still encountering the following error:

Type '(x: number) => boolean' is not assignable to type '(t: T) => boolean'.

Types of parameters 'x' and 't' are incompatible.

Type 'T' is not assignable to type 'number'.


Answer №1

When analyzing the sample code provided:

type P = { id: string }
type F = <T>(x: T) => string
const f: F = (x: P) => x.id

The type F is designed to be a generic function that can take any type T and return a string. In this case, for a function to conform to type F, it must accept arguments of any type. However, the function f only accepts arguments of type P, making it incompatible with type F.


In relation to the actual problem at hand, it becomes apparent that Option should represent a union type. This is due to the fact that the parameter type accepted by isVerified depends on the value of path:

type Option = {
    path: 'a',
    isVerified: (t: number) => boolean
} | {
    path: 'b',
    isVerified: (t: string) => boolean
}

To simplify the declaration of this union type for practical applications, one can define a type Paths to encompass the objects being verified. Subsequently, construct the Option type using a mapped type approach:

type Paths = { a: number, b: string }

type Option = {
  [K in keyof Paths]: {
    path: K,
    isVerified: (t: Paths[K]) => boolean
  }
}[keyof Paths]

With this setup, calls to the verify function will pass type-checks effortlessly while inferring parameter types automatically without needing explicit annotations:

const obj = { a: 1, b: 'abc' }

// Successfully verifies
verify(obj, [
  { path: 'a', isVerified: x => x > 0 },
  { path: 'b', isVerified: x => x.startsWith('a') }
])

This structure also ensures that if an incorrect parameter type is assigned to isVerified, a type error will be triggered as intended. This occurs because the path property restricts the type of isVerified method required:

// Results in a type error
verify(obj, [
  { path: 'a', isVerified: x => x.startsWith('a') },
  { path: 'b', isVerified: x => x > 0 }
])

One final adjustment is needed - adding a type assertion within the verify function to ensure that the correct type is assumed for isVerified, preventing potential inference issues like taking a parameter of type

never</code (the <em>intersection</em> <code>number & string
):

const verify = (obj: any, options: Option[]): boolean => {
  const results = options.map(option => {
    const { path, isVerified } = option

    // Type assertion required here
    return (isVerified as (t: Paths[typeof path]) => boolean)(obj[path])
  })
  return results.every(x => x)
}

Playground Link

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

Passing parameters in React classes is a crucial aspect of creating

Within a project I am currently working on, there is a const defined for the page header which takes in parameters and utilizes the information: interface UserProps { user?: { name: string, image: string }, loading?: boolean, error?: E ...

Tips for restricting User access and displaying specific sections of the menu

I have a component that utilizes map to display all menu parts. Is there a way to make certain parts of the menu hidden if the user's access rights are equal to 0? const Aside: React.FunctionComponent = () => { const[hasRight, setHasRight] = us ...

Converting a "String" value to a specific "Type" in Angular 2 using TypeScript

This is my current object, Home points to the import statement for Home component. import { Home } from '../home/home'; arr = [ { name: "Home", root: Home, icon: "calc" } ]; This is what I want to achieve: import { Home } from & ...

Utility managing various asynchronous tasks through observables and signaling mechanism

Looking for a Signal-based utility to monitor the status of multiple asynchronous operations carried out with observables (such as HTTP calls). This will enable using those signals in Components that utilize the OnPush change detection strategy. Imagine h ...

What is the significance of requiring a specific string in a Typescript Record when it is combined with a primitive type in a union?

I am facing an issue with the following data type: type ErrorMessages = Record<number | 'default', string>; When I declare a variable like const text: ErrorMessages = {403: 'forbidden'}, Typescript points out that default is miss ...

Creating a Jsonifiable type that aligns with static interfaces: A step-by-step guide

When working with Typescript, there are 3 types that share similarities as they are composed of primitive types, maps, and arrays: type Color1 = { [component: string]: number } type Color2 = { green: number red: number blue: number } interface Colo ...

Retrieving data from a JSON using Typescript and Angular 2

Here is an example of what my JSON data structure looks like: { "reportSections": [ { "name": "...", "display": true, "nav": false, "reportGroups": { "reports": [ { "name": "...", "ur ...

Combining one item from an Array Class into a new array using Typescript

I have an array class called DocumentItemSelection with the syntax: new Array<DocumentItemSelection>. My goal is to extract only the documentNumber class member and store it in another Array<string>, while keeping the same order intact. Is th ...

Having trouble executing my Node.js project written in Typescript due to an error: TypeError [ERR_UNKNOWN_FILE_EXTENSION] - the file extension ".ts" for /app/src/App.ts is unrecognized

After attempting to launch my application on Heroku, I encountered the following stack trace. The app is a basic ts.app using ts-node and nodemon. I am eagerly awaiting the solution to this issue. 2020-05-30T00:03:12.201106+00:00 heroku[web.1]: Starting p ...

Substitute Customized Interface Type Identifier

I am working on creating a versatile function interface for functor map while respecting the provided interface. In the code snippet below, my goal is to ensure that the value of mb is of type Maybe<number>, rather than the actual type Functor<num ...

Issue accessing member value in inherited class constructor in Typescript

My situation involves a class named A, with another class named B that is inherited from it. class A { constructor(){ this.init(); } init(){} } class B extends A { private myMember = {value:1}; constructor(){ super(); ...

Exposing the method to the outside world by making it public in

I have a situation where I have a base class with a protected method called foo, and a child class that needs to make this method publicly accessible. Since this method will be called frequently, I am looking for a more efficient solution to avoid unnecess ...

Ways to properly assign a key in a Generic Interface as the interface key

Can someone assist me with TypeScript generics? I am wondering how to access the T["value"] field within the ActionAdd interface. type UserValue = { username: string; }; interface User { id: number; value: UserValue; } interface ActionAdd<T = unkn ...

Automate the process of replacing imports in Jest automatically

Currently, I am in the process of setting up a testbench for a more intricate application. One challenge we are facing is that our app needs to call backend code which must be mocked to ensure the testbench runs efficiently. To address this issue, we utili ...

Angular 2: Issue with Table not Being Updated

https://i.stack.imgur.com/qLDUZ.png The UsersList component opens a new page upon clicking the table. https://i.stack.imgur.com/WwqIX.png After changing and saving user values, the updated value is not immediately reflected in the grid for the first tim ...

A guide on logging errors triggered within reducers

I'm facing a challenge in Redux where I am unable to get error messages logged to the console. My stack includes React, Redux Toolkit, and TypeScript. Here is a snippet of one of the reducers I've implemented: // Reducer const removeResourceRedu ...

What steps should I take to retrieve my information from a typescript callback function?

While I am familiar with using callbacks in JavaScript, I have recently started learning Angular and TypeScript. I am facing an issue with getting my data from a service back to where I need it after executing the callback function. The callback itself i ...

Angular modules are designed to repeat chunks of code in a

Whenever I scroll the page, my function pushes items to an array. However, I am facing an issue where the pushed items are repeating instead of adding new ones. Solution Attempt onScroll(): void { console.log('scrolled'); var i,j,newA ...

A guide on how to follow a specific item in an Angular 2 store

I have integrated ngrx store into my Angular2 application. The store reducer contains two objects as shown below: export function loadSuccessNamesAction(state: StoreData, action: loadSuccessNamesAction): StoreData { const namesDataState = Object.assi ...

TypeScript does not recognize the $.ajax function

Looking for help with this code snippet: $.ajax({ url: modal.href, dataType: 'json', type: 'POST', data: modal.$form.serializeArray() }) .done(onSubmitDone) .fail(onSubmitFail); ...