Is it possible to restrict the type of a function parameter based on other parameters provided?

type ItemX = { type: 'X', value: 'X1' | 'X2' | 'X3' };
type ItemY = { type: 'Y', value: 'Y1' | 'Y2' };
type Item = ItemX | ItemY;

function processItem(item: Item) {
  // ...
}

function multipleItems<I extends Item, T extends I['type'], V extends I['value']>(type:T, value: V) {
  // ... type and value should be 
}

// Examples
processItem({ type: 'X', value: 'X1' });
processItem({ type: 'X', value: 'Y1' }); // type error

multipleItems('X', 'X1');
multipleItems('X', 'Y1'); // no type error

Link to Typescript Playground

Is there any way to make this last example cause a type error, just like in the second example, but only using two parameters (type and value)?

I tried this solution, but it would require me to add a third parameter like item: I to the multipleItems function. Anyway, in that case, the first fn processItem would be simpler.

Answer №1

There are two distinct approaches that come to mind.


The initial approach involves modifying multiParams() to accept a rest parameter consisting of a union of tuple types, which can be immediately destructured into correlated variables - type and value. See the implementation below:

type MultiParamsArgs = Resource extends infer R ? R extends Resource ?
  [type: R['type'], value: R['value']]
  : never : never;

function multiParams(...[type, value]: MultiParamsArgs) { }

In this scenario, a distributive conditional type is used over the union within Resource to generate the MultiParamsArgs type, defining the acceptable argument list for multiParams().

The second approach introduces generality to multiParams() by incorporating a key type K from a helper mapping type MultiParamsMap, establishing a connection between the type K representing type and the indexed access type MultiParamsMap[K] corresponding to value. This version of the function looks as follows:

type MultiParamsMap = { [T in Resource as T['type']]: T['value'] }

function multiParams<K extends keyof MultiParamsMap>(type: K, value: MultiParamsMap[K]) { }

While the first method leverages narrowed variables for discrimination tasks, the second method excels in providing detailed IntelliSense support during coding sessions. Ultimately, the choice between these approaches hinges on personal requirements and preferences.

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

The ng-model used within an *ngFor loop is not displaying the correct value

I am working with a JSON file in my Angular2 App. The specific JSON object I am referring to is named tempPromotion and I am trying to access the data within ['results'] like this: tempPromotion['response_payload']['ruleset_list ...

Issue with MUI Dialog: Struggling to pass the onClose function to onClick within dialog actions

Currently, I am in the process of developing a reusable component called Dialog which is based on MUI dialog. Below is the code snippet for this component: import React from 'react'; import { Dialog as MuiDialog, DialogProps, Button, Dia ...

Angular version 12 (node:3224) UnhandledPromiseRejectionWarning: Issue encountered with mapping:

Trying to generate the translation file in my Angular project using the command ng extract-i18n --output-path src/translate, I encountered this error message: \ Generating browser application bundles (phase: building)...(node:3224) UnhandledPromiseRej ...

How can I restrict a generic type to include the new() method?

Is there a way to create a function similar to the following in TypeScript? createEntity<TEntity>(): TEntity { return new TEntity(); } In C#, we can achieve this using: void TEntity CreateEntity<TEntity>() where TEntity : new() How would ...

Combining functions does not result in a callable function, even when the parameters fulfill the constraints of each individual function

I have encountered an issue while trying to compile a Typescript snippet: function foo(v: string) { return 'foo'; } function bar(v: string | number) { return 'bar'; } const notCallable: typeof foo | typeof bar = function() {} as any; ...

Is emitting a side effect event acceptable within an RxJS pipe?

Currently, I am utilizing RxJS within the context of an Angular application. Within my service, there is functionality to reinitialize the entire application with different settings as needed. @Injectable() class BootstrapService{ public initApplicatio ...

Is there a beginner's pack or trial version available for utilizing TypeScript with IBM Cloud Functions / OpenWhisk?

While working on developing actions in IBM Cloud Functions, I have been primarily using Node.js / Javascript and Python for coding. However, I haven't come across specific instructions on how to incorporate TypeScript into IBM Cloud Functions. I am c ...

Angular 4 not throwing errors when using Array.Filter and find

Having trouble filtering a list using Array.find and filter functions. Here is the function in question: setSupplierDetails(supplierId) { const supplier = this.suppliers.filter(tempSupplier => tempSupplier.id === supplierId)[0]; this.supplierName = ...

What is the best way to display several components in a particular location within a parent component using react-native?

I am struggling to position multiple components within a parent component at a specific location determined by some calculations. The calculations for the vertical position seem accurate, but the components are not appearing where they should be. I have ex ...

Node was experiencing difficulty locating a module alias that had been defined in the tsconfig file and package.json

I'm currently working on deploying a typescript project in production mode. You can find the code on Github here Executing npm run start:dev launches the server at http://localhost:3000/ Running npm run build generates the dist folder The definitio ...

Warning: The use of the outdated folder mapping "./" in the "exports" field for module resolution in the package located at node_modulespostcsspackage.json is deprecated

I recently upgraded my Node to version 16 and since then I have been encountering this issue while building my Angular app. Warning: The folder mapping "./" used in the "exports" field of the package located at ".../node_modules/postcss/package.json" is de ...

Problem encountered during NextJS build: ReferenceError - 'window' is undefined

While I am in the process of developing my app, I have encountered a perplexing issue with a ReferenceError: window is not defined. This error seems to be happening even though I am utilizing 'use client' "use client"; import React, { u ...

Generating statically typed events in Vue

Recently, I encountered a run-time error in a Vue / Typescript application due to the lack of typing for custom events. For example, the following code compiles without any issues but fails at run-time: // Within component A public foo() { this.$e ...

Retrieve a collection of nested dictionaries containing flask and angular data

In my app development journey with flask and ionic(angular), I'm working on returning a JSON list. Here's the python code snippet: def get-stocks(): # Select all stocks cursor.execute("""SELECT * FROM `tbl_symbol_index`"" ...

What is the process for transforming a multi-dimensional array containing strings into a multi-dimensional array containing numbers?

I've got a unique structure of data composed of arrays with strings as seen below: [ 0: Array(1) 0: Array(6) 0: [5.379856, 43.252967] 1: [5.422988, 43.249466] 2: [5.425048, 43.245153] 3: [5.383804, 43.239 ...

What is the process for assigning a value to a property?

I am currently developing an Angular application that utilizes reactive forms. I need to retrieve the values of dynamically created fields within a form group. Here is the code I have implemented: this.formSaisieSecondary = this.fb.group({ ...

What are the properties used in functional components of React?

Seeking guidance on passing React component props to another component: interface IMyComponent { props: Props<any> } const MyComponent: FC = ({ props }) => { } Previously, I attempted to utilize the React.Props type after consulting this que ...

What can TypeScript do with high-level type functions?

Take a look at the following pseudo-code attempting to define a higher-order type function with a function-typed parameter M<?>: type HigherOrderTypeFn<T, M<?>> = T extends (...) ? M<T> : never; The syntax M<?> is not va ...

What is the method for utilizing a class variable without assigning a value to it initially

class testClass { student: { name: string, age: number } constructor(options?: any) { this.student = { name: '', age: 0 }; } setStudent(name:string, age:number) { this.student.name ...

Using TypeScript with React Redux, encountering issue of property not being available in the Reducer from the ActionType

Currently, I am learning how to implement a Reducer in Redux while using React with TypeScript. I have encountered an issue that I need help with. Below are the action types that I am working with: import { LoginResponseInterface } from "../../interfaces ...