In Part 1 of this series we developed an API for searching and sorting HTML tables. We introduced some code reuse in Part 2 but ended up with a lot of boilerplate and fell short in our efforts to address the problem. In this post we discover a feature of TypeScript that offers hope.
Some days later Patrick says:
“Hey, Gordon, I found something. Check this out.”
What’s this? What does
K extends keyof T mean1?
But in TypeScript, while
firstName is a string, it is also a type. Because
Person has a field called
firstName, the string
firstName matches a type called
keyof Person. If you inspect
keyof Person you get a union type consisting of all field names in
Yields a compile error:
How great is that? Sold! Now we can update the TableSort API
Recalling the search API, while we’re at it we can lose the
FieldExtractor and write a new predicate leveraging the
keyof T type
Then users can write code like this to set up the table
And an IDE can offer code completion
Whoops. Code completion just ruined our day.
The astute reader will recognize that
age is a number field, yet code completion offers it as an option where a string field is expected. We want this for
textPredicate; all fields values will be converted to strings for the text search. But
tableSort.addString() should clearly reject the addition of
age to its list.
To illustrate the problem, consider how these types resolve
And this code
This definition permits calling
addString('age') but it *should* be an error because
Person['age'] is a number. We need to distinguish between string fields and number fields with something like
Two types for which we can write two type-safe functions. One could imagine these additions to the
Surely that’s too much to ask of the type system. On the other hand, the utility of
keyof seems starkly limited if these additional constraints can’t be applied. What does TypeScript have to say about all this? Find out in the final post of this series.