I am trying to create a generic type check function that checks if an object's property has a type. But it would be nice if I didn't need to define the field as both an argument value and type value.
For example, this works but feels a bit redundant:
function isFieldPopulated<T1, T2, K extends keyof T1>(doc: T1, field: K): doc is Omit<T1, K> & Record<K, T2> {
// check if T1[K] is a T2
return ...;
}
if (isFieldPopulated<Post, Category, 'category'>(data, 'category')) {
// data.category is a Category type
}
I was hoping not to have to set 'category' here <Post, Category, 'category'>
AND here (data, 'category')
. Is there a way for TS to know that the field
argument extends keyof T1 without having to specifically put 'category' inside <..., 'category'>
since it's already being passed through as a string argument?
UPDATE: Here is a minimal working example.
CodePudding user response:
Because TypeScript can already infer T1
and K
correctly for us, there should be no need to explicitly provide T2
. It seems that you want only the object types and not primitives (like string
), so we can give T2
the type Extract<T1[K], object>
, giving us all the object types in T1[K]
:
function isFieldPopulated<T1, T2 extends Extract<T1[K], object>, K extends keyof T1>(doc: T1, field: K): doc is T1 & Record<K, T2> {
You can verify that it works here.