Understanding how to infer literal types or strings in Typescript is essential for maximizing the

Currently, my goal is to retrieve an object based on the parameter being passed in. I came across a similar question that almost meets my requirements. TypeScript function return type based on input parameter However, I want to enhance the function's capability to accept strings as well. In cases where the parameters passed in are not of the literal type, it should infer any or unknown

Let me illustrate what I mean with some code.

interface Circle {
    type: "circle";
    radius: number;
}

interface Square {
    type: "square";
    length: number;
}

type TypeName = "circle" | "square" | string; 

type ObjectType<T> = 
    T extends "circle" ? Circle :
    T extends "square" ? Square :
    unknown;

function getItems<T extends TypeName>(type: T) : ObjectType<T>[]  {
    ...
}

Note that TypeName has a union type of both literal types and string. My expectation is to be able to infer the return type based on the parameter when using the type. For example:

const circle = getItems('circle'); // infers: Circle
const something = getItems('unknown'); // infers: unknown

The above functionality works perfectly fine. However, I am unable to get the IDE to suggest the options. I anticipate seeing options like: 'circle' | 'square' | string.

Is it feasible to achieve this?

Answer №1

Sorry, it's not feasible because the string is a supertype of a string literal so

type TypeName = "circle" | "square" | string; 

is essentially the same as

type TypeName = string; 

Nevertheless, you can utilize function overloading to reach your objective

type TypeName = "circle" | "square"
type ObjectType<T> = 
    T extends "circle" ? Circle :
    T extends "square" ? Square :
    never

function getItems<T extends TypeName>(type: T) : ObjectType<T>[]
function getItems(type: string) : unknown[]
function getItems(type: string) {
  // implementation goes here
}

Regardless, here is an alternative solution

type TypeName = "circle" | "square" | {} & string; 

type ObjectType<T> = 
    T extends "circle" ? Circle :
    T extends "square" ? Square :
    unknown;

function getItems<T extends TypeName>(type: T) : ObjectType<T>[]  {
    ...
}

Give it a try yourself

Answer №2

To achieve this functionality, you can make use of overloads and specific conditional utility types:

interface Circle {
    type: "circle";
    radius: number;
}

interface Square {
    type: "square";
    length: number;
}


type KnownShape = Circle | Square
type IsKnownShapeType<T extends string, U = KnownShape> = U extends { type: T } ? T : never
type ShapeForType<T extends string, U = KnownShape> = U extends { type: T } ? U : never

function getShapes<T extends string>(type: IsKnownShapeType<T>) : ShapeForType<T>[]
function getShapes<T extends string>(type: T) : any[]
function getShapes<T extends string>(type: T) : any[] {
    return []
}

const circle = getShapes('circle'); // infers: Circle
const something = getShapes('unknown'); // infers: any

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

Ways to broaden React categories for embracing html attributes as props?

When designing a component that accepts both custom props and HTML attribute props, what is the best approach for creating the interface? The ideal interface should also accommodate React-specific HTML props, such as using className instead of class. Here ...

Using Typescript to transform a list into function arguments

My current challenge involves a set of arguments structured like so: const args: FeatureEventArg[] = [ { name: 'username', type: 'string', }, { name: 'message', type: 'string', }, { name ...

Avoid making API calls in every ngOnInit() function

I am currently developing an Angular front-end for a web-based application. One of the challenges I am facing is that all sub-page drill downs, implemented as different Angular components, make identical API calls in the ngOnInit() method. This repetitiv ...

Standardized identification code

My request response needs to be defined, but the key name may vary. It will always be a string, but the specific key depends on the request. These are the possible responses: { someRequest: { message: 'success', status: 200 } } { someOtherReques ...

Challenges with exporting dynamically generated divs using jspdf in an Angular 2 project

I have been utilizing the jspdf library to print div elements in my current project. But I recently discovered an issue where dynamic content within a div is not being printed correctly. Specifically, when incorporating simple Angular if statements, jspdf ...

Verify Angular Reactive Form by clicking the button

Currently, I have a form set up using the FormBuilder to create it. However, my main concern is ensuring that validation only occurs upon clicking the button. Here is an excerpt of the HTML code: <input id="user-name" name="userName" ...

Angular 2 is throwing an error, stating that Observable is not defined

I'm currently working with Observable and ChangeDetectionStrategy to notify other components about any changes that occur. However, I am encountering an issue where the Observable object addItemStream is coming up as undefined. Can anyone spot what mi ...

Can you explain the execution process of this Http.post method and provide details about the code path it follows

As I delve into the world of web development, one aspect that has me stumped is the functionality of the Http.post section within a project I stumbled upon on GitHub. Specifically, this pertains to an ExpressJS with Typescript repository I came across. So, ...

When using the e.target.getAttribute() method in React, custom attributes may not be successfully retrieved

I am struggling with handling custom attributes in my changeHandler function. Unfortunately, React does not seem to acknowledge the custom "data-index" attribute. All other standard attributes (such as name, label, etc.) work fine. What could be the issu ...

Determine whether there is only one array in the object that contains values

At the moment, I am attempting to examine an array in order to determine if only one of its elements contains data. Consider this sample array: playersByGender = { mens: [], womens: [], other: [] }; Any combination of these elements may contain dat ...

AngularTS - Using $apply stops the controller from initializing

Every time I launch the application, the angular {{ }} tags remain visible. Removing $scope.$apply eliminates the braces and displays the correct value. I am utilizing Angular with Typescript. Controller: module Application.Controllers { export class Te ...

Declarations for TypeScript in NPM packages

In order to streamline my development process with bun.sh using workspaces as npm packages, I have created a tool available here. However, I am facing two issues: After bun installing the 'core' packages from npm and testing a sample, I encounte ...

Using TypeScript to implement functions with multiple optional parameters

Imagine having a function like the one shown here: function addressCombo(street1:string, street2:string = "NA", street3?:string) { console.log("street1: " + street1); console.log("street1: " + street2); console.log("street2: " + street3); } I ...

Tips for verifying that parameters possess designated characteristics in TypeScript

How can I ensure that data2 and data3 work correctly, while data1 triggers an error if the data type is not specified as shown in the code below? I need to validate that when a user enters params like {name: 'aa', age: 20}, it should throw an er ...

Exploring the concepts of TypeScript interface inheritance and the powerful capabilities of generics in type inference

I'm facing a dilemma with TypeScript interfaces, generics, classes... not exactly sure which one is causing the issue. My mind is in overdrive trying to find a solution but I can't seem to simplify things. Here's what I'm grappling with ...

TS2339: The 'contacts' property is not found within the 'Navigator' type

I am currently developing a contacts application that utilizes the Apache Cordova plugins for contacts. However, when attempting to run the npm run bundle command for my application, I encountered the error mentioned in the title above. Can anyone guide me ...

What is the method for launching a standalone terminal window from a vscode extension?

I am in the process of creating a custom extension for Visual Studio Code. My goal is to open a separate terminal window and execute multiple commands consecutively, similar to Terminal.sendText but not within the integrated terminal. Is there a method to ...

The input argument must be of type 'PollModel', as the property 'pollId' is required and missing in the provided 'any[]' type

Hey there! An issue popped up when I tried to pass an empty array as a model in my Angular project. The error message reads: "Argument of type 'any[]' is not assignable to parameter of type 'PollModel'. Property 'pollId' is ...

Extract values from an object using Typescript

Here is my JavaScript code: const { a, b, c } = { a : "hello", b : "stackoverflow", c : "it's greate" }; I am interested in converting this to TypeScript. Is there any solution for this? ...

Having trouble locating node_modules post deployment?

Although the title may lead you astray, please stay with me for a moment. I've created a basic Angular2 application in Visual Studio 2015 and have now deployed it to Azure. While having node_modules in the development environment worked perfectly fi ...