Creating a type and function to split elements into a Tuple with a variable number of items

Challenge
My goal is to develop a function and its corresponding typing that can effectively split an array into multiple typed arrays inside a tuple. The concept involves calling the .divide method on an array instance, providing a flexible number of typeguards or typeguard-like functions. The output of divide should be a Tuple containing an equal number of typed arrays as the typeguards specified. Any items that do not match any of the provided typeguards will be removed from the result. Here's an example of how this could be used:

const [typeAs, typeBs, typeCs] = myArr.divide(isTypeA, isTypeB, isTypeC);
const [typeFs] = myArr.divide(isTypeF)
const [typeAs, typeFs, typeDs, typeCs, typeXYZs] = myArr.divide(isTypeA,isTypeF,isTypeD,isTypeC,isTypeXYZ)
//and so on

To start off, I've made an attempt at setting up a function for dividing into 3 types with potential for a variable length Tuple + arguments list. I've defined an interface for Array:

type TGuard<S> = ((input: any) => input is S) | ((input: any) => boolean);
divide<OrigType, NewT1, NewT2, NewT3>(
            t1: TGuard<NewT1>,
            t2: TGuard<NewT2>,
            t3: TGuard<NewT3>,
        ): [NewT1[], NewT2[], NewT3[]];

Here's my implementation:

Array.prototype.divide = function <OGType, NewT1, NewT2, NewT3>(
    t1: TGuard<NewT1>,
    t2: TGuard<NewT2>,
    t3: TGuard<NewT3>,
): [NewT1[], NewT2[], NewT3[]] {
    const d3: [NewT1[], NewT2[], NewT3[]] = [[], [], []];
    const discards: OGType[] = [];
    this.forEach((item) => {
        t1(item) ? d3[0].push(item) : t2(item) ? d3[1].push(item) : t3(item) ? d3[2].push(item) : discards.push(item);
    });

    return d3;
};

While this implementation works for 3 types, I'm struggling to extend it to accept a dynamic number of typeguards and generate a variable number of typed arrays within a Tuple wrapper. I have various ideas for the final implementation, but currently my biggest challenge lies in determining the appropriate type signature.

Answer №1

Let's create a custom divide function with the following signature:

function divide<T, G extends (((item: T) => item is any) | ((item: T) => boolean))[]>(array: T[], ...guards: G): InferGuards<G>;

This function allows us to iterate over the guard types in G and infer their respective types:

type InferGuards<G> = {
    [K in keyof G]: G[K] extends (item: any) => item is infer U ? U[] : unknown[];
};

If a type guard cannot be determined, the resulting type defaults to unknown[], indicating uncertainty.

Try it out in the 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

I am experiencing difficulties with TypeORM connecting to my Postgres database

Currently, I am utilizing Express, Postgres, and TypeORM for a small-scale website development project. However, I am encountering challenges when it comes to establishing a connection between TypeORM and my Postgres database. index.ts ( async ()=>{ ...

Resetting Formik: Step-by-step guide to refreshing form post-dialog confirmation

I'm looking for a way to reset the form after it has been submitted. I tried using resetForm() on a child component, and while it did work, I encountered an issue where the resetForm only worked when clicking on a button in the child component. cons ...

Transfer a value to the ng2 smart table plugin extension

Upon reviewing the document and source code related to pagination implementation in the (advanced-example-server.component.ts), I discovered that the ServerDataSource being used only supported pagination through HTTP GET (_sort, _limit, _page, etc paramete ...

Creating Concurrent Svelte Applications with Local State Management

Note: Self-answer provided. There are three primary methods in Svelte for passing data between components: 1. Utilizing Props This involves passing data from a parent component to a child component. Data transfer is one-way only. Data can only be passed ...

Instances of classes in Typescript modules not properly imported resulting in undefined values

I am dealing with two files app.js ///<reference path='mongodb.d.ts'/> ///<reference path='MyDatabase.ts'/> module MyModule { import mongodb = module("mongodb"); new mongodb.Server(); var db = new MyDatabase(); // Th ...

extract keys and values from an array of objects

I would like assistance with removing any objects where the inspectionScheduleQuestionId is null using JS. How can we achieve this? Thank you. #data const data = [ { "id": 0, "inspectionScheduleQuestionId": 1, ...

Is it possible to conditionally trigger useLazyQuery in RTK Query?

Is it possible to obtain trigger from useLazyQuery conditionally? const [trigger] = props.useLazySearchQuery(); My objective is to retrieve trigger only when useLazySearchQuery is provided in the props. One way I can achieve this is by using const [ ...

I am looking to extract only the alphanumeric string that represents the Id from a MongoDB query

Working with mongoDB, mongoose, and typescript, I am facing an issue where I need to preserve the document ids when querying. However, all I can retrieve is the type _id: new ObjectId("62aa4bddae588fb13e8df552"). What I really require is just the string ...

Permitted the usage of a global variable of any type as the return value of a function that does not explicitly define its

Here's a snippet of TypeScript code that compiles successfully: let testVar: any; const testFunc: () => number = () => { return testVar; }; Why does this code compile without errors? What is the reasoning behind it? ...

Incorrect form of @types/elasticsearch SearchResponse

Whenever I utilize the ElasticsearchService from @nestjs/elasticsearch, the response does not align with the type SearchResponse from @types/elasticsearch. The issue is that SearchResponse is supposed to be an object, but I actually receive an array contai ...

What is the method to incorporate the current time into a date object and obtain its ISO string representation?

I'm using a ngbDatePicker feature to select a date, which then returns an object structured like this: {year:2020, month:12, day:03} My goal is to convert this date into an ISOString format with the current time. For example, if the current time is 1 ...

The abundance of options in WebStorm's code completion for Node can be overwhelming

I recently finished a project using NodeJS and TypeScript. I made sure to install the type definition files with 'tsd install node'. The code begins with the following lines: var http = require('http'); var server = http.createServer(. ...

Why is it necessary to define a property outside the constructor in Typescript, when in Javascript I wouldn't have to do that?

When working with Javascript, creating a class like the one below allows us to avoid declaring and initializing a property named logs outside of the constructor: class Logger { constructor() { this.logs = []; } } However, transitioning to TypeScri ...

Creating a dynamic horizontal list of buttons in NativeScript

I am currently diving into the world of NativeScript and I find myself struggling a bit with the MVVM concept, specifically when it comes to binding. I have configured my environment to work with TypeScript. On my HomePage, I am tasked with creating a hor ...

Create a recursive array structure that contains two distinct data types and specific guidelines

I have a unique array structure where the odd index always contains elements of TypeA and the even index always contains elements of TypeB. It is guaranteed that this array will always have an even length, never odd. The data structure of this array must ...

How to dynamically assign a value in a React datepicker component in a React application

Having troubles with react-datepicker? I encountered an issue where setting the value of react-datepicker from props caused it to either not show the value or display a 'wrong time format' error. Here is a snippet of the Datepicker code: this.sta ...

Are there more efficient methods for utilizing local scope when defining a variable?

Having experience in the ML world, I'm used to creating variables with limited scope like this: let myVar = let result1 = doSomething() let result2 = doSomethingElse() result1 + result2 In TypeScript, it seems you can achieve similar sco ...

Neglect TypeScript errors in project using yarn workspaces

While working on a repository with Yarn workspaces, I encountered an issue. When I use tsc --noEmit to perform type checking within the workspace folder, errors are appearing for packages stored in the top-level node_modules directory. ../../node_modules/ ...

Troubleshooting Angular: Unidentified property 'clear' error in testing

I've implemented a component as shown below: <select #tabSelect (change)="tabLoad($event.target.value)" class="mr-2"> <option value="tab1">First tab</option> <op ...

Using JavaScript or TypeScript to locate the key and add the value to an array

My dilemma involves an object structured as follows: [{ Date: 01/11/2022, Questionnaire: [ {Title: 'Rating', Ans: '5' }, {Title: 'Comment', Ans: 'Awesome' } ] }, { Date: 01/11/2022, Questionnaire ...