Got the idea from the example below from Typescript Docs: Distributive Conditional Types
So I've adapted it, and it works:
interface SOME_OBJECT {
title: string,
label: string,
someBool: boolean,
someDate: Date,
someNumber: number
}
type ExtractStringPropertyNames<T> = {
[K in keyof T]: T[K] extends string ? K : never
}[keyof T]
type STRING_KEYS = ExtractStringPropertyNames<SOME_OBJECT>
Typescript playground
If possible, I'm still interested in see other ways of doing that. Especially if there are more straightforward ways of doing it, as I think this answer feels like a "hack", 'cause it does not make it very clear what the code is doing.
UPDATE (HOW IT WORKS)
I've studied a bit more to understand what the code is actually doing, and I think I've figured it out.
I've broken it into two steps:
STEP 1
In the first step, a new object/type will be created.
The keys for this new object will the same keys K in keyof T
as from the keys of the generic type T
(SOME_OBJECT
in the example).
And for the values of those keys, we'll check in the generic type T
, if the values for those properties K
extends string
. Which means that those values are assignable to string
. For example: string
, "some_hard_coded_string_type"
and any
will all pass the test.
For each property that passes the test, we will repeat its key K
name as the value for them, otherwise will pass never
. You can see the result in STEP_1_RESULT
below.
STEP 2
In this step, we'll simply get that object generated from the step 1, and ask
Typescript to return all of its possible values, by doing type STEP_2<T> = T[keyof T]
.
Remember that keyof T
represents the union of all properties from T
. So Typescript will return a union with all possible values for the STEP_1_RESULT
object when called with the members of the keyof T
union.
In our example, it will return "title" | "label" | never | never | never
.
But since the never
types are meaningless inside a union type, those values are discarded and we are left with "title" | "label"
.