Ability to specify Map/Record key types/formats/patterns
I had asked for advice in this discussion #1626 and got pointed to creating an issue.
If you use
alias MyMap = Record<int32>;
You can't say anything about the keys. They are just string as far as I can tell.
I wanted to be able to put something like @pattern("[a-f0-9]{10}") on my keys.
Could also imagine: @format("uuid")
Hope that is detailed enough.
@markcowl: look for existing issue
Things to think about if we want to provide similar functionality to TypeScript here. If we were to have the key be a string template we could use it so the type system knows what are the values for those types of keys and combine that with other constraint.
Example of what I mean in typescript https://www.typescriptlang.org/play?#code/C4TwDgpgBASgcgVwLZQLywgYwPYCcAmAPAAYAeAtAHbLkAkA3gM7C4CWlA5gL7EA0U1JACMIuAHwBuALAAoUJFgBlFuw5oMOAiQrNcdJis49+u1ZNmz50AGLZs6+MigAyJYY7SZsnJWZQAhgBcULb26PSyUFFQAEQUguT+McEAjLyR0XFUNELJsbox6TLRsTos5Jh5MQVFJVm65Ph5ACxFXEA
Example use case we could see in TypeSpec
(I used Record<K, V> to show the example but this is most likely not going to be the type as this would be significantly breaking.)
alias C1 = Record<string, string>; // every property is a string
alias C2 = Record<string, int32>; // every property is a int32
model C3 is Record<string, int64> { // all properties are int64 but name is int32 - works because int32 is subtype of int64
name: int32
}
alias C4 = Record<string, int64> & {name: int32}; // all properties are int64 but name is int32 - works because int32 is subtype of int64
model C5 { // All properties are int64 but name is string
name: string;
...Record<string, int64>
}
model C5 { // name is string and can have extra properties of type int64 or boolean
name: string;
...Record<string, int64>
...Record<string, boolean>
}
// Here we are saying that all starting with int64- are int64 and all starting with boolean- are boolean
alias C6 = Record<"int64-${string}", int64> & Record<"boolean-${string}", boolean> & {name: string};
model C7 { // name is a string then there is extra properties that start with int64-(int64) and boolean-(boolean
name: string;
...Record<"int64-${string}", int64>;
....Record<"boolean-${string}", boolean>
}
model C8 { // name is a string then there is extra properties that start with int64-(int64 or object) and boolean-(boolean
name: string;
...Record<"int64-${string}", int64>;
...Record<"int64-${string}", object>;
....Record<"boolean-${string}", boolean>
}
I think it might be possible to do it in a non breaking maner
https://typespec.io/playground?c=QGluZGV4ZXIoSywgVikKbW9kZWwgUmVjb3JkS2V5ZWQ8xBggPSBLPiB7fQrHIFRlc3QgewogIGxlZ2FjeTE6zTJzdHJpbmc%2BO8kgMs4gaW50MzLFH25ld9U8LCDLRG5ld89ByCXNSTPOJCJ4LSR7xil9IsorfQo%3D&e=%40typespec%2Fopenapi3&options=%7B%7D
it just means we can't have a constraint valueof string on the key and this might need to be done manually in the decorator.
This doesn't cover custom types so bring back a Map type would be better.
@mapConfig(K, V)
scalar Map<K, V>;
Sefaria uses a pattern where the responses to some bulk queries are records, where the objects are keyed by the query parameters. (Here is a simplified Playground example.) In such a case, it would be really nice to be able to specify that the Record is keyed by the type of the source parameter.
I think it's acceptable to require the key type to be a valueof string - after all, For JSON, that's what's supported. (One could argue it's TypeScript's job to support serialization of fancy models, not TypeSpec's.)
cc @markcowl