Reputation: 411
Need to declare a object type. Getting below mentioned error:
type CarKeys = "mercedes" | "mercedes-sedan" | "mercedes-hatch";
interface Car { color: string; }
const KEY_MAP = { mercedes: 'mercedes', mercedes_sedan: 'mercedes-sedan', mercedes_hatch: 'mercedes-hatch'};
const carType:Record<CarKeys, Car> = {
[KEY_MAP.mercedes]:{ color: 'red'},
[KEY_MAP.mercedes_sedan]: {color: 'yellow'},
[KEY_MAP.mercedes_hatch]: {color: 'black'}
};
TypeScript is throwing following error :
Type'{[x: string]: { color: string }}' is missing the following properties from type 'Record': mercedes, mercedes-sedan, mercedes-hatch`
Upvotes: 4
Views: 2462
Reputation: 20162
First of all when using TypeScript you don't need to use Key -> Value map + String literal types. You can choose one of both, as it will ensure the type safety. Also approach with using Enum instead of standard JS object will be more appropriate as it will solve and the value and the type in one language construct. Consider the solution with using Enum only:
interface Car { color: string; }
enum KEY_MAP {
mercedes = 'mercedes',
mercedes_sedan = 'mercedes_sedan',
mercedes_hatch = 'mercedes_hatch'
}
const carType: Record<KEY_MAP, Car> = {
[KEY_MAP.mercedes]:{ color: 'red'},
[KEY_MAP.mercedes_sedan]: {color: 'yellow'},
[KEY_MAP.mercedes_hatch]: {color: 'black'}
}
Also solution with only string literal is fully valid and type safe. Consider:
type CarKeys = "mercedes" | "mercedes_sedan" | "mercedes_hatch";
interface Car { color: string; }
const carType: Record<CarKeys, Car> = {
mercedes:{ color: 'red'},
mercedes_sedan: {color: 'yellow'},
mercedes_hatch: {color: 'black'}
} // carType cannot be created with wrong key or value type
String literal type should not be considered as 'magic string' as it is watched by compiler and type safe. We don't need to create some middle structure to use it directly.
And last not least. You can fix your implementation directly by specifing correct type for KEY_MAP.
type CarKeys = "mercedes" | "mercedes_sedan" | "mercedes_hatch";
interface Car { color: string; }
const KEY_MAP: { [P in CarKeys]: P } = { mercedes: 'mercedes', mercedes_sedan: 'mercedes_sedan', mercedes_hatch: 'mercedes_hatch'};
const carType:Record<CarKeys, Car> = {
[KEY_MAP.mercedes]:{ color: 'red'},
[KEY_MAP.mercedes_sedan]: {color: 'yellow'},
[KEY_MAP.mercedes_hatch]: {color: 'black'}
}; // no issues
The core thing is { [P in CarKeys]: P }
. We are saying that our object has exact single item from CarKeys
as a key and as a value.
Upvotes: 3
Reputation: 185445
There is an error in your code, the values in KEY_MAP
do not actually match the values specified in CarKeys
. Also, the semi-colons in carType
need to be commas.
To fix the problem at hand you can use as const
. In your code the resolved type of KEY_MAP
is:
const KEY_MAP: {
mercedes: string;
mercedes_sedan: string;
mercedes_hatch: string;
}
Specify it like this:
const KEY_MAP = {
mercedes: 'mercedes',
mercedes_sedan: 'mercedes_sedan',
mercedes_hatch: 'mercedes_hatch'
} as const;
Then the resolved type will be:
const KEY_MAP: {
readonly mercedes: "mercedes";
readonly mercedes_sedan: "mercedes_sedan";
readonly mercedes_hatch: "mercedes_hatch";
}
Which should compile.
Upvotes: 3
Reputation: 19997
Two things, first you wrote type CarKeys = "mercedes" | "mercedes_sedan" | "mercedes_hatch"
, all with underscore but values in KEY_MAP
have hyphen, that's a mismatch you might want to fix.
Second, by default TS will infer typeof KEY_MAP
to be { mercedes: string; ... }
instead of { mercedes: "mercedes", ... }
.
This means typeof [KEY_MAP.mercedes]
is actually string
, not the "mercedes"
string literal, thus typeof carType
is actually { [key: string]: Car }
, that's why the error.
To fix it, you can add as const
to the end of KEY_MAP
:
const KEY_MAP = {
mercedes: 'mercedes',
mercedes_sedan: 'mercedes-sedan',
mercedes_hatch: 'mercedes-hatch'
} as const;
Or, you can turn it to a enum
enum KEY_MAP {
mercedes = 'mercedes',
mercedes_sedan = 'mercedes-sedan',
mercedes_hatch ='mercedes-hatch'
}
Upvotes: 5