6 ms·
Do you have an example for what you want to do, with an object before and after mapping? I don't understand what you mean by "functionally map over a typed obje
by cuddlecake 4y ago
Do you have an example for what you want to do, with an object before and after mapping? I don't understand what you mean by "functionally map over a typed object by key"
- shadowofneptune 4y agoI 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.
- lozenge 4y agoCan you define a const array with type Array<TokenId> and use it every time you want to loop through these keys?
- shadowofneptune 4y agoThat's a possibility, yes. This is the only time in the program that a token table is iterated through, however. Most of the time a table is consulted to pursue an action in the parser. For example, there's a function table for when a statement is encountered, another for when an expression operand is encountered, etc. Each entry in the table is either an error message or code which completes the parsing of that statement. The awkwardness above is excusable when it is encountered so little. When writing expression-heavy stuff like 'Object.keys(typedObjName).map(...)' it's more of a problem.
- gnud 4y agoYou can approximate something by defining the valid TokenTable keys as an enum, and using a mapped type for the actual TokenTable type. There's some boilerplate in the definition, but it's fairly clean and non-repetitive. And easy to use in the "client code". https://www.typescriptlang.org/play?#code/KYOwrgtgBAKg9ga1ASQCJQN4Cgq6gBwBswBnKAXigHIjSqAaHPCAS3DMqtfYadwCMAhiADmFakNG88BQQCdQAeXyhxNeUpUgqWAL5YALgE8VsRKBiD+hYAB4YAPnHYZAbQRQ2ZpCDQBdAC5YPSwAelCoAGFBAGMAC2AoADM4OSgDBPSTRJEweQATLBi4EBIDKAB9eB80DlxFfgArYBiDADokIxIACmqUVABKLCSwEFaWEs8SPt987s6gsrk2EQGoIM6p737MPigFAzA5EEqZ2ra2GOJ84B7Oof1wqG7jFXy1whYyqDgkqEFCIQoAA3AEsfLpcwnZD5EhFErfACCgLOsPEVSh5ySLEIBmAcm6X1RQywWBs5XwggMeOOZCCM0s1jsACVgCIAKIAD3wTkoLjwtBIQVCAB0ANShRgybikYUigC0kr2khEcoAhEqZJSFCBlKA5d1QiEycBygYoeIAESWgDcJvK4PpmPQAB8oKMbtiQMB8nb7VASGB+EsVla1ZbSU8AKokRIZRKfb6-KCdOEpNLdYqlcqbZPIwiokhrfm4LPfCBU+LiSnU-GldzAIx+NrATktbqB4MGZaiAY2qB7FhJboVgzxYt7GRluA2NqEOAieaNoYyfT6MIRRRyeieP5GOBgKgKKAgODlQPHgFA1P-Y-4BSxkAGHekRKCKC5ArDVLPMs5xueCcNY0qUE4yEOhLTJicz3GBMh4H+UCjlWlDAXWJANk2LZtjEHZBiGvb9pOeAQchcRwfB8HTrO86LvcxG4Poq56EAA https://www.typescriptlang.org/play?#code/KYOwrgtgBAKg9ga1AS...
- shadowofneptune 4y agoYou put some real effort into the example. It's the opposite approach of how I did it, yet works just as well. Thanks!
- cuddlecake 4y agoYou can also write the array first, without using enum: const tokens = ['parenOpen', 'bang', 'plus', 'minus'] as const; type Token = typeof tokens[number]; type TokenTable<T> = Record<Token, T> // alias for { [key in Token]: T } const isToken = (t: string): t is Token => tokens.includes(t); const patterns: TokenTable<RegExp> = { bang: /\+/, // rest }
- ryanmcbride 4y agoI can't really think of like, a practical use case but here's a jsFiddle of what I mean. https://jsfiddle.net/knvztxq7/ https://jsfiddle.net/knvztxq7/ ^ that code will work, it outputs the key names to the console https://jsfiddle.net/knvztxq7/1/ https://jsfiddle.net/knvztxq7/1/ ^ that code... is also working even though I swear it hasn't worked for me before so now I think I'm actually just losing my mind. Yeah wow I can't reproduce my error now... I'll come back here if I figure out what I did.