This is my interface
interface X {
key: string
value: number | undefined
default?: number
}
But I want the non-optional keys only, aka. "key" | "value"
, or just "key"
(both will do fine for me)
type KeyOfX = keyof X
gives me "key" | "value" | "default"
.
type NonOptionalX = {
[P in keyof X]-?: X[P]
}
type NonOptionalKeyOfX = keyof NonOptionalX
gives "key" | "value" | "default"
as -?
only removes the optional modifier and make all of them non-optional.
ps. I use Typescript 2.9.
You can use conditional type operator of the form undefined extends k ? never : k
to substitute never
for keys of values that undefined
could be assigned to, and then use the fact that union T | never
is just T
for any type:
interface X {
key: string
value: number | undefined
default?: number
}
type NonOptionalKeys<T> = { [k in keyof T]-?: undefined extends T[k] ? never : k }[keyof T];
type Z = NonOptionalKeys<X>; // just 'key'
Also this comment might be relevant: https://github.com/Microsoft/TypeScript/issues/12215#issuecomment-307871458
But I want the non-optional keys only, aka. "key" | "value", or just "key" (both will do fine for me)
While easier option of "key"
is covered, I'd like to cover a less obvious option of "key" | "value"
. It might be needed because value
is not an optional field. It can be assigned undefined
, but it should pass a "value" in x
check.
type NonOptionalKeys<T> = { [K in keyof T]-?: T extends { [K1 in K]: any } ? K : never}[keyof T]
How it works:
K
) are actually not only types, but types with "requiredness" and "readonlyness" attached;T
with -?
makes optional keys required before putting them into K
;{ [K1 in K]: any }
object is an object with single required keynever
;never
as value;[keyof T]
a union of all the value types gets computed, never
types get removed ((A | never) = A
), and only a union of all required keys is left.Update: readonly
is way trickier. Read here or here. You can completely disassemble an object into a tuple like this.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With