diff --git a/packages/type-utils/src/object.ts b/packages/type-utils/src/object.ts index 1f18d90868..ede5f56822 100644 --- a/packages/type-utils/src/object.ts +++ b/packages/type-utils/src/object.ts @@ -11,3 +11,20 @@ export type GetObjectWithoutKey = U extends object : never; export type ObjectsOnly = T extends Record ? T : never; + +/** + * All keys of types in a union. + * + * Example: + * ``` + * type T = { a: number; b: string } & ({ foo: numer } | { bar: string }); + * type K: KeysOfUnion; // 'a' | 'b' | 'foo' | 'bar' + * ``` + */ +export type KeysOfUnion = T extends T ? keyof T : never; + +export type NarrowObjectWithKey = T extends any + ? K extends keyof T + ? T + : never + : never; diff --git a/packages/utils/src/typedObject.ts b/packages/utils/src/typedObject.ts index 3e1dce592d..5ab1e0cc8c 100644 --- a/packages/utils/src/typedObject.ts +++ b/packages/utils/src/typedObject.ts @@ -1,3 +1,5 @@ +import { KeysOfUnion, NarrowObjectWithKey } from '@trezor/type-utils'; + export const typedObjectEntries = >( obj: T, ): [keyof T, T[keyof T]][] => Object.entries(obj) as [keyof T, T[keyof T]][]; @@ -13,3 +15,20 @@ export const typedObjectKeys = >(obj: T): Array>(obj: T): Array => Object.values(obj) as Array; + +/** + * @example + * ```ts + * type Props = { a: number; b: string } & ({ foo: number } | { bar: string }); + * + * function someFn(props: Props) { + * return hasOwn(props, 'foo') ? props.foo : props.bar; + * } + * ``` + */ +export function hasOwn>( + obj: T, + key: K, +): obj is NarrowObjectWithKey { + return Object.hasOwn(obj, key); +}