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?
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.
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.
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 ).
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.
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.
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.
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.
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.
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
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With