What circumstances allow for the exclusion of "generic types" in TypeScript?

There seems to be inconsistency in how the TypeScript compiler handles parametrised types. Sometimes it raises an error if a type is not passed, other times it doesn't, and the reasoning behind this behavior is unclear.

It appears that the structure of the function may influence whether the compiler can infer the type T, but there are instances where this assumption does not hold true.

Several experiments were conducted to test this theory:

  1. Experiment 1

    function cannotBeInferred<T>(): T {
      return 0 as T;
    }
    
    const a1 = cannotBeInferred();
    const a2 = cannotBeInferred<string>();
    
    • Variable a1 is inferred as unknown; an unexpected outcome
    • Variable a2 is correctly inferred as string
  2. Experiment 2

    function canBeInferredNativeType<T>(par: T): T {
      return par;
    }
    
    const b1 = canBeInferredNativeType('test');
    const b2 = canBeInferredNativeType<string>('test');
    
    • Variable b1 is of type "test", which should generate an error
    • Variable b2 is correctly inferred as string
  3. Experiment 3

    function canBeInferredInterface<T>(param: { something: T }): T {
      return param.something;
    }
    
    interface Something { something: string };
    const param: Something = { something: 'blabla' };
    
    const c1 = canBeInferredInterface({ something: 'test' });
    const c2 = canBeInferredInterface(param);
    const c3 = canBeInferredInterface<number>({ something: 123 });
    
    • Variable c1 is inferred as string, despite potential ambiguity
    • Variable c2 is also inferred as string, which could benefit from clearer error handling
    • Variable c3 is correctly inferred as number

This inconsistency calls for a more uniform approach. Is there a compiler option available to achieve this?

Answer №1

One interesting aspect of Typescript is the ability to exclude generic type parameters under certain conditions:

  • If they are optional, meaning a default value has been set
    type Type<Optional = string> = .....
    => you can utilize Type without explicitly stating the generic parameter, which will default to string
  • If they can be inferred and not partially specified
type Func<Input, Return> = (input: Input) => Return;

const hoist = <Input, Return>(func: Func<Input, Return>, input: Input) => {

 return func(input);
}

const hoistReturnNumber = <Input, Return = number>(func: Func<Input, Return>, input: Input) => {

 return hoist<Input, Return>(func, input);
}

// fully inferrable, no specifications => OK
hoist((a: string) => parseInt(a), '12')

// specifying first parameter, leaving second optional => OK
hoistReturnNumber<string>((a: string) => parseInt(a), '12')

// fully inferrable with first parameter specified while second required => ERROR
hoist<string>((a: string) => parseInt(a), '12')

// fully specified
hoist<string, number>((a: string) => parseInt(a), '12')

Although it may seem an obsessive-compulsive behavior trigger, having inferred generic parameters enables deep inference and truly versatile code that does not necessitate arduous refactoring when types involved undergo changes.

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

Creating a JSON object from an array of data using TypeScript

This might not be the most popular question, but I'm asking for educational purposes... Here is my current setup: data = {COLUMN1: "DATA1", COLUMN2: "DATA2", COLUMN3: "DATA3", ..., COLUMNn: "DATAn"}; keyColumns = ["COLUMN2", "COLUMN5", "COLUMN9"]; ...

Limit the keys of an object to only those present in the provided array

I am trying to use Typescript to limit the keys of a given object in a React component to only the items contained within an array that is also passed to the component: <MyComponent values={{ dog:true }} items={['dog']} /> // valid ...

Encountering Error TS2411 when upgrading from Typescript version 1.0.0 to 1.1.0-1

After updating my TypeScript using npm install typescript -g, I have been encountering a recurring error during compilation. Although the compilation is successful, it's becoming tedious. cmd.exe /D /C C:/Users/Vado/AppData/Roaming/npm/tsc.cmd --sour ...

React's componentDidUpdate being triggered before prop change occurs

I am working with the CryptoHistoricGraph component in my app.js file. I have passed this.state.coinPrices as a prop for this element. import React from 'react'; import axios from 'axios'; import CryptoSelect from './components/cry ...

Error in React Typescript Order Form when recalculating on change

When creating an order form with React TypeScript, users can input the quantity, unit price, and select whether the item is taxable. In this simplified example, only 1 or 2 items can be added, but in the final version, users will be able to add 10-15 item ...

Guide to accessing references in a nested v-for loop using Vue 3, Typescript, and the Composition API

I've been grappling with the challenge of migrating Vue2 to Vue3 Composition API using Typescript. Refs don't seem to function in the same way, leaving me unsure of how to make them work in Vue3. It used to be so simple in Vue 2 with a code snipp ...

Problem with ngStyle: Error indicating that the expected '}' is missing

I encountered an error in the Chrome console when trying to interpret the code below: <div [ngStyle]="{'width': '100%'; 'height': '100%'; 'background-size': 'cover'; 'background-repeat&ap ...

Utilizing Vue 3 with TypeScript for enforcing type checking on single file components' props

In my exploration of Vuetify and other sources, I discovered that it is possible to incorporate type checking for props within the template tag. Let's consider a simple button component: <template> <div> <button>{{ label ...

Material UI Error TS1128: Expected declaration or statement for ButtonUnstyledProps

While working on my application that utilizes Material UI, I encountered an issue. I keep receiving a Typescript error and haven't been able to find a solution for it. TypeScript error in C:/.../node_modules/@mui/base/ButtonUnstyled/index.d.ts(3,1): D ...

Guide to leveraging tanstack table v8 for sorting data within a specific date range

Received data from API: const abc = [ { date: '2023-12-8', value: 'mop' },{ date: '2023-10-8', value: 'qrs' } ] How can we create a date range using two input fields when the dates are in string forma ...

Distinguishing Between TypeScript Interface Function Properties

Could anyone clarify why the assignment to InterfaceA constant is successful while the assignment to InterfaceB constant results in an error? interface InterfaceA { doSomething (data: object): boolean; } interface InterfaceB { doSomething: (data: obje ...

Encountering a Angular 12 Observable<Object[]> Error while attempting to execute a GET request

I've been grappling with this error I encountered while working on Angular 12. Cannot find a differ supporting object '[object Object]' of type 'object'. NgFor only supports binding to Iterables such as Arrays. This is the code f ...

Organize JSON data in Angular 6 from an observable based on a specific key

Note: While I am familiar with sorting a regular array of objects using .sort(), I am facing a challenge with an observable object that I am not accustomed to. My task involves retrieving a JSON array of objects with a service: import { Injectable } from ...

In what scenario would one require an 'is' predicate instead of utilizing the 'in' operator?

The TypeScript documentation highlights the use of TypeGuards for distinguishing between different types. Examples in the documentation showcase the is predicate and the in operator for this purpose. is predicate: function isFish(pet: Fish | Bird): pet ...

Is it possible to have a button within a table that, when clicked, opens a card overlaying the entire table?

I'm having an issue with a table and card setup. When I click the button in the table, the card that appears only covers part of the table. I want it to cover the entire table area based on the content inside the card. How can I make this happen? I&a ...

Utilize a single component across various instances for enhanced efficiency

After thorough research, I couldn't find a solution to my problem despite similar questions being asked. I've developed an angular component for styled radio buttons and need to use it multiple times on different instances. To get a better unde ...

Parent dropdown passes selected value to child component for triggering various API calls

Can anyone assist me with sending http requests to service methods based on a dropdown selection using Rxjs Observables in Angular? I am passing the selected value from the dropdown to a child component. Thank you for your help. child-component.ts @Inp ...

What is the reason behind providing self-references in Typescript interfaces?

type SomeGeneric<T> = { x: T; } type TTest = SomeGeneric<TTest> & { a: string; }; // The type alias 'TTest' creates a circular reference. interface ITest extends SomeGeneric<ITest> { // This is acceptable a: string ...

What could be causing the absence of the exported Object when importing into a different Typescript project?

I am currently in the process of developing a React component library using Typescript that I want to import into another Typescript project. Specifically, I want to import an Analytics chart library into a storybook for demonstration and testing purposes. ...

Is it possible to utilize an @Input() in Angular with multiple types?

Is it possible for a parent component to pass an object in @Input to the child component that may not always be the same? For instance, can I use: @Input() obj: string | number; In my scenario, I have two different objects as potential inputs: @Input() ob ...