Welcome back! Let's go back on track after bonus questions. This question will be less abstract, and more practical, we will land more at value level 🚁.
We have a function concatToField
which takes object, and key of this object, and string value. The purpose of this function is to create a new object with concatenated property object[key] with third argument.
The question - How to type generic types T
and K
in the definition of concatToField
function in order to achieve compile time guarantee that obj[key]
can be only string
.
const concatToField =
<T /* here your code 💪*/, K /* here your code 💪*/>(obj: T, key: K, payload: string): T => {
const prop = obj[key]; // compile error should not be here
return { ...obj, [key]: prop.concat(payload) }; // compile error should not be here
}
// tests
const test = { fieldStr: 'text', fieldNum: 1, fieldStr2: 'text' };
concatToField(test, 'fieldStr', 'test'); // should be ok 👌
concatToField(test, 'fieldNum', 'test'); // should be error fieldNum is not string field 🛑
concatToField(test, 'notExistingField', 'test'); // should be error - no such field 🛑
concatToField(test, 'fieldStr2', 'test'); // should be ok 👌
Full code available in the playground
Important - body of the function should remain unchanged, no type assertion (as), or any changes of the body are allowed. The only thing needs to be done is constraint on T
and K
generic types.
Post your answers in comments (preferred links to the playground). Have fun! Answer will be published soon!
This series will continue. If you want to know about new exciting questions from advanced TypeScript please follow me on dev.to and twitter.
Top comments (5)
Cool challenge.
Explanation:
Pretty straight forward. The test object is a map of
string
keys to any values, though of course, if those values are strings, then we want to be able to apply theconcatToField
method to it.I'll break this into two parts
By itself, this is just saying 'the value of K is going to be one of the keys of that T object'.
We're saying that 'is the value at
T[K]
of type string? If so, then the type of K is string, if not, then the type of K isnever
'.The
never
type allows us to return compile errors when something is illogical/not allowed - in this case it is not allowed to to have aT[K]
value that is not of type string.Note:
It would be nice if we could just do
instead of using that ternary - but this apparently is not valid typescript.
Hi David thank you for the answer.
But your code doesn't make errors when it should, so there are no compile time guarantees. I put in the snippet two places where the error should occur, you see there 🛑 icon. Even more the code you have provided compiles for any second argument like
concatToField(test, 'anything', 'test');
.So try again! And good luck.
Ah, was just missing some brackets. :/
Playground
What about:
?