Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a const object that conforms to a specific type in Typescript

Tags:

typescript

I am searching for a better solution of the following... I need to do this:

const FRUIT_PROPERTIES = {
   "apple": { color: "red" },
   "banana": { color: "yellow" }
} as const

const myFavoriteFruitColor = FRUIT_PROPERTIES.apple.color

That is fine and dandy, but I also want the FRUIT_PROPERTIES object to conform to a type like this:

type FruitEnum = Record<string, { color: string }>

const FRUIT_PROPERTIES: FruitEnum = {
   "apple": { color: "red" },
   "banana": { color: "yellow" }
} as const

But this way I am loosing the original inferred type and autocompletion of the "apple" and "banana" keys.

So I have solved this by doing the following

type FruitEnum = Record<string, { color: string }>;

const validateFruitEnum = <TParam extends FruitEnum>(param: TParam) => {
   return param;
};

const FRUIT_PROPERTIES = validateFruitEnum({
   apple: { color: 'red' },
   banana: { color: 'yellow' },
} as const)

This way I retain the original type...

But I was wondering if there is some better way of doing this? Does anybody have any better solution?

like image 970
ToothlessFury Avatar asked Aug 10 '21 12:08

ToothlessFury


People also ask

How to create an object of a type in TypeScript?

To create an object based on an interface, declare the object's type to be the interface, e.g. const obj1: Employee = {} . The object has to conform to the property names and the type of the values in the interface, otherwise the type checker throws an error.

How to create an object using interface in TypeScript?

TypeScript allows you to specifically type an object using an interface that can be reused by multiple objects. To create an interface, use the interface keyword followed by the interface name and the typed object.

What is as const TypeScript?

When using as const in TypeScript, we are able to set the properties of an object or the elements of an array to readonly , indicating to the language, that the type in the expression will not be widened (e.g. from 42 to number ).

When should I use TypeScript?

Use the as Keyword in Type Predicates in TypeScriptType predicates are used as type guards on untyped objects or objects with weak types, such as the union of two or more types. The animal is Dog is used as a type predicate.

What is const in typescript?

Type Inference Typescript constants are variables, whose values cannot be modified. We declare them using the keyword const. They are block-scoped just like the let keyword.

How to create custom types for object shapes in typescript?

In this section, you are going create types that can be used to describe any object shape you need to use in your code. In TypeScript, the syntax for creating custom types is to use the type keyword followed by the type name and then an assignment to a {} block with the type properties.

How to use type parameters in generic constraints in typescript?

Using type parameters in generic constraints TypeScript allows you to declare a type parameter constrained by another type parameter. The following prop () function accepts an object and a property name. It returns the value of the property.

Why does typescript not work with objects only?

TypeScript doesn’t issue any error. Instead of working with all types, you may want to add a constraint to the merge () function so that it works with objects only. To do this, you need to list out the requirement as a constraint on what U and V types can be.


Video Answer


2 Answers

It is also possible to infer literal type without using as const assertion:


const validateFruitEnum = <
  Color extends string,
  Value extends { color: Color },
  Prop extends string,
  Obj extends Record<Prop, Value>
>(param: Obj) => param

const FRUIT_PROPERTIES = validateFruitEnum({
  apple: { color: 'red' },
  banana: { color: 'yellow' },
})

FRUIT_PROPERTIES.apple.color  // red

Playground

Using explicit type disables as const assertion. For instance string[] as const can't give you literal type as well as const a:string[]=['a','b'] as const

like image 72
captain-yossarian Avatar answered Nov 15 '22 05:11

captain-yossarian


You need a source of truth for the fruit types. So here is what I would do instead of using the validateFruitEnum function, although not exactly what you were looking for:

Define a fruits enum before and use that:

const FruitEnum = {
  apple: "apple",
  banana: "banana",
} as const;

type FruitToColorMap = Record<keyof typeof FruitEnum, { color: string }>

const FRUIT_PROPERTIES: FruitToColorMap = {
   "apple": { color: "red" },
   "banana": { color: "yellow" }
};

link: playground

like image 28
deckele Avatar answered Nov 15 '22 05:11

deckele