Create a custom data type that consists of a specific set of keys from an object

Is there a way to create a type in TypeScript that includes only a subset of keys from an object? Consider the example object below:

const something = {
  cannary: "yellow",
  coyote: "brown",
  fox: "red",
  roses: "white",
  tulipan: "purple",
  palmera: "green"
}

If I define a type like this:

type Something = keyof typeof something

Autocomplete and type checking will work for all keys, but what if I want to restrict it to only certain keys like:

type Animal = keyof typeof {only cannary|coyote|fox} 

Is this possible to achieve in TypeScript?

Answer №1

The Extract<T, U> type built into the system is a great option for this situation. It will...

Pull out the types from T that can be assigned to U

However, in your specific scenario, this still permits

Extract<keyof typeof something, 'cannary' | 'coyote' | 'monkey'>

to go through, even though 'monkey' is not present in T.

A slight adjustment to the Extract<T, U> type from:

type Extract<T, U> = T extends U ? T : never;

to

type ExtractExact<T, U extends T> = T extends U ? T : never;

requires the user to specify a type for U that must be an extension of T.

Now:

type CausesTypeError = ExtractExact<keyof typeof something, 'cannary' | 'coyote' | 'monkey'>

would immediately point out any unintended issues in the IDE:

https://i.stack.imgur.com/kPy5o.png

Playground Link

Answer №2

According to @spender, the Extract function is designed to retrieve specific members from a set and can be utilized to fulfill your requirements.

An alternative option is to utilize the Pick method.

type AnimalsPicked = keyof Pick<typeof something, 'cannary' | 'coyote' | 'monkey'>
type AnimalsExtracted = Extract<keyof typeof something, 'cannary' | 'coyote' | 'monkey'>

The outcome remains the same.

If you require the object type in between:

type AnimalsObj = Pick<typeof something, 'cannary' | 'coyote' | 'monkey'>

Given that the broader issue you are attempting to address has not been provided, the following suggestions may or may not be relevant.

const something = {
  cannary: "yellow",
  coyote: "brown",
  fox: "red",
  roses: "white",
  tulipan: "purple",
  palmera: "green"
} as const;
const animals = (()=>{
   const {cannary,coyote,fox} = something;
   return {cannary,coyote,fox};
})();
// The UI displays:
// const animals: {
//   cannary: "yellow";
//   coyote: "brown";
//   fox: "red";
// }

Visit the playground for a demo.

Answer №3

You should consider utilizing the Pick<T> utility type

https://www.typescriptlang.org/docs/handbook/utility-types.html#picktype-keys

const items = {
  apple: 'red',
  banana: 'yellow',
  grape: 'purple',
  kiwi: 'green',
};

// type ItemsType = "apple" | "banana" | "grape" | "kiwi"
type ItemsType = keyof typeof items;

// type Fruits = "apple" | "banana" | "grape"
type Fruits = keyof Pick<typeof items, 'apple' | 'banana' | 'grape'>;

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

How can I set up Prettier to exclude a line following a specific pattern?

Is there a method to configure Prettier in Visual Studio Code to exclude lines following a specific pattern? Sometimes, I require a directive like /**@ts-ignore */ followed by a lengthy line. However, when Prettier formats the code, it introduces new line ...

I am currently experiencing a problem with deleting documents in Firebase Firestore using React, Typescript, and Redux. Despite the code running, the document continues to exist in

I seem to be encountering an issue that I can't quite figure out. Despite my code running smoothly, I am unable to delete a document from Firestore. The document ID definitely exists within the database, and there are no subcollections attached to it ...

Resolving search box setup problem in PrimeNG dataView

I am working on integrating p-dataView with Angular 5 but encountering an error Cannot read property 'split' of undefined at DataView.filter Despite checking the documentation, I have been unable to find a solution to this issue. It seems lik ...

The Angular Observable continues to show an array instead of a single string value

The project I am working on is a bit disorganized, so I will try to explain it as simply as possible. For context, the technologies being used include Angular, Spring, and Maven. However, I believe the only relevant part is Angular. My goal is to make a c ...

Currently focused on developing vertical sliders that can be manipulated by dragging them up or down independently

https://i.stack.imgur.com/NgOKs.jpg# I am currently working on vertical sliders that require dragging up and down individually. However, when I pull on the first slider, all sliders move together. The resetAllSliders button should also work independently, ...

What improvements can I implement in this React Component to enhance its efficiency?

Seeking advice on improving the efficiency of this React Component. I suspect there is code repetition in the onIncrement function that could be refactored for better optimization. Note that the maxValue prop is optional. ButtonStepper.tsx: // Definition ...

What is the best way to implement a comprehensive switch case in Typescript using string enums that are referencing other string enums?

I am faced with a challenge where I have a subset of values from one enum that I need to switch case across in TypeScript. Here's an example to illustrate my dilemma: const enum Fruit { APPLE = 'Apple', BANANA = 'Banana', ...

Discover the process of changing a prop with a button click in NextJS

In my NextJs project, I have a video player component that displays videos using a {videoLink} prop: <ReactPlayer playing={true} controls={true} muted={true} loop={true} width="100" height="100" url={videoLinkDeep} poster="ima ...

Constructor not executing when using Object.create

Attempting to instantiate a class within a static method, I am using Object.create(this.prototype), which appears to be functioning correctly. Nonetheless, when I check the console, my property items is showing as undefined. The base class called model lo ...

Separate the date format string into tokens

I am currently attempting to create a function that is able to transform a date format string such as %d/%m/%Y %H:%n where the variables are always denoted by a percentage sign followed by one character, into an array of tokens: ["%d", "/", "%m", "/", " ...

The properties are not found in the type 'Observable<Todo[]>'

I'm currently following a YouTube tutorial and I've hit a roadblock trying to figure out where the error is originating from? Error Message: Type 'Observable' is missing properties such as length, pop, push, concat, and 25 more.ts(2740 ...

Is it possible to pass a different variable during the mouse down event when using Konva for 2D drawing?

I am trying to pass an additional value in a mouse event because my handleMouseDown function is located in another file. stage.on('mousedown', handleMouseDown(evt, stage)) Unfortunately, I encountered an error: - Argument of type 'void&apos ...

What is the best way to add a service to a view component?

I am facing an issue with my layout component where I am trying to inject a service, but it is coming up as undefined in my code snippet below: import {BaseLayout, LogEvent, Layout} from "ts-log-debug"; import {formatLogData} from "@tsed/common/node_modul ...

Navigating dropdown list items using the keyboard in TypeScript is a breeze

I've encountered a bug while working on my open-source project. The issue is with navigating the dropdown list items using the keyboard (arrow key/tab). I have implemented the keyboard-navigation logic, but I'm unsure of how to make it work corre ...

What are the steps to effectively troubleshoot TypeScript code in Visual Studio 2017?

Currently working on an ASP.NET Core project that heavily utilizes TypeScript. Does Visual Studio support debugging TypeScript code? ...

How can Jest be configured to test for the "permission denied" error?

In my Jest test, I am testing the behavior when trying to start a node http server with an invalid path for the socket file: describe('On any platform', (): void => { it('throws an error when trying to start with an invalid socket P ...

Tips for resolving Typescript type error when overriding MuiContainer classes

My application is divided into two main files: (https://codesandbox.io/s/react-ts-muicontainer-override-yywh2) //index.tsx import * as React from "react"; import { render } from "react-dom"; import { MuiThemeProvider } from "@material-ui/core/styles"; imp ...

Angular: Refresh mat-table with updated data array after applying filter

I have implemented a filter function in my Angular project to display only specific data in a mat-table based on the filter criteria. Within my mat-table, I am providing an array of objects to populate the table. The filtering function I have created loo ...

"Create a separate function for the pipeable operator in RXJS for enhanced code

After working on some code, I came up with the following implementation this.form.valueChanges.pipe( take(1), map(val => // doSomething), exhaustMap(val => // someInner observable logic return of({someValue}) ) ).subscrib ...

Updating the DOM after making changes with Maquette involves calling the `renderMaquette

In a previous discussion, I expressed my desire to utilize Maquette as a foundational hyperscript language. Consequently, avoiding the use of maquette.projector is essential for me. However, despite successfully appending SVG objects created with Maquette ...