I think I have run into a similar issue. I wrote a lexer in Typescript. It is table-based, as is the parser that runs after it. The type for the table looks something like this:
type TokenTable<T> = {
plus: T,
minus: T,
bang: T,
parenOpen: T,
//etc.
};
I also have a type defined as 'type TokenID = keyof TokenTable<unknown>;' this makes it possible to check if a string is a valid key at compile-time. The innermost loop of the lexer is a for..in loop. This gives you the keys of the object. One problem: if you try to apply the TokenID type to the loop variable, you get this message: "The left-hand side of a 'for...in' statement cannot use a type annotation." Because of the design of JavaScript, TS cannot give object keys any other type but 'string', even though this type seems like a clear match.
To get the typechecking back on the keys, you either need to declare the loop variable outside of the loop itself, or use type casting like this:
let token = "";
let id: TokenID | undefined;
for (let key in patterns) {
const match = patterns[key as TokenID].exec(substring);
if (match && (match[0].length > token.length || key == "EOF")) {
token = match[0];
id = key as TokenID;
}
}
Neither is particularly clean.
To get the typechecking back on the keys, you either need to declare the loop variable outside of the loop itself, or use type casting like this:
Neither is particularly clean.