Finding the specific type within a union based on its field type

I am trying to implement a function sendCommand that returns a value of type specified by the union InputActions, selected based on the action_id type. Below is my code snippet:

interface OutputAction1 {
  command: 'start',
  params: string;
}

interface OutputAction2 {
  command: 'end'
  data: string;
}

type OutputActions = OutputAction1 | OutputAction2;

interface InputAction1 {
  action_id: 'start',
  token: string
}

interface InputAction2 {
  action_id: 'end',
  userData: string
}


type InputActions = InputAction1 | InputAction2;

const sendCommand = (action: OutputActions): Extract<InputActions, {action_id: OutputActions['command']}> => {
    return action.command === 'start' ? {
      action_id: 'start',
      token: '123'
    }:{
    action_id: 'end',
    userData: '123'
    }
 
}

let k = sendCommand({command: 'start', params: ''})
k.token // Property 'token' does not exist on type 'InputAction2'

I expect variable k to have type InputAction1, however it currently has type InputActions. Is there a way to inform TypeScript to infer the expected type based on the action_id from the arguments?

Sandbox

Answer №1

In my opinion, opting for Function Overloads would be the best choice here to keep things simple. The correct return type will be automatically inferred.

function sendCommand(action: OutputAction1): InputAction1;
function sendCommand(action: OutputAction2): InputAction2;
function sendCommand(action: OutputActions) {
  return action.command === "start"
    ? {
        action_id: "start",
        token: "123"
      }
    : {
        action_id: "end",
        userData: "123"
      };
}

let k = sendCommand({command: "start", params: ""});
// let k: InputAction1

let k2 = sendCommand({command: "end", data: ""});
// let k2: InputAction2

TypeScript Playground

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

Show just a single error message if there are two validation errors present

In my AngularJS timepicker, users can choose multiple time segments for each day. The code has validation to detect duplicates and overlapping time segments. For example, entering 11:00am - 12:00am twice will trigger two error messages: 'Overlapping t ...

Signing in to a Discord.js account from a React application with Typescript

import React from 'react'; import User from './components/User'; import Discord, { Message } from 'discord.js' import background from './images/background.png'; import './App.css'; const App = () => { ...

`The error "mockResolvedValue is not recognized as a function when using partial mocks in Jest with Typescript

Currently, I am attempting to partially mock a module and customize the return value for the mocked method in specific tests. An error is being thrown by Jest: The error message states: "mockedEDSM.getSystemValue.mockResolvedValue is not a function TypeEr ...

Retrieve indexedDb quota storage data

I attempted the code below to retrieve indexedDb quota storage information navigator.webkitTemporaryStorage.queryUsageAndQuota ( function(usedBytes, grantedBytes) { console.log('we are using ', usedBytes, ' of ', grantedBytes, & ...

The type undefined cannot be assigned to the type even with a null check

When looking at my code, I encounter an error stating Argument of type 'Definition | undefined' is not assignable to parameter of type 'Definition'. Even though I am checking if the object value is not undefined with if (defs[type] != u ...

Error: The 'Window' object is not defined. The use of Client in NextJS13 is not

I've been attempting to integrate NextJS 13 with react-leaflet, but I keep encountering the error "window is not defined" when running my component. I attempted using the "use client" declaration at the beginning of the file and adding a check for "ty ...

We could not find the requested command: nodejs-backend

As part of my latest project, I wanted to create a custom package that could streamline the initial setup process by using the npx command. Previously, I had success with a similar package created with node.js and inquirer. When running the following comma ...

Changing function arguments in TypeScript using the spread operator

Could the Tuple spreading syntax in Typescript be utilized to consolidate these function overloads? The challenge lies in the necessity to refactor the function arguments into new types. type Type = TString | TNumber type TString = { tag: 'string&apos ...

Using React Native with TypeScript to Select the Parent and Child Checkboxes within a FlatList

My objective is to ensure that when a user selects a checkbox for one of the parent items ('Non Veg Biryanis', 'Pizzas', 'Drinks', 'Desserts') in the flatlist, all corresponding child items should also be selected au ...

The name is not found when using attribute, but it is found when using extends

Lately, I've encountered difficulties with creating large TypeScript modules, and there's one thing that has been puzzling me. Specifically, the following scenario doesn't seem to work: // file A.ts export = class A { } // file main.ts imp ...

The `Home` object does not have the property `age` in React/TypeScript

Hey there, I'm new to React and TypeScript. Currently, I'm working on creating a React component using the SPFX framework. Interestingly, I'm encountering an error with this.age, but when I use props.age everything seems to work fine. A Typ ...

Having trouble executing the project using Gulp

I'm a beginner in front-end development and I am working on an existing project that I'm having trouble running. According to the documentation, I should run the project by executing: $ gulp && gulp serve But I keep getting this error: ...

Is there a way to define the length of children when performing props type checking?

I need my component to only allow for three children that are considered as type React.ReactChild. However, I'm uncertain if ReactChild is the most suitable type to validate. Essentially, these children should be three distinct sections. function Top ...

An email value being recognized as NULL

create-employee.html <div class="form-group"> <label for="exampleInputEmail1">Email address</label> <span><input type="text" [required]="!standingQueue" class="form-control" name="exampleInputEmail1" ...

Receiving an eslint error while trying to integrate Stripe pricing table into a React web application

If you're looking to incorporate a Stripe documentation code snippet for adding a stripe-pricing-table element, here's what they suggest: import * as React from 'react'; // If you're using TypeScript, don't forget to include ...

Typescript throwing error TS2307 when attempting to deploy a NodeJS app on Heroku platform

Encountering an error when running the command git push heroku master? The build step flags an error, even though locally, using identical NodeJS and NPM versions, no such issue arises. All automated tests pass successfully without any errors. How can this ...

Utilize the gsap ScrollTrigger in conjunction with React's useRef() and Typescript, encountering issues with type mism

Recently, I've been trying to add some animation to a simple React Component using the GreenSock ScrollTrigger plugin. However, I ran into an issue due to types mismatch in my Typescript project. Here's a snippet of the code: import React, {useRe ...

Retrieve all the characteristics accessible of a particular course

I am facing a situation where I have the following class structure: class A { id: number propertyA: string constructor(id: number) { this.id = id } } let a = new A(3) console.log(SomeFunction(a)) // expected output = ['id', ' ...

What is the importance of using getters for functions involving Moment.js in vueJS and typescript?

weekOfMonth() calculates the current month and week within that month. <template> <h3>{{ weekOfMonth }}</h3> </template> <script lang="ts"> export default class HomeView extends Vue { const moment = require(& ...

Ways to reveal heavily nested components when the Angular change detector fails to detect them

A particular component called Grid has been implemented with the following template: <div *ngFor="let row of item.rows"> <div *ngFor="let col of row.cols"> <div *ngFor="let grid of col.items"> < ...