Exploring the application of keyof with object structures instead of defined types

Looking to create a new type based on the keys of another object in TypeScript.

Successfully achieved this through type inference. However, using an explicit type Record<string, something> results in keyof returning string instead of a union of the actual keys used.

View TypeScript Playground GIF

Check out this example code:

type FileType = "image" | "video" | "document";

type FileTypeList = Record<string, FileType>

const inferedFileList = {
    a: "image",
    b: "video",
    c: "document"
}

//type files = "a" | "b" | "c"
type files = keyof typeof inferedFileList;

const explicitelyTypedList : FileTypeList = {
    a: "image",
    b: "video",
    c: "document"
}

//type typedFiles = string
type typedFiles = keyof typeof explicitelyTypedList;

Access Relevant TypeScript Playground

Is it possible to use explicit typing like Record<string, something> and still obtain a union type with keyof? Perhaps there is a keyword that functions similarly to typeof, but utilizes the shape of an object instead of its declared type. Does TypeScript offer such functionality?

Answer №1

Utilizing type inference in TypeScript can be a powerful tool, and there is no harm in not manually annotating types.

When you explicitly type an object, it may actually become less precise:

const aString = "a" as const; // typeof aString is 'a'
const justString: string = aString; // typeof justString is 'string'

If you foresee the need for a particular type later on, you can use this syntax:

type FileTypeRecord = Record<keyof typeof inferedFileList, FileType>

This retrieves the entire Record type with existing keys (a, b, c) only.

To ensure that an object contains valid values with statically known keys, consider trying out this method:

type FileType = "image" | "video" | "document";

function getTypedFileObject<T extends { [k: string]: FileType }>(blueprint: T) : Record<keyof T, FileType> {
  return blueprint;
}

const obj = getTypedFileObject({
    a: "image",
    b: "video",
    c: "document",
    // d: "test" will not compile
})

Answer №2

If you're looking for assistance, this code snippet might be useful:

type FileCategory = "image" | "video" | "document";

const categorizedFiles = {
    x: "image",
    y: "video",
    z: "document"
}

type FiledTypeList = Record<keyof typeof categorizedFiles, FileCategory>

const specifiedFileTypes : FiledTypeList = {
    x: "image",
    y: "video",
    z: "document"
}

//type specifiedFiles = string
type determinedFiles = keyof typeof specifiedFileTypes; // x | y | z

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

Create a variety of URL formats for various object cases

Can you guide me on how to verify and create a URL under different circumstances? I am dealing with 3 cases that involve different types of objects: "repositories": { "toto": { "tata": "https://google.com/", ...

Tips for eliminating unnecessary module js calls in Angular 9

https://i.sstatic.net/3R7sr.png Utilizing a lazy loading module has been efficient, but encountering challenges with certain modules like all-access-pass and page not found as shown in the image above. Is there a way to effectively remove unused module J ...

What is the process for changing the value type of a function in an already existing record?

Trying to create a function that transforms the definitions of object functions into different, yet predictable, functions. For example: converter<{ foo: (n: number) => void, bar: (s: string) => void }>({ foo: fooFunction, bar: barFunc ...

Can data be filtered based on type definitions using Runtime APIs and TypeDefs?

My theory: Is it feasible to generate a guard from TypeDefs that will be present at runtime? I recall hearing that this is achievable with TS4+. Essentially, two issues; one potentially resolvable: If your API (which you can't control) provides no ...

Tips for implementing debounce functionality in mui Autocomplete

How can I debounce the onInputChange function within the MyAutocomplete component? export interface AutocompleteProps<V extends FieldValues> { onInputChange: UseAutocompleteProps<UserOrEmail, true, false, false>['onInputChange']; } ...

Guide to invoking the API prior to shutting down the browser window in Angular4

Currently, I am working on an Angular 4 application that consists of 5 components. My goal is to trigger an API call when the user closes the browser window from any one of these components. However, I have encountered an issue where the API does not get ...

Obtain the precise Discriminated conditional unions type in the iterator function with Typescript

export type FILTER_META = | { type: 'string'; key: string; filters: { id: string; label?: string }[]; } | { type: 'time'; key: string; filters: { min: string; max: string }[]; } | { ...

Is it feasible to invoke a method without any arguments on this basic subscription?

A BRIEF SUMMARY Implementing an observable in my code, I strive for maintaining cleanliness and efficiency by utilizing the detectChanges() method to update *ngIf= in the HTML. QUERY Is there a way to invoke the detectChanges() method within subscribe() ...

Combining two observables into one and returning it may cause Angular guards to malfunction

There are two important services in my Angular 11 project. One is the admin service, which checks if a user is an admin, and the other is a service responsible for fetching CVs to determine if a user has already created one. The main goal is to restrict ac ...

What is the process of assigning a value type to a generic key type of an object in typescript?

I am currently working on developing a function that can merge and sort pre-sorted arrays into one single sorted array. This function takes an array of arrays containing objects, along with a specified key for comparison purposes. It is important to ensure ...

Guide on accomplishing masking in Angular 5

I'm curious if it's achievable to design a mask in Angular 5 that appears as follows: XXX-XX-1234 Moreover, when the user interacts with the text box by clicking on it, the format should transform into: 1234121234 Appreciate your help! ...

Converting Objects to Arrays with Angular Observables

After searching extensively on SO for answers regarding item conversions in Javascript/Angular, I couldn't find a solution that addresses my specific problem. When retrieving data from Firestore as an object with potential duplicates, I need to perfor ...

Angular RxJS: The never-ending reduction

I have developed a component that contains two buttons (searchButton, lazyButton). The ngOnDestroy method is defined as follows: public ngOnDestroy() { this.unsubscribe$.next(); this.unsubscribe$.complete(); } I have created two observables from ...

The name '__DEV__' is not discoverable at the moment

While working with the mobx library in my project, I encountered an issue after installing it using npm. Upon exploring the mobx/src/error.ts file within the node_modules folder, I came across a compile time error on line 78: const errors: typeof niceError ...

Tips on configuring a segment in an Angular 6 route

Question: I am looking to configure a specific segment after the user logs in, for example http://localhost:4200/#/{dynamic name}/{dynamic name}/app/... However, I am facing an issue when navigating to /app/... across the application. Is there a way to a ...

Ways to access the values of checkboxes that are initially checked by default

Recently, I was working on a project that involved multiple checkboxes. My goal was to have the checkboxes pre-checked with values in the form (using reactive form). Users should be able to unselect the boxes as they wish and the data would be stored accor ...

Search for records in MySQL using Typeorm with the condition "column like %var%" to retrieve results containing the specified

Looking for a way to search in MySql using typeorm with the "column like" functionality. async findAll({ page, count, ...where }: CategorySelectFilter): Promise<Category[]> { return this.categoryRepository.find({ where, ...

How come the props aren't being passed from the parent to the child component? (React / TypeScript)

Learning TypeScript for the first time and facing an issue with passing props from parent to child components. The error seems to be related to the type of props, but I'm not sure how to fix it since all types seem correct. Error message: "Property ...

Issue encountered when utilizing TypeORM within NestJS: Unable to import Entity Repository

Issue with EntityRepository Import Despite having @nestjs/typeorm installed, VS Code is not recognizing the decorator I need to use. Any suggestions on how to resolve this? ...

The error message "window is not defined" is commonly encountered in Next

Having some trouble with using apexcharts in a next.js application, as it's giving me an error saying 'window is not defined'. If anyone has any insights or solutions, I would greatly appreciate the help. Any ideas on what could be causing ...