In my typescript program (code below) I define two base types (Player, State) and then a few nested Record types used as mappings.
I then in a typed function create an instance of one of these records based on an existing instance of the nested record.
type Player = "1" | "2";
type State = "A" | "B" | "C";
type StateMapping = Record<State, State>;
type PlayerStateMappings = Record<Player, StateMapping>
type PlayerStates = Record<Player, State>;
const playerStateMappings: PlayerStateMappings = {
"1": {
"A": "B",
"B": "C",
"C": "A"
},
"2": {
"C": "B",
"B": "A",
"A": "C"
},
}
function nextStates(currentState: State): PlayerStates {
var nextStates = {};
for(const player of Object.keys(playerStateMappings)){
nextStates[player] = playerStateMappings[player][currentState]
}
return nextStates;
}
console.log(nextStates("A"))
This code throws the following type error at the return statement, since I created the object without the required keys and only added those afterwards:
TS2739: Type '{}' is missing the following properties from type 'PlayerStates': 1, 2.
My question is if there is a way to avoid this type error that fulfils the following requirements:
- The typesystem is not relaxed in particular it still enforces that the
nextStatesfunction returns a complete and validPlayerStatesobject. - The
nextStatesobject is created programatically based on the keys of theplayerStatesMappingobject, meaning I don't have to hardcode all of the players again.
After some research on SO I found a few options that avoid the error but all of which violate one of the two requirements mentioned above:
Approaches that violate condition 1:
- Make the PlayerStates type partial:
type PlayerStates = Partial<Record<Player, State>>; - Enforce type using
askeyword:var nextStates = {} as PlayerStates; (from this question)
Approaches that violate condition 2:
- Set a default value for each Player in the object creation:
var nextStates = {"1": "A", "2": "B"}
I know that the whole typing is a bit of an overkill in the above example but this is a highly simplified / reduced version of the problem that I encountered in a more complex project where above requirements / expectations make more sense.
PS: Coming from a python background I guess I am looking for something like a dict comprehension that allows me to initialize a new dictionary based on some iteration.
PlayerStatesRecord. For example the following code would typecheck: ``` function nextStates(currentState: State): PlayerStates { var nextStates = {} as PlayerStates; return nextStates; } ```