The type of a TypeScript field is determined by the type of another field

I am interested in creating an interpreter using TypeScript. This language has 2 primitive types, which I have defined as follows:

type DataType = { kind: 'number' } | {kind: 'string' }

Next, I would like to define another type that also includes its instance.

type _DataType<T extends 'type' | 'typedValue'> = {
    kind: 'number',
    value: T extends 'type' ? undefined : number,
} | {
    kind: 'string'
    value: T extends 'type' ? undefined : string,
}
type DataType = _DataType<'type'>;
type TypedValue = _DataType<'typedValue'>;

Everything seems to be working well so far. However, I am facing a challenge when trying to define a higher-order type like an array that can take the original DataType as a parameter. Here is what I have attempted:

type _HigherType<T extends 'type' | 'typedValue'> = {
    kind: 'Array',
    t: DataType,
    value: Array<?????>
} | {
    kind: 'Single',
    t: DataType,
    value: ?????
}
type HigherType = _HigherType<'type'>;
type HigherTypedValue = _HigherType<'typedValue'>;

It appears that the type of value depends on the type of t, but how can I express their relationship?

I am considering expanding HigherType as shown below:

type _HigherType<T extends 'type' | 'typedValue'> = {
    kind: 'Array',
    t: { kind: 'number },
    value: T extends 'type' ? undefined : Array<number>
} | {
    kind: 'Array',
    t: { kind: 'string' },
    value: T extends 'type' ? undefined : Array<string>
} | {
    kind: 'single',
    t: { kind: 'number' },
    value: T extends 'type' ? undefined : number
} | {
    kind: 'single',
    t: { kind: 'string' },
    value: T extends 'type' ? undefined : string
}

However, if there are m variants of DataType and n variants of HigherType (besides Array, e.g., Option, Set, etc.), we would need to write m*n variants, most of which have repeated parts. Is there a way to define only m + n variants?

Answer №1

If you are looking to represent m*n within the TypeScript system, utilizing distributivity is key.

Take a simple example for consideration:

type All = 'a' | 'b' | 'c'

type Variants<T extends string> = T extends any ? { tag: T } : any


type Result_ = Variants<All> // combination of all possible states

// Without distribution
type Variants2<T> = { tag: T }

type Result__=Variants2<All> // no combination

You can also refer to this article and this question for additional assistance.

Solution:


// TypeScript code snippet provided in the original post

Playground When in need to distribute something, always remember to utilize T extends 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

Issue found in Next.js 14: Hydration Error | Caution: Client Components can only receive plain objects from Server Components

I'm currently in the process of creating an application using Next.js 14, TypeScript, Mongoose, and MongoDB. In this app, I retrieved user data from my database and displayed them on cards along with relevant information like tags represented by badg ...

Retrieve the public variable of a child page from the parent page

Is there a way to access the public variable offlineArticlesCount from an inner child page within the parent page? Please note: Each of the 3 components mentioned below has its own set of modules. myPage.html - Parent Page <picks *ngFor="let pick of ...

What is the method to ensure that the children of an object strictly adhere to a specific interface or inherit from it?

Is there a way to ensure that an interface extends from another interface in TypeScript? For example: export interface Configuration { pages: { home: IHome; about: IAbout; // How can we make IAbout extend IPage? contact: IPage; }; } inte ...

Angular2 Release Candidate 5: Unable to connect to 'Property X' because it is not recognized as a valid property of 'Child Component'

I am currently working on upgrading a small Angular2 project, which is based on the Angular2 Seed project, to Angular2 RC5. Within my project, I have various features, one of them being referred to as home. The Home component utilizes a child component na ...

managing commitments in TypeScript

Is there a way to convert a promise into a string, or is there another method for handling this result? I am encountering an error stating "You cannot use an argument of type 'Promise' for a parameter of type 'string'." const pokemonIma ...

Trouble arises when attempting to transfer cookies between server in Fastify and application in Svelte Kit

In the process of developing a web application, I am utilizing Fastify for the backend server and Svelte Kit for the frontend. My current challenge lies in sending cookies from the server to the client effectively. Despite configuring Fastify with the @fas ...

What is the process for obtaining the eTag (MetaData) from a DocumentInfoRecord retrieval in SAP Cloud SDK using Javascript?

I am utilizing the SAP Cloud SDK for javascript to manage DocumentInfoRecords. Upon updating a DIR, I encountered error 428. Therefore, I require the etag of the request similar to what is available in the SAP Cloud API. How can I retrieve the etag from t ...

The @Input directive is failing to receive any data from its parent component

Recently, I delved into the workings of Angular's @Input feature and have found it quite useful thus far. My database is Firebase, and the data snippet I am fetching looks like this: { "page_area_business_image" : { "expand" : { ...

Typescript versus ES5: A comparison of Node.js server-side applications written in different languages

Note: When I mention regular JavaScript, I am referring to the ES5 version of JS. As I lay down the groundwork for a new project, my chosen tech stack consists of Node.js for the back-end with Angular2 for the front-end/client-side, and Gulp as the build ...

What are the solutions for handling undefined data within the scope of Typescript?

I am encountering an issue with my ngOnInit() method. The method fills a data list at the beginning and contains two different logic branches depending on whether there is a query param present (navigating back to the page) or it's the first opening o ...

Function generation using TypeScript

I'm in the process of creating a tool to automatically generate boilerplate code for me. The concept involves parsing all .json files within a folder called config, and then creating interfaces and auxiliary functions based on that data. Thanks to t ...

What is preventing me from utilizing TouchEvent in Safari browser?

Recently, while working on a project utilizing Angular 8, I encountered an issue regarding touch event handling. In my code, I had a handler setup like this: @HostListener('touchend', ['$event']) onTouchend(event: TouchEvent) { eve ...

Navigating the syntax of React with Typescript - Feeling lost

As I embark on my journey with Typescript/React, I find myself trying to decode the meanings behind it all. Coming from a C# background, this new environment presents a unique challenge for me. Despite going through several tutorials, I still find myself p ...

What can cause a problem with the reduce function that populates an empty object with keys in TypeScript?

I've encountered an issue with a function that is meant to reduce an object. The problem lies in using the reduce method to assign the values of acc[key] as object[key], which is resulting in errors in the code. I am trying to avoid using any specific ...

Error TS2769: Extending styles with props on base style in React Styled-components TypeScript results in a compilation error

I've been attempting to expand a base style to other styled components and encountering a TypeScript error. While I could achieve this in pure JavaScript, I'm facing difficulties in TypeScript. Base file _Modal.ts import styled from 'styled ...

Watch a live Youtube stream directly on Discord using discord.js!

Recently, I've been experimenting with creating a custom Discord bot as a way to have some fun and help out my friends. One of the features I'm trying to implement is streaming a live video in a voice chat whenever someone uses the !play study co ...

What is the reason for the index type being defined twice?

Here is an example from the official TypeScript documentation: class Animal { name: string; } class Dog extends Animal { breed: string; } // Error: indexing with a 'string' will sometimes get you a Dog! interface NotOkay { [x: numbe ...

"Experience the power of utilizing TypeScript with the seamless compatibility provided by the

I'm attempting to utilize jsymal.safeDump(somedata). So far, I've executed npm install --save-dev @types/js-yaml I've also configured my tsconfig file as: { "compilerOptions": { "types": [ "cypress" ...

Troubleshooting issues with accessing the _id property using Typescript in an Angular application

Encountering an Angular error that states: src/app/components/employee/employee.component.html:67:92 - error TS2345: Argument of type 'string | undefined' is not assignable to parameter of type 'string'. Type 'undefined' is ...

Managing clicks outside of the render function

I'm brand new to using React and I'm currently exploring how to properly manage an event handler outside of the Return() function within a component. If there's a more efficient or conventional way to do this, I'm definitely open to sug ...