@zendesk/retrace
Version:
define and capture Product Operation Traces along with computed metrics with an optional friendly React beacon API
202 lines (174 loc) • 6.72 kB
text/typescript
/* eslint-disable @typescript-eslint/no-explicit-any */
import type { States, TraceStates } from './Trace'
import type { RelationSchemasBase } from './types'
export type DistributiveOmit<T, K extends keyof any> = T extends T
? Omit<T, K>
: never
export type Prettify<T> = {
[K in keyof T]: T[K]
} & {}
export type RemoveAllUndefinedProperties<T> = Prettify<{
[K in keyof T as T[K] extends undefined ? never : K]: T[K]
}>
// type TestAbove = RemoveAllUndefinedProperties<{ a?: boolean; b: undefined }>
/**
* Extract the set of keys in T whose type is not exactly `undefined`.
* If T[P] is `? undefined`, we treat that key as "unused."
*/
type NonUndefinedKeys<T> = {
[P in keyof T]-?: T[P] extends undefined ? never : P
}[keyof T]
// type TestAbove = NonUndefinedKeys<{ a: string; b?: number; c: undefined }>
type ExactKeySet<T, K extends PropertyKey> = [NonUndefinedKeys<T>] extends [K] // is T's key-set a subset of K?
? [K] extends [NonUndefinedKeys<T>] // is K a subset of T's key-set?
? true
: false
: false
/**
* Picks from U those members whose *non-undefined* keys
* are exactly the set K.
*/
export type SelectByAllKeys<K extends PropertyKey, U> = U extends unknown
? ExactKeySet<U, K> extends true
? U
: never
: never
/**
* Picks from U those members that have at least one
* non-undefined key from K.
*/
export type SelectBySomeKeys<K extends PropertyKey, U> = U extends unknown
? Extract<NonUndefinedKeys<U>, K> extends never
? never
: U
: never
/**
* For T, check if NonUndefinedKeys<T> is exactly equal to the set of keys in K.
* "Exactly equal" means the two sets are mutual subsets of each other.
*/
type HasExactKeys<
T,
K extends readonly PropertyKey[],
> = NonUndefinedKeys<T> extends K[number] // T's keys ⊆ K
? K[number] extends NonUndefinedKeys<T> // K ⊆ T's keys
? true
: false
: false
// type TestAboveTrue = HasExactKeys<{ a: string; b?: number }, ['b', 'a']>
// type TestAboveTrue2 = HasExactKeys<{ a: string; b?: undefined}, ['a']>
// type TestAboveFalse = HasExactKeys<{ a: string; b: number }, ['a']>
// type TestAboveFalse2 = HasExactKeys<{ a: string; b?: undefined}, ['b', 'a']>
// type TestAboveFalse3 = HasExactKeys<{ a: string; b?: number | undefined}, ['a']>
/**
* For T, check if it has at least one key from K as non-undefined.
*/
type HasSomeKeys<T, K extends readonly PropertyKey[]> =
// We see if NonUndefinedKeys<T> intersects with K[number] is non-empty
Extract<NonUndefinedKeys<T>, K[number]> extends never ? false : true
// type TestAboveTrue = HasSomeKeys<{ a: string; b?: number }, ['b', 'a']>
// type TestAboveTrue2 = HasSomeKeys<{ a: string; b?: number }, ['a']>
// type TestAboveFalse = HasSomeKeys<{ a: string; b?: number; c: undefined }, ['c']>
/**
* From a union of object types U, pick those whose non-undefined keys
* are *exactly* the set of keys in K (ignoring order).
*/
export type SelectByAllKeysUnion<
K extends readonly PropertyKey[],
U,
> = U extends unknown ? (HasExactKeys<U, K> extends true ? U : never) : never
// type TestAboveOk = SelectByAllKeysUnion<['a', 'b'], { a: string; b: number } | { a: string; c: number }>
// type TestAboveOk2 = SelectByAllKeysUnion<['c', 'a'], { a: string; b: number } | { a: string; c: number }>
// type TestAboveNever = SelectByAllKeysUnion<['c'], { a: string; b: number } | { a: string; c: number }>;
// type TestAboveNever2 = SelectByAllKeysUnion<['a'], { a: string; b: number } | { a: string; c: number }>;
/**
* From a union of object types U, pick those that have at least one
* non-undefined key from K.
*/
export type SelectBySomeKeysUnion<
K extends readonly PropertyKey[],
U,
> = U extends unknown ? (HasSomeKeys<U, K> extends true ? U : never) : never
// type TestAbove = SelectBySomeKeysUnion<['a'], { a: string; b: number } | { a: string; c: number }>;
// type TestAbove2 = SelectBySomeKeysUnion<['b'], { a: string; b: number } | { a: string; c: number }>;
export type UnionToIntersection<U> = (
U extends U ? (x: U) => void : never
) extends (x: infer I) => void
? I
: never
type HandlerToPayloadTuples<
SelectedRelationNameT extends keyof RelationSchemasT,
RelationSchemasT extends RelationSchemasBase<RelationSchemasT>,
VariantsT extends string,
State extends TraceStates = TraceStates,
> = State extends State
? {
[K in keyof States<
SelectedRelationNameT,
RelationSchemasT,
VariantsT
>[State]]: States<
SelectedRelationNameT,
RelationSchemasT,
VariantsT
>[State][K] extends (...args: infer ArgsT) => infer ReturnT
? [K, ArgsT[0], ReturnT]
: never
}[keyof States<SelectedRelationNameT, RelationSchemasT, VariantsT>[State]]
: never
type TupleToObject<T extends [PropertyKey, any, any]> = Prettify<{
[K in T[0]]: T extends [K, infer V, any] ? V : never
}>
type TupleToObject2<T extends [PropertyKey, any, any]> = Prettify<{
[K in T[0]]: T extends [K, any, infer V] ? V : never
}>
export type StateHandlerPayloads<
SelectedRelationNameT extends keyof RelationSchemasT,
RelationSchemasT extends RelationSchemasBase<RelationSchemasT>,
VariantsT extends string,
> = TupleToObject<
HandlerToPayloadTuples<SelectedRelationNameT, RelationSchemasT, VariantsT>
>
export type StateHandlerReturnTypes<
SelectedRelationNameT extends keyof RelationSchemasT,
RelationSchemasT extends RelationSchemasBase<RelationSchemasT>,
VariantsT extends string,
> = TupleToObject2<
HandlerToPayloadTuples<SelectedRelationNameT, RelationSchemasT, VariantsT>
>
export type MergedStateHandlerMethods<
SelectedRelationNameT extends keyof RelationSchemasT,
RelationSchemasT extends RelationSchemasBase<RelationSchemasT>,
VariantsT extends string,
> = {
[K in keyof StateHandlerPayloads<
SelectedRelationNameT,
RelationSchemasT,
VariantsT
>]: (
payload: StateHandlerPayloads<
SelectedRelationNameT,
RelationSchemasT,
VariantsT
>[K],
) => StateHandlerReturnTypes<
SelectedRelationNameT,
RelationSchemasT,
VariantsT
>[K]
}
export type ArrayWithAtLeastOneElement<T> = readonly [T, ...T[]]
export type MapTuple<KeysTuple extends readonly unknown[], MapToValue> = {
[Index in keyof KeysTuple]: MapToValue
}
/** Convert a union of values U into a single tuple type (in an arbitrary order). */
export type UnionToTuple<U, R extends any[] = []> = [U] extends [never]
? R
: UnionToTuple<Exclude<U, LastOf<U>>, [LastOf<U>, ...R]>
type LastOf<U> = UnionToIntersection<
U extends any ? (x: U) => void : never
> extends (x: infer L) => void
? L
: never
export type OpenPick<T, K extends string> = {
[P in K & keyof T]: T[P]
}