I'm hitting this wall since days now and I'm not sure anymore if I'm the problem or if typescript is broken...
I defined a generic class with the generic extending Record<string, string>
:
class DbTable<ColumnDefinitions extends Record<string, string>> { /* ... */ }
At a later point I want to use the exact keys (e.g. 'id' | 'name'
instead of just string
), so I use the keyof
operator on the generic, like this:
function selectFields(fields: (keyof ColumnDefinitions)[]) { /* ... * / }
But keyof ColumnDefinitions
resolves to string | number | symbol
instead of just being of type string
.
What did I miss?!
Here is a TS playground link with an example.
CodePudding user response:
To my understanding, the built-in generic Record<T>
adds on the symbol and number type. If you think about what happens in Javascript, which is what typescript compiles to, this makes sense, because you can index with number, string, or symbols.
Ex:
const map = {0: "hello"}
//both are valid
map[0]
map["0"]
A simple type check to ensure fieldNames is equal to string should resolve your problem at the end of your sandbox.
fields: fields.map(fieldName => {
if(typeof fieldName === "string") return new DbField(fieldName)
else return {}
}
Or you can do the following to ensure conversion into string:
fields: fields.map(fieldName => new DbField(fieldName.toString())
CodePudding user response:
You can extract only strings from string | number | symbol
in the method signature.
Instead of
fields: (keyof T)[]
you can write
fields: (Extract<keyof T, string>)[]
and the error goes away.