represents an Object consisting of a collection of single-parameter functions that map the entries of type R to entries of type U.
however, if U does not contain a certain key that's in R, then we will assume that it is being mapped to a single default type D.
to give you an idea, here is a flawed example: (more is covered on the flaw right after)
// here is a scenario where we want to remap game player stats from version `v1` to `v2`, // in addition to wanting to count the number of player name duplications in `NamesTallyDB`.
// a record that keeps a tally (value) of the number of occurrences of each name (key) constNamesTallyDB: Record<string, number> = {}
// some player's stats in version `v1` constmy_stats_v1 = { name:"haxxor", game:"league of fools and falafel", fame:505, tame:false, lame: ["yes", 735], }
// a collection of functions that maps each entry of a player's stats in `v1` to `v2`. conststats_v1_to_v2: RecordMapper<typeofmy_stats_v1> = { name: (s) => { // `s` is automatically inferred as a `string`, thanks to `typeof my_stats_v1` generic parameter NamesTallyDB[s] ??= 0 constrepetitions = NamesTallyDB[s]++ return [s, repetitions] }, game: (s) =>s, fame: (v) =>v * 1.5, tame: (b) =>undefined, lame: (a) => ({ current_status:a[0] === "yes" ? true : false, bad_reputation_history: [["pre-v2", a[1]], ["original-sin", 5], ] }) }
uh oh, did you notice the problem? the IDE thinks that stats_v1_to_v2 maps each entry of my_stats_v1 to unknown.
you must provide a second type parameter that specifies the new type of each entry (which in this context would be StatsV2).
conststats_v1_to_v2: RecordMapper<typeofmy_stats_v1, StatsV2> = { // just as before }
but this is a lot of repetition in typing, and the additional type will be utterly useless if it's not being used elsewhere.
luckily, with the introduction of the satisfies operator in tsc 4.9, you can be far more concise:
// a record that keeps a tally (value) of the number of occurrences of each name (key) constNamesTallyDB: Record<string, number> = {}
// some player's stats in version `v1` constmy_stats_v1 = { name:"haxxor", game:"league of fools and falafel", fame:505, tame:false, lame: ["yes", 735], }
// the map function parameters `s`, `v`, `b`, and `a` all have their types automatically inferred thanks to the `satisfies` operator. // `stats_v1_to_v2` now indeed maps the correct `stats_v2` interface, without us having to write out what that interface is. conststats_v1_to_v2: RecordMapper<typeofmy_stats_v1> = { name: (s) => { // `s` is automatically inferred as a `string`, thanks to `typeof my_stats_v1` generic parameter NamesTallyDB[s] ??= 0 constrepetitions = NamesTallyDB[s]++ return [s, repetitions] }, game: (s) =>s, fame: (v) =>v * 1.5, tame: (b) =>undefined, lame: (a) => ({ current_status:a[0] === "yes" ? true : false, bad_reputation_history: [["pre-v2", a[1]], ["original-sin", 5], ] }) } satisfiesRecordMapper<typeofmy_stats_v1>
now, for an example that uses the optional generic type parameter D (3rd parameter) for declaring the default output type:
constnow_i_know_my = { a:1, b:2, c:3, s:"nein" }
constlatin_to_greek: RecordMapper< typeofnow_i_know_my, // these are the inputs that will be mapped { s: number }, // the entry `"s"` will be mapped to a `number` string// all other entries will be mapped to `string` > = { a: (v) =>`${v}-alpha`, b: (v) =>`${v}-beta`, c: (v) =>`${v}-theta`, s: (v) =>9, }
represents an
Object
consisting of a collection of single-parameter functions that map the entries of typeR
to entries of typeU
. however, ifU
does not contain a certain key that's inR
, then we will assume that it is being mapped to a single default typeD
.to give you an idea, here is a flawed example: (more is covered on the flaw right after)
uh oh, did you notice the problem? the IDE thinks that
stats_v1_to_v2
maps each entry ofmy_stats_v1
tounknown
. you must provide a second type parameter that specifies the new type of each entry (which in this context would beStatsV2
).but this is a lot of repetition in typing, and the additional type will be utterly useless if it's not being used elsewhere. luckily, with the introduction of the
satisfies
operator intsc 4.9
, you can be far more concise:now, for an example that uses the optional generic type parameter
D
(3rd parameter) for declaring the default output type: