I'm looking for a way to modify my standard function so that it can receive warnings

Below is my function called defc

    export function defc<T extends Record<string,any> >(f:(a:T)=>void){
      return function(a:T){
        return f(a)
      }
    }

The purpose of this function is to ensure the correct return type of functions.

However, I am facing an issue where I am not receiving the required warning message implicitly has an 'any' type

    const foo=defc(function({bar}){//wanted warnings: Binding element 'bar' implicitly has an 'any' type.ts(7031)
      console.log(bar)
    })

My query is: Is there a way to modify defc in order to receive the warning as intended?

Answer №1

bar is implicitly assigned an any type, but that was your intention, right? You set up defc to anticipate a parameter of type

T extends Record<string, any>
.

By providing the inner function signature as function({ bar }) to defc, TypeScript deduces that the type of { bar } extends Record<string, any>, hence inferring that bar is of type any. This eliminates any implicit type errors.

Even if you modify Record<string, any> to Record<string, number>, TypeScript will still determine the type of bar as number and not raise objections. However, TypeScript would alert you when attempting to use the newly created foo with a non-number type:

function defc<T extends Record<string, number>>(f: (a: T) => void) {
    return function(a: T) {
        return f(a)
    }
}

const foo = defc(function({ bar }) { // no issues here, TS can infer that `bar` is `number`
    console.log(bar)
})

foo({ bar: 1 }) // ok!
foo({ bar: "wrong type" }) // Type 'string' is not assignable to type 'number'.

P.S. A potential bug could exist in your code. The behavior may be intentional or accidental.

When you don't specify the parameter type of the inner function passed to defc, it allows unrestricted arguments for the resulting foo function.

function defc<T extends Record<string, any>>(f: (a: T) => void) {
    return function(a: T) {
        return f(a)
    }
}

const foo = defc(function({ bar }) {
    console.log(bar)
})

foo({ bar: 1 }) // this is valid, will print "1"
foo({ notExists: "hm" }) // but this is also valid and will print "undefined"

foo anticipates a Record<string, any> and retrieves bar from it; however, TypeScript won't raise warnings if bar is missing inside that Record.

If you know the expected keys in advance, it's advisable to define them explicitly.

function defc<T extends Record<string, any>>(f: (a: T) => void) {
    return function(a: T) {
        return f(a)
    }
}

const foo = defc(function <T extends Record<"bar", any>>({ bar }: T) {
    console.log(bar)
})

foo({ bar: 1 }) // prints "1"
foo({ notExists: "hm" }) // invalid, `foo` expects only the `bar` key

Answer №2

Your defc function allows for generic inference in the type T. If the callback provided lacks parameter annotations and relies on contextual typing, the generic inference will default to its constraint. In this case, if the constraint is set as Record<string, any>, the callback type will resolve to

(a: Record<string, any>) => void
. The inferred any for bar does not constitute an implicit any due to explicit declaration within the contextual type. Unfortunately, there is no way to selectively prevent this inference.

It appears that Record<string, any> may not be the ideal choice, as it permits properties under a string index signature that you might not intend. To restrict T to the object type, which encompasses non-primitive types without predefined properties, consider the modified function below:

function defc<T extends object>(f: (a: T) => void) {
    return function (a: T) {
        return f(a)
    }
}

When calling defc without specifying { bar }, T defaults to object, rendering ({bar}) => void as (a: object) => void. Any attempt to access the undeclared property bar will result in an error message indicating its unexpected nature.

You can test the code in the TypeScript Playground using this 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

Using custom types for prop passing in Next.js with TypeScript

After making a http call, I obtain an array containing JSON data. This data is then assigned to a type called Service. type Service = { id?: string; name?: string; description?: string; }; The api call is made in getServerSideProps and the Service type is ...

Transitioning from Webpack to Vite: Resolving Path Alias and Ensuring Proper Imports

Recently, I decided to transition my project from Webpack to Vite with "vite": "^4.3.9",. However, upon running npm start, I encountered the following error: Error: The dependencies imported could not be resolved: In my React Typesc ...

Transform nested properties of an object into a new data type

I created a versatile function that recursively converts nested property values into numbers: type CastToNumber<T> = T extends string ? number : { [K in keyof T]: CastToNumber<T[K]> }; type StringMap = { [key: string]: any }; const castOb ...

Calculating the frequency of a variable within a nested object in an Angular application

After assigning data fetched from an API to a variable called todayData, I noticed that there is a nested object named meals within it, which contains a property called name. My goal is to determine the frequency of occurrences in the name property within ...

The TypeScript compiler is tolerant when a subclass inherits a mixin abstract class without implementing all its getters

Update: In response to the feedback from @artur-grzesiak below, we have made changes to the playground to simplify it. We removed a poorly named interface method and now expect the compiler to throw an error for the unimplemented getInterface. However, the ...

Resolving issues with Typescript declarations for React Component

Currently utilizing React 16.4.1 and Typescript 2.9.2, I am attempting to use the reaptcha library from here. The library is imported like so: import * as Reaptcha from 'reaptcha'; Since there are no type definitions provided, building results ...

Are the functions 'useEffect' and 'useCallback' being repetitively used in this case?

I have implemented a custom hook in my React application to manage back navigation actions (POP). The functionality is operational, but I can't help but notice that useCallback and useEffect seem to be performing similar tasks. Here is the snippet of ...

Addressing ESLint and TypeScript Issues in Vue.js with Pinia: A comprehensive guide

Experiencing difficulties with Vue.js + Pinia and need assistance to resolve these issues. Error: 'state:' is defined but never used. Here is the snippet of code located in @/stores/user.ts. import { defineStore } from 'pinia' export ...

Obtaining gender information by utilizing checkboxes in Angular 7

I have developed an Angular application that enables users to filter samples by gender using checkboxes. The options include male, female, or both genders selected. Currently, the filtering works for selecting either male or female individually, as well as ...

Using Typescript generics within a callback function

I am currently working on developing a versatile service that can fetch data from a remote source and create objects based on that data. @Injectable() export class tService<T> { private _data: BehaviorSubject<T[]> = new BehaviorSubject([]) ...

Preventing the "Block-scoped variable used before its declaration" error in an Angular/TypeScript tree structure with child/parent references

Imagine a scenario where we have a set of simple nodes/objects forming a tree structure, each with parent and children references. The challenge lies in the need to reference both the parent and children nodes independently from the tree itself. This means ...

What is the process of substituting types in typescript?

Imagine I have the following: type Person = { name: string hobbies: Array<string> } and then this: const people: Array<Person> = [{name: "rich", age: 28}] How can I add an age AND replace hobbies with a different type (Array< ...

Switch up your component button in Angular across various pages

I've created a new feature within a component that includes a toolbar with multiple buttons. Is there a way to customize these buttons for different pages where the component is used? Component name <app-toolbar></app-toolbar> Component ...

In my coding project using Angular and Typescript, I am currently faced with the task of searching for a particular value within

I am facing an issue where I need to locate a value within an array of arrays, but the .find method is returning undefined. import { Component, OnInit } from '@angular/core'; import * as XLSX from 'xlsx'; import { ExcelSheetsService } f ...

Why has Jasmine decided not to wait for my promises to finish?

Utilizing the FileSystem API to generate a directory with 2 entries for a test, I am facing an issue where Jasmine does not wait for the promise to resolve before executing the test, resulting in failure. Despite using the async wrapper, the problem persis ...

Showing the Enum name rather than the value in an Angular HTML template for a bound Typescript Interface

After retrieving an array of objects with various properties from a .NET Controller, I am utilizing the following Typescript code: import { Component, Inject } from '@angular/core'; import { HttpClient } from '@angular/common/http'; @Co ...

"Customizing the template of the Angular Material 2 datepicker: A step-by-step

Looking to make changes to the templates of the angular 2 material date-picker? These templates are located within various internal components in @angular/material/esm5/datepicker.es5.js. One option is to directly modify the template in the node package, ...

Converting a string value into an object in Javascript using a command that functions similarly to eval in Python

When working with Python, the stringValue variable is often assigned as a string: stringValue = '{"DATA":{"VERSION":1.1, "STATE":True, "STATUS":"ONLINE"}}' To convert this string into a Python di ...

Typescript overloaded function parameters explained

I am currently working on the following code snippet: import React from "react"; interface BaseFormValue { name: string; } export interface NewFormValue extends BaseFormValue { email: string; } export interface ExistingFormValue extends Ba ...

Discovering ways to optimize argument type declarations in TypeScript

If we consider having code structured like this: function updateById( collection: Record<string, any>[], id: number, patch: Record<string, any> ): any[] { return collection.map(item => { if (item.id === id) { return { ...