Home > Net >  Define a type with a subset of an object keys
Define a type with a subset of an object keys

Time:04-26

I wonder how to create a type that has only a subset of keys from an object, imagine the following object:

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

If I defined a type like:

type Something = keyof typeof something

Autocomplete and the check type will work for all the keys, but what about if I want to accept only some of those keys like:

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

is this feasible to do in typescript?

CodePudding user response:

The built-in Extract<T, U> type is a good candidate for this. It will...

Extract from T those types that are assignable to U

However, in your case, this still allows

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

to pass, even though 'monkey' does not exist in T.

A small modification 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;

forces the consumer to supply a type for U that must extend T.

Now:

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

will show up immediately in the IDE as something unintended:

enter image description here

Playground Link

CodePudding user response:

As @spender pointed out, Extract will "extract" members from a set, and can be used to meet your request.

You can also use Pick

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

Same result.

If you want the intermediate object type

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

Because you haven't actually described the larger problem you trying to solve, the following might or might not be helpful.

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};
})();
// UI shows
// const animals: {
//   cannary: "yellow";
//   coyote: "brown";
//   fox: "red";
// }

playground

CodePudding user response:

You can use Pick<T> utility type

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

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

// type Something = "cannary" | "coyote" | "fox" | "roses" | "tulipan" | "palmera"
type Something = keyof typeof something;

// type Animal = "cannary" | "coyote" | "fox"
type Animal = keyof Pick<typeof something, 'cannary' | 'coyote' | 'fox'>;
  • Related