Allow for an optional second parameter in Typescript type definition

Here are two very similar types that I have:

import { VariantProps } from "@stitches/core";

export type VariantOption<
  Component extends { [key: symbol | string]: any },
  VariantName extends keyof VariantProps<Component>
> = Extract<VariantProps<Component>[VariantName], string>;

export type Variants<
  Component extends { [key: symbol | string]: any }
> = Extract<VariantProps<Component>, string>;

Both types are almost identical, with the main difference being that the second type does not require a second generic parameter, therefore it excludes an index from the VariantProps<Component> type.

Is there a way to combine these types, making the second parameter optional and adjusting the result based on whether it is provided or not?

An attempted syntax for this would look like the following (though it is not valid):

import { VariantProps } from "@stitches/core";

export type VariantOption<
  Component extends { [key: symbol | string]: any },
  VariantName? extends keyof VariantProps<Component>
> = VariantName ?
        Extract<VariantProps<Component>[VariantName], string> :
        Extract<VariantProps<Component>, string>;

Answer №1

One way to establish a "default" value for a generic is as follows:

type Foo<X extends string, Y extends object = {baz: string}> = {
    xParam: X;
    yParam: Y;
}

In your particular situation, it could look something like

VariantName extends keyof VariantProps<Component> = ???
where ??? represents the default type you desire.

To cater to different scenarios, you can utilize conditional types to adjust the outcome based on whether it's set or not:

// yParam defaults to "null" if second generic type is not specified
type Foo<X extends string, Y extends object | unknown = unknown> = {
    xParam: X;
    yParam: Y extends object ? Y : null;
}

type Bar = Foo<'hello', {}>;
/*
type Bar = {
    xParam: "hello";
    yParam: {};
}
*/

type Baz = Foo<'world'>;
/*
type Baz = {
    xParam: "world";
    yParam: null;
}
*/

If I grasp your requirements correctly from your query, this updated code snippet might be suitable:

export type VariantOption<
  Component extends { [key: symbol | string]: any },
  VariantName extends keyof VariantProps<Component> | unknown = unknown
> = VariantName extends keyof VariantProps<Component>
  ? Extract<VariantProps<Component>[VariantName], string>
  : Extract<VariantProps<Component>, string>;

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

What is the best way for me to determine the average number of likes on a post?

I have a Post model with various fields such as author, content, views, likedBy, tags, and comments. model Post { createdAt DateTime @default(now()) updatedAt DateTime @updatedAt id String @id @default(cuid()) author U ...

The type does not contain a property named `sort`

"The error message 'Property sort does not exist on type (and then shoes4men | shoes4women | shoes4kids)' pops up when attempting to use category.sort(). I find it puzzling since I can successfully work with count and add a thousand separato ...

Issues with using hooks in a remote module in Webpack 5 module federation

I am attempting to create a dynamic system at runtime using Module Federation, a feature in webpack 5. Everything seems to be working well, but I encounter a multitude of 'invalid rule of hooks' errors when I add hooks to the 'producer' ...

Is there a way to get interpolation working outside of onInit?

In one component, I have set up a functionality to subscribe to an HTTP GET request from a service and store the response in a variable. The service contains a Subject as an observable so that it can be subscribed to in another component. However, while I ...

The debate between using "this" versus "classname" to access static elements in

When working with TypeScript, I've observed that there are multiple valid approaches for accessing a static class member. class MyClass { private static readonly FOO: string = "foo"; public DoSomething(): void { console.log(MyClass.FOO);} pu ...

Utilizing Typescript for parsing large JSON files

I have encountered an issue while trying to parse/process a large 25 MB JSON file using Typescript. It seems that the code I have written is taking too long (and sometimes even timing out). I am not sure why this is happening or if there is a more efficien ...

Outdated compiler module in the latest version of Angular (v13)

After upgrading to Angular 13, I'm starting to notice deprecations in the usual compiler tools used for instantiating an NgModule. Below is my go-to code snippet for loading a module: container: ViewContainerRef const mod = this.compiler.compi ...

Issue: Module "expose?Zone!zone.js" could not be located

Just started experimenting with Angular 2 and encountering an issue when importing zone.js as a global variable: https://i.stack.imgur.com/gUFGn.png List of my packages along with their versions: "dependencies": { "angular2": "2.0.0-beta.3", "es ...

Developing an object using class and generic features in Typescript

I am currently working on creating a function or method that can generate sorting options from an array. One example is when using Mikro-ORM, where there is a type called FindOptions<T> that can be filled with the desired sorting order for database q ...

Can you explain the mechanics behind the functionalities of @angular and @type dependencies?

This inquiry may have been raised before, but I couldn't uncover all the solutions. If that's the case, my apologies. I have a good grasp on how package.json and dependencies / dev-dependencies function in Node applications. Currently delving i ...

Controlling numerous websockets using React

I am currently developing a single-page application using React.js with a JSON RPC 2.0 backend API that relies on websockets. Managing multiple websocket connections simultaneously across different React.js components has been a challenge. Initially, I th ...

Filtering without specifying a data type and (with any luck) converting

Upon defining the function below: const filterAndCast = <T, U>( items: T[], predicate: Predicate<T>, cast: (x: T) => U, ) => items .reduce( (p, c) => [ ...p, ...(predicate(c) ? [cast(c)] ...

Customizing the placeholder text for each mat input within a formArray

I have a specific scenario in my mat-table where I need to display three rows with different placeholder text in each row's column. For example, test1, test2, and test3. What would be the most efficient way to achieve this? Code Example: <div form ...

Error: Element type is invalid: a string was anticipated, but not found

I recently experimented with the example provided in React's documentation at this link and it functioned perfectly. My objective now is to create a button using material-ui. Can you identify what is causing the issue in this code? import * as R ...

What is the best way to transfer data from a component to a .ts file that contains an array?

I am currently developing a budgeting application and I have a component that is responsible for holding values that I want to pass to an array stored in a separate file. While I can retrieve data from the array, I am facing difficulty in figuring out how ...

"Optimize Your Data with PrimeNG's Table Filtering Feature

I'm currently working on implementing a filter table using PrimeNG, but I'm facing an issue with the JSON structure I receive, which has multiple nested levels. Here's an example: { "id": "123", "category": "nice", "place": { "ran ...

"Implementing a Filter for Selecting Multiple Options in Ionic Framework

I need help with filtering books in an online library project using a modal page. The modal has 3 input fields for title, author, and year. How can I filter the books based on these inputs? Here is a snippet of my modal.html code: <ion-content pa ...

What is the Reason for TypeScript's Inability to Verify the Type of Dynamic Key Object Fields?

How come TypeScript allows the declaration of seta even though it doesn't return objects of type A? type A = { a: '123', b: '456' } // Returns copy of obj with obj[k] = '933' function seta<K extends keyof A> ...

Circular Dependencies in Angular (only the file name)

Previously, I used to keep interfaces and services in separate files but later combined them into one file since they were always requested together. For example, instead of having user.interface.ts and user.service.ts as separate files, I now have all the ...

Angular: How can the dropdown arrow in 'ng-select' be eliminated?

Is there a way to hide the dropdown arrow in an 'ng-select' element in Angular? <div class="col-md-6"> <ng-select id="selectServiceType" [items]="clientServiceTypes$ | async" pl ...