Reputation: 38
Here I want to define the type for object value only. In order to get types for keys. Is there any way to get without defining types for each value.
const sizes: Record<string, CSSObject>= {
md: {
padding: [10, 24],
fontSize: 'medium',
},
xs: {
padding: [6, 12],
fontSize: 'small',
},
sm: {
padding: [8, 16],
fontSize: 'small',
},
lg: {
padding: [14, 30],
fontSize: 'large',
},
} as const;
// Expecting 'md' | 'xs' | 'sm' | 'lg'
type Sizes = keyof typeof sizes;
// But it is string
Upvotes: 0
Views: 390
Reputation: 21
Just wanted to add on to @kaya3's very helpful answer:
The helper
function here works specifically with CSSObject
. I needed to use this helper on multiple objects with different value types, so I wrote a version that lets you pass in any type:
function constrainValuesAndInferKeys<V>() {
return function <K extends PropertyKey>(obj: Record<K, V>) {
return obj;
}
}
const sizes = constrainValuesAndInferKeys<CSSProperties>()({
md: {
padding: [10, 24],
fontSize: 'medium',
},
// ...
});
type Sizes = keyof typeof sizes;
// 'md' | 'xs' | 'sm' | 'lg'
The downside is you have to add that extra ()
in constrainValuesAndInferKeys<CSSProperties>()({
.
Upvotes: 0
Reputation: 51037
As I understand it, you want to infer the keys 'md' | 'xs' | 'sm' | 'lg'
from the object's actual properties, but you also want the type-checker to make sure that the properties' values are of type CSSObject
.
The problem is that you would need a type annotation on the object literal to check the values are CSSObject
; but if you use a type annotation then keyof ...
will get the keys from the annotated type, not the object itself.
The way around this is to use a generic helper function, so that the record's key type is inferred while the value type is specified:
function helper<K extends PropertyKey>(obj: Record<K, CSSObject>): Record<K, CSSObject> {
return obj;
}
const sizes = helper({
md: {
padding: [10, 24],
fontSize: 'medium',
},
// ...
});
type Sizes = keyof typeof sizes;
// 'md' | 'xs' | 'sm' | 'lg'
Upvotes: 2