Determining the accurate return type of a function based on a type map

I have a task where a function is needed to return the correct type based on a key-type mapping it has access to.

Here's a simplified example of what I'm working on. Almost there, but seems like something is missing.

Note: This is intended for a library and user-provided types are unknown.

type Plane = {
    name: string;
    wings: number;
};

type Car = {
    name: string;
    wheels: number;
};

type Vehicles = {
    cars: Car;
    planes: Plane;
};

type TypeMap = { [key: string]: any };

type Mapper<VehicleMapType extends TypeMap = TypeMap> = {
    getVehicle<
        VehicleType extends
            | Extract<keyof VehicleMapType, string>
            | never = Extract<keyof VehicleMapType, string>
    >(
        type: VehicleType
    ): VehicleMapType[VehicleType];
};

const mapper: Mapper<Vehicles> = null;

const vehicle1 = mapper.getVehicle('cars');
// This outputs a Car!
console.log(vehicle1);

const getVehicles = <
    VehicleMapType extends TypeMap = TypeMap,
    VehicleType extends Extract<keyof VehicleMapType, string> | never = Extract<
        keyof VehicleMapType,
        string
    >
>(
    type: VehicleType
): VehicleMapType[VehicleType] => {
    return null;
};

const vehicle2 = getVehicles<Vehicles>('cars');
// Need help to get just a Car instead of a Car or a Plane?
console.log(vehicle2);

Thanks!

Edit

In addition to that, we're encountering an issue with the Mapper implementation as evident from this TS Playground

Answer №1

To properly invoke the function, you must provide both generics (in your case, you only provided Vechicles), or

  • utilize a functional abstraction to deduce the types, as shown below:

TS Playground

type StringKeys = Record<string, any>;

type Named = { name: string };
type Plane = Named & { wings: number };
type Car = Named & { wheels: number };

type Vehicles = {
  cars: Car;
  planes: Plane;
};

type Mapper<T extends StringKeys> = {
  getVehicle<K extends keyof T>(type: K): T[K];
};

const mapper: Mapper<Vehicles> = {
  getVehicle (type) {
    const vechicles: Vehicles = {
      cars: {name: 'a car', wheels: 4},
      planes: {name: 'a plane', wings: 2},
    };
    const result = vechicles[type];
    if (result) return result;
    throw new Error('unknown vehicle type');
  }
};

const vehicle1 = mapper.getVehicle('cars'); // Car


// Generic functional abstraction:

const pickFrom = <T extends StringKeys>(o: T): <K extends keyof T>(key: K) => T[K] => {
  return key => o[key];
};

declare const vehicles: Vehicles;
const getVehicles = pickFrom(vehicles);
const vehicle2 = getVehicles('cars'); // Car

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

Styling map controls in Google Maps and React

import { GoogleMap, useLoadScript } from '@react-google-maps/api'; import { IGoogleCredentials } from '../../context'; import { googleMapsContainer } from './droppoint-map.css'; export interface IDroppointMapProps { googl ...

D3 event: Latest in Type Definitions for Version 6 and Beyond

I have a collection of widgets created using d3 (version 5) and now I need to transition them to version 7. After consulting the migration guide at , I discovered the updated syntax for events: // previously element.on('click', (d, i, e) => .. ...

Compiler is unable to comprehend the conditional return type

I've done some searching, but unfortunately haven't been able to find a definitive solution to my issue. Apologies if this has already been asked before, I would appreciate any guidance you can offer. The problem I'm facing involves a store ...

Prefix each type within a string union with a specific word

Can a new type be generated from a union type by applying a specific pattern to each element in the union? For example, adding a prefix: type EventNames = 'DragStart' | 'Drag' | 'DragStop' type HandlerNames = Prefix<'o ...

The Angular template is throwing an error stating that c_r1.getCatType is not a valid function

Within my Angular project (version 9.1.0), I have a class structured like this: export class Contract { contractName: string; limit: number; public getCatType(): string{ if(this.limit > 0) return 'p'; return &ap ...

Issue with Hooks (Batched update cycle) - error code TS6133: Unused declaration of '' is detected and not being utilized

I am attempting to pass the previous state as an argument to batch state updates in a single cycle using isOpen => index, but it throws a semantic error TS6133: 'isOpen' is declared but its value is never read. const initialState = -1; const [ ...

Encountering the following error message: "E11000 duplicate key error collection"

Currently, I am in the process of developing an ecommerce platform using the MERN stack combined with TypeScript. As part of this project, I am working on a feature that allows users to provide reviews for products. The goal is to limit each user to only o ...

Capture a screenshot with Puppeteer at a random URL stop

I am facing an issue with my service nodejs running on Ubuntu, where I use puppeteer to capture screenshots of pages. However, the method page.screenshot({fullPage: true, type: 'jpeg'}) sometimes fails on random URLs without displaying any errors ...

tips on waiting for the outcome of an http request (synchronous http request, utilizing http request as a promise)

My TypeScript service loads base data through HTTP requests from a server. The requests are for various data, arranged in order from independent data to data that depends on other data. Due to the asynchronous nature of HTTP requests, there is no guarant ...

Handling Errors in Angular 4

If a client sends a POST request with a LicenseNumber that already exists in the database (and must be unique), the server will respond as follows: {"errorCode":"Validation Error", "errorMessage":"Invalid inputs.", ...

Leveraging Angular 2 to retrieve information from mongoDB

I recently finished setting up my nodejs project which includes a database and some data. The database was created using the following URL: mongodb://localhost:27017/ Check out the code snippet below: var MongoClient = require('mongodb').MongoC ...

Unlocking the power of URL manipulation in Fastify using Node.js

I'm attempting to retrieve specific parts of the URL from a Fastify server. For instance, the URL looks like this: http://localhost:300/query_tile/10/544/336 Within the Fastify server, I need the values for z/x/y. I've attempted the following ...

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 ...

I'm curious if it's possible to set up both Tailwind CSS and TypeScript in Next.js during the initialization process

When using the command npx create-next-app -e with-tailwindcss my-project, it appears that only Tailwind is configured. npx create-next-app -ts If you use the above command, only TypeScript will be configured. However, running npx create-next-app -e with ...

pertains to a specific numerical quantity, but is currently being utilized as a category in this context

As a newcomer to typescript and node.js, I am attempting to utilize both in my development process. I have created a model with mongoose and imported it into my users.service.ts file. However, I encountered an error message stating: 'CreateUserDto&ap ...

How can I utilize regex to change the background color of a specific character in a react/typescript application?

One of my components contains mapped data, and I've been tasked with changing the background color of specific characters, namely "Miss", "Mrs", and "Ms". I've attempted to use regex, but I keep encountering an error that the object is possibly n ...

Exploration of narrowing union types in React with TypeScript

import { Chip } from "@mui/material"; type CourseFilterChipsRangeType = { labels: { from: string; to: string }; values: { from: number; to: number }; toggler: (from: number, to: number) => void; }; type CourseFilterChipsCheckType = { ...

Identifying and handling errors in the outer observable of an RXJS sequence to manage

Encountered a puzzling rxjs issue that has me stumped. Here's the scenario: I have two requests to handle: const obs1$ = this.http.get('route-1') const obs2$ = this.http.get('route-2') If obs1$ throws an error, I want to catch it ...

Ensuring seamless collaboration between Typescript node modules

Is there anyone who has successfully set up a configuration where module 1, using TypeScript, is referencing another module 2 also with TypeScript, and both are utilizing tsd types like node.d.ts? I have been able to compile and use both modules without a ...

TypeError: Unable to access the 'classify' property of an object that has not been defined (please save the ml5.js model first)

In my React app, I have set up ml5.js to train a model by clicking on one button and make predictions with another. However, I encounter an error when trying to test the model for the second time: TypeError: Cannot read property 'classify' of und ...