Reputation: 7178
For student.ts
type Student = {
name: string,
marks: string[],
subjects: string[]
}
How to get ArrayKey<Student>
such that it return only keys which points to any array, here it should point to 'marks'|'subjects'
My try
type ArrayKey<T, Key extends keyof T = keyof T> = T[Key] extends any[] ? Key : never;
let c: ArrayKey<Student> = 'marks';
but it throws error [ts] Type '"marks"' is not assignable to type 'never'
Upvotes: 1
Views: 33
Reputation: 330466
You're close, but your code requires the developer to specify Key
, which is what you're trying to output. You can instead use mapped types to iterate over the keys of T
and then use your conditional type to identify the ones with array-valued properties. Like this:
type ArrayKey<T> = { [Key in keyof T]: T[Key] extends any[] ? Key : never }[keyof T];
type Student = {
name: string,
marks: string[],
subjects: string[]
}
let c: ArrayKey<Student> = 'marks'; // okay
Another way to do it which is closer to your original definition would be to use a distributive conditional type to distribute the conditional over the contituents of K
:
type ArrayKey<T, Key extends keyof T = keyof T> =
Key extends any ? T[Key] extends any[] ? Key : never : never
That will also work, but K
has to be a bare type parameter and Key extends any
might be confusing (distributive conditional types are a bit surprising) and it's abusing the default value of K
as a hack, so I wouldn't recommend it. Less hacky but still using distributive conditional types:
type ArrayKeyInner<T, Key extends keyof T> =
Key extends any ? T[Key] extends any[] ? Key : never : never
type ArrayKey<T> = ArrayKeyInner<T, keyof T>
That doesn't abuse a default parameter, which is nice. Still, the distributive conditional type surprise factor still holds so overall I'd still recommend the mapped type solution.
Hope that helps. Good luck!
Upvotes: 3