How to deduce a string literal using a ternary conditional in TypeScript

Here is a simple illustration:

function doSomething(animal: 'bird' | 'fish'){ }

let flies=true;

const animal = flies ? 'bird' : 'fish'

doSomething(animal);         

In the assignment to `animal` from the ternary conditional, TypeScript infers type `'bird' | 'fish'`. (If `animal` were not constant, it would give an error since it would infer type string which is not assignable to 'bird' or 'fish')

However,

const parms = {
    animal: flies ? 'bird' : 'fish'
}
doSomething(parms); /* Argument of type '{ animal: string; }' is not    
                        assignable to parameter of type '{ animal: "bird" | "fish"; } */

Here, it infers string from the ternary conditional. Is there a way to maintain this style without defining a type and declaring the field `animal` as that type?

Answer №1

String literal types are not always inferred by Typescript, except in specific situations. Typically, a property does not automatically imply a literal type unless there are additional factors that indicate a literal type for the property (this is unrelated to the ternary operator).

In an upcoming release of Typescript 3.4 (currently available as typescript@next on npm), it will be possible to indicate to the compiler that you want object literals to be inferred according to this issue:

let flies=true;
// infers type as { readonly animal: "bird" | "fish"; }
const parms ={
    animal: flies ? 'bird' : 'fish'
} as const

Prior to version 3.4, a workaround in Typescript 3.3 and earlier involved using a function to specify the desired literal type inference:

let flies=true;
function withLiteralTypes<T extends Record<string, P>, P extends string | number | null | boolean | Record<string, P>> (o: T) {
    return o;
}
// infers type as { animal: "bird" | "fish"; }
const parms =withLiteralTypes({
    animal: flies ? 'bird' : 'fish',
})

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

How can you apply an active class using React-Router?

My React-Router navigation issue nav.tsx import React from 'react' import { menu } from './menu' import { Link } from 'react-router-dom' import styles from './HamburgerMenu.module.scss' const HamburgerMenu: React.F ...

Angular and Node version discrepancies causing problems

This particular CLI version is designed to work with Angular versions ^11.0.0-next || >=11.0.0 <12.0.0, however an Angular version of 13.0.0 was detected instead. If you need assistance with updating your Angular framework, please refer to the follo ...

Clearly defining the data types for static dictionary values, while also deducing the precise structure or at least the keys

My goal is to create a static dictionary that is defined as a single object literal. I want to: Specify the type of values explicitly for typechecks and IDE suggestions Still have the ability to infer the exact shape, or at least keys I can achieve the f ...

Tips for enlarging the font size of a number as the number increases

Utilizing the react-countup library to animate counting up to a specific value. When a user clicks a button, the generated value is 9.57, and through react-counter, it visually increments from 1.00 to 9.57 over time. Here's the code snippet: const { ...

Efficient Typescript ambient modules using shorthand notation

Exploring the code snippet from the official module guide, we see: import x, {y} from "hot-new-module"; x(y); This syntax raises a question: why is 'x' not within curly brackets? What does this coding structure signify? ...

I want to search through an array of tuples to find a specific value in the first index, and if there is a match, I need to return the value in the second index of the matching tuple

I am dealing with an array of tuples: var tuparray: [string, number][]; tuparray = [["0x123", 11], ["0x456", 7], ["0x789", 6]]; const addressmatch = tuparray.includes(manualAddress); In my function, I aim to verify if the t ...

Convert a JavaScript variable to a TypeScript interface

In my JavaScript project, I am utilizing TypeScript and JSDOC for code validation against the TS compiler. When analyzing my code, the TS compiler identifies an error in the following snippet: interface IBox { idx: number; } interface IBoxes { ...

Tips for effectively utilizing the drag and drop feature with the Table Component in Ant Design

Recently, I received a new project from another team, and my client is requesting some changes to the admin page. Specifically, they want to customize the order of data pulled from the database. For instance, they would like to arrange the job positions in ...

The identifier "id" is not a valid index for this type

The code snippet below demonstrates the similarities and differences between the functions addThingExample2 and addThing. While addThingExample2 directly uses the union type Things, addThing utilizes a generic parameter THING extends Thing. The expression ...

A guide to setting properties using a Proxy object

Within my class, I have included a Proxy which is structured as follows: export class Row<T extends ModelItems> { private _row: T = <T>{} public constructor(rowItems?: T) { if (rowItems) { this._row = rowItems } return new Proxy( ...

A tip for transferring the value of a binding variable to a method within the template when the button is clicked

I am currently exploring the concept of binding between parent and child components using @Input, @Output, and EventEmitter decorators. This is demonstrated in the HTML snippet below: <h1 appItemDetails [item]="currentItem">{{currentItem}}& ...

What is the best way to access a web.config key using Typescript?

Is there a way to retrieve key values in an Angular 2 application using TypeScript? add key="localPath" value="http://localhost:618/" add key="serverPath" value="http://api.azure.net/" I am looking to access the values of "localpath" and "serverpath" in ...

What is the best way to transfer information from one column to another column with Office Scripts?

I'm in the process of automation with Microsoft Excel using Office Scripts, and I've hit a roadblock when trying to transfer data from one column to another. https://i.sstatic.net/56ipi.png Specifically, I need to move the data from the Date co ...

Typescript decorator specifically designed for abstract generic Container class's child elements

Struggling with Typescript generics in my project, specifically with Typescript 2.6. My goal is to design a MobX store that implements a class decorator for basic authentication checks. This decorator should take a class type derived from the abstract gen ...

Callbacks are never fired in SQL Server because of the tedious connection

I have successfully connected to a SQL Server instance hosted in Azure through DBeaver and can browse all the data. After installing tedious with the following commands: npm install tedious npm install @types/tedious This is the exact code I am using: im ...

What is the best way to implement a nested fetch call?

I have a piece of code similar to the one below that is functioning properly: const url = "https://something"; let data2 = JSON.stringify({ source: "https://someimage.jpg" }); const test1 = fetch(url, { method: "POST", hea ...

What is the best way to handle various sections with changing structures within a complex form using react-hook-form?

I am working on a complex form that has sections A, B, and C, each of which can be in shape A1 or A2, B1 or B2, C1, or C2. Users are required to fill out settings based on whether the section is set to "advanced" or "basic". I want users to submit the enti ...

Encountering an error with Mongoose's .pre('save') method in Typescript

Every time I attempt to use the hash password .pre hook, it refuses to save. userSchema.pre("save", async function (next) { let user = this as UserDocument; if (!user.isModified("password")) return next(); const salt = await bcry ...

Exploring the potential of utilizing dynamic types in a TypeScript React application alongside React Hook Form

Currently, I am in the process of converting a React application that was previously not using TypeScript to now incorporate TypeScript. I am facing an issue with the use of React Hook Form's setValue method. The component I am working on serves as a ...

Unlock the Power of Typography in React with Material UI Styled Components

Exploring the world of material UI is a new experience for me. I am currently in the process of creating a styled component using Typography. Below is what I have attempted so far: import styled from 'styled-components'; import { FormGroup, ...