Is it possible to deduce a more precise type from a dictionary in TypeScript? What steps can be taken to assist TypeScript

Behold the incredible code I have:

export type Locale = "en" | "fr";
export type Namespace = "products" | "home";

const dict = {
  en: {
    home: { title: "My Super Title" },
    products: { product: "Product" },
  },
  fr: {
    home: { title: "Mon Super Titre" },
    products: { product: "Produit" },
  },
};

export const getTranslation = (namespace: Namespace, locale: Locale) => {
  return dict[locale][namespace];
};

const t = await getTranslation("home", "en");
// Typescript infer of T 
// const t: {
//   title: string;
// } | {
//   product: string;
// } | {
//   title: string;
// } | {
//   product: string;
// }

I assumed TypeScript would correctly infer this, but unfortunately, that is not the case.

So my initial query is, why is TypeScript unable to infer this accurately?

Is there a way I can assist by manually typing getTranslation to ensure proper inference?

I was initially anticipating:

{
    title: string;
}

By the way, my TypeScript version is "^5"

Perhaps I am not utilizing the correct keyword to uncover the solution.

Nevertheless, I am firmly convinced that there exists a type solution to resolve my dilemma.

Answer №1

To implement a more specific type inference in your function parameters, you can utilize generic type parameters.

Instead of explicitly mentioning the types of your function parameters as unions (Namespace and Locale), you can allow TypeScript to deduce a more precise type while still applying constraints to avoid unintended types:

export const getTranslation = <N extends Namespace, L extends Locale>(namespace: N, locale: L) => {
    return dict[locale][namespace];
};

const t = getTranslation("home", "en");
//    ^? { title: string; }

const t2 = getTranslation("products", "fr");
//    ^? { product: string; }

const t3 = getTranslation("unknown", "other"); // Error as expected: Argument of type '"unknown"' is not assignable to parameter of type 'Namespace'.
//                        ~~~~~~~~~

Playground Link

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

In the latest version of Angular, accessing document.getelementbyid consistently returns null

I am struggling with a component that looks like this export class NotificationPostComponent extends PostComponent implements OnInit, AfterViewInit { commentsDto: IComment[] = []; commentId = ''; ngOnInit(): void { this.route.data ...

Displaying svg files conditionally in a react native application

I have developed an app specifically for trading dogs. Each dog breed in my app is associated with its own unique svg file, which are all stored in the assets folder (approximately 150 svg files in total). When retrieving post data from the backend, I re ...

Guide on importing a markdown file (.md) into a TypeScript project

I've been attempting to import readme files in TypeScript, but I keep encountering the error message "module not found." Here is my TypeScript code: import * as readme from "./README.md"; // I'm receiving an error saying module not found I als ...

Investigating the issue: Why is my React Typescript canvas image resizing component producing small, fuzzy images from high-quality, large images

I have developed a small image resizer but am facing an issue with the output images being blurry, especially when working with large images. import React, { useState } from 'react'; interface PropsInterface { placeholder: string; resizeTo: ...

A guide on determining the number of rows in an ag-grid with TypeScript and Protractor

I am currently working on extracting the number of rows in an ag-grid. The table is structured as follows: <div class="ag-body-container" role="presentation" style="height: 500px; top: 0px; width: 1091px;"> <div role="row" row-index="0" row-id="0 ...

Arrangement of items in Angular 2 array

Received a JSON response structured like this JSON response "Terms": [ { "Help": "Terms", "EventType": "Success", "Srno": 1, "Heading": "Discount Condition", "T ...

The unique Angular type cannot be assigned to the NgIterable type

As a newcomer to Angular, I was introduced to types and interfaces today. Excited to apply my new knowledge, I decided to enhance my code by utilizing a custom interface instead of a direct type declaration: @Input() imageWidgets: ImageWidget; Here is the ...

NextJS VSCode Typescript results in breakpoints becoming unbound

I have been following the instructions provided by Next.js from their official documentation on debugging using Visual Studio Code found here: https://nextjs.org/docs/advanced-features/debugging#using-the-debugger-in-visual-studio-code When attempting to ...

What is the best way to populate an Angular Bootstrap Table Widget with data obtained from an API request?

I am currently in the process of making an API call and utilizing the received data in a Bootstrap Angular Table Widget. The specific widget I am utilizing can be found here: Complete example (Angular powered bootstrap widget) Ensure you are working with ...

Exploring two main pages, each with tabs displaying two negative behaviors

I developed an app with an ion-footer at the bottom of each root page : <ion-footer> <ipa-footer-buttons></ipa-footer-buttons> </ion-footer> The <ipa-footer-button> component is structured as follows: html: <ion-toolb ...

Broaden the current category within the MUI Theme

I am attempting to enhance the current options within MUI's theme palette by adding a couple of properties. Take a look at this example: declare module @material-ui/core/styles/createMuiTheme { interface CustomOptions extends SimplePaletteColorOptio ...

Challenge when providing particular strings in Typescript

Something seems to be wrong with the str variable on line number 15. I would have expected the Typescript compiler to understand that str will only ever have the values 'foo' or 'bar' import { useEffect } from 'react' type Ty ...

When I try to load JSON data using the http.get() method in my Angular 2 template, it returns

I've encountered an issue while attempting to read and parse a local json file into a custom class I created. The problem arises when trying to access properties of the class, as it throws errors indicating that the class is either null or undefined. ...

The activation of [routerLinkActive] triggers an error related to the data.split function

In my lazy loaded module, I have implemented simple routing as shown below: <div id="nav"> <div class="nav-content"> <div class="nav-item" [routerLink]="'basic'" [routerLinkActive]="active-nav"> <span ...

Utilizing the spread operator in Typescript to combine multiple Maps into a fresh Map leads to an instance of a clear Object

Check out the code below: let m1 = new Map<string, PolicyDocument>([ [ "key1", new PolicyDocument({ statements: [ new PolicyStatement({ actions: [&q ...

Ionic 2 faced an unresolved core-js dependency issue

Recently, I started working on a new Ionic 2 project and encountered an issue when trying to incorporate https://github.com/afrad/angular2-websocket. Upon installation, I received the warning message: UNMET PEER DEPENDENCY core-js@^2.4.1 The template pro ...

Incorporate the pdfmake.js file into my TypeScript file

Working on a VSTS web extension and looking to utilize PDFmake.js to generate a pdf. The PDFmake.js file needs to be imported into the node_nodules folder by running npm install pdfmake. To import this JavaScript file into my TypeScript file, I'm fol ...

Leveraging IF conditions on part of the worksheet title

Currently, my script is performing the task of hiding three columns for tabs in a workbook that start with "TRI". However, the execution speed is quite sluggish. I am seeking suggestions on how to optimize and enhance the performance. If possible, please p ...

Inheritance-based generic type inference in Typescript

Take a look at this piece of code: class A<T> { t?: T; } interface B {} class C implements A<B> {} function f<T1 extends A<T2>, T2>(a: T1): T2 | undefined { return a.t; } const result = f(new C()); const result2 = f(new A<B> ...

What's the reason behind the inconsistency of the exports field in typescript and npm?

Our software development kit @ltonetwork/lto is built using typescript. We utilize the tsc compiler to convert the codebase into JavaScript files stored in the lib directory. Within the package, there are multiple sub-packages located in subdirectories, e ...