From 99c9659e857ad862f6273fe2209abdd47073440c Mon Sep 17 00:00:00 2001 From: "andreas.karlsson" <andreas.karlsson.se@gmail.com> Date: Thu, 22 Aug 2024 17:49:25 +0200 Subject: [PATCH] refactor: remove the widen type (#193) * refactor: remove the widen type * fixup! refactor: remove the widen type --- api/react.api.md | 62 ++++++++++++++++++++++++++++++---- api/sdk.api.md | 27 ++++++++++++--- packages/react/src/index.tsx | 52 ++++++++++++++++++++++++---- packages/sdk/src/Confidence.ts | 16 ++++++--- packages/sdk/src/Value.ts | 9 ----- packages/sdk/src/flags.ts | 18 ++++++++-- 6 files changed, 151 insertions(+), 33 deletions(-) diff --git a/api/react.api.md b/api/react.api.md index b6093279..3fd87b8c 100644 --- a/api/react.api.md +++ b/api/react.api.md @@ -40,9 +40,21 @@ export class ConfidenceReact implements EventSender, Trackable, FlagResolver { get contextState(): string; // @internal readonly delegate: Confidence; - evaluateFlag<T extends Value>(path: string, defaultValue: T): FlagEvaluation<Value.Widen<T>>; + evaluateFlag(path: string, defaultValue: string): FlagEvaluation<string>; + // (undocumented) + evaluateFlag(path: string, defaultValue: boolean): FlagEvaluation<boolean>; + // (undocumented) + evaluateFlag(path: string, defaultValue: number): FlagEvaluation<number>; + // (undocumented) + evaluateFlag<T extends Value>(path: string, defaultValue: T): FlagEvaluation<T>; getContext(): Context; - getFlag<T extends Value>(path: string, defaultValue: T): Promise<Value.Widen<T>>; + getFlag(path: string, defaultValue: string): Promise<string>; + // (undocumented) + getFlag(path: string, defaultValue: boolean): Promise<boolean>; + // (undocumented) + getFlag(path: string, defaultValue: number): Promise<number>; + // (undocumented) + getFlag<T extends Value>(path: string, defaultValue: T): Promise<T>; setContext(context: Context, { transition }?: { transition?: boolean | undefined; }): void; @@ -50,8 +62,20 @@ export class ConfidenceReact implements EventSender, Trackable, FlagResolver { track(name: string, message?: Value.Struct): void; track(manager: Trackable.Manager): Closer; useContext(): Context; - useEvaluateFlag<T extends Value>(path: string, defaultValue: T): FlagEvaluation<Value.Widen<T>>; - useFlag<T extends Value>(path: string, defaultValue: T): Value.Widen<T>; + useEvaluateFlag(path: string, defaultValue: string): FlagEvaluation<string>; + // (undocumented) + useEvaluateFlag(path: string, defaultValue: number): FlagEvaluation<number>; + // (undocumented) + useEvaluateFlag(path: string, defaultValue: boolean): FlagEvaluation<boolean>; + // (undocumented) + useEvaluateFlag<T extends Value>(path: string, defaultValue: T): FlagEvaluation<T>; + useFlag(path: string, defaultValue: string): string; + // (undocumented) + useFlag(path: string, defaultValue: number): number; + // (undocumented) + useFlag(path: string, defaultValue: boolean): boolean; + // (undocumented) + useFlag<T extends Value>(path: string, defaultValue: T): T; useWithContext(context: Context): ConfidenceReact; withContext(context: Context): ConfidenceReact; } @@ -62,11 +86,37 @@ export const useConfidence: () => ConfidenceReact; // @public export function useConfidenceContext(confidence?: ConfidenceReact): Context; +// Warning: (ae-missing-release-tag) "useEvaluateFlag" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// Warning: (ae-missing-release-tag) "useEvaluateFlag" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// Warning: (ae-missing-release-tag) "useEvaluateFlag" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public -export function useEvaluateFlag<T extends Value>(path: string, defaultValue: T, confidence?: ConfidenceReact): FlagEvaluation<Value.Widen<T>>; +export function useEvaluateFlag(path: string, defaultValue: string, confidence?: ConfidenceReact): FlagEvaluation<string>; +// @public (undocumented) +export function useEvaluateFlag(path: string, defaultValue: number, confidence?: ConfidenceReact): FlagEvaluation<number>; + +// @public (undocumented) +export function useEvaluateFlag(path: string, defaultValue: boolean, confidence?: ConfidenceReact): FlagEvaluation<boolean>; + +// @public (undocumented) +export function useEvaluateFlag<T extends Value>(path: string, defaultValue: T, confidence?: ConfidenceReact): FlagEvaluation<T>; + +// Warning: (ae-missing-release-tag) "useFlag" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// Warning: (ae-missing-release-tag) "useFlag" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// Warning: (ae-missing-release-tag) "useFlag" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public -export function useFlag<T extends Value>(path: string, defaultValue: T, confidence?: ConfidenceReact): Value.Widen<T>; +export function useFlag(path: string, defaultValue: string, confidence?: ConfidenceReact): string; + +// @public (undocumented) +export function useFlag(path: string, defaultValue: number, confidence?: ConfidenceReact): number; + +// @public (undocumented) +export function useFlag(path: string, defaultValue: boolean, confidence?: ConfidenceReact): boolean; + +// @public (undocumented) +export function useFlag<T extends Value>(path: string, defaultValue: T, confidence?: ConfidenceReact): T; // @public export function useWithContext(context: Context, parent?: ConfidenceReact): ConfidenceReact; diff --git a/api/sdk.api.md b/api/sdk.api.md index 25280b59..205b3361 100644 --- a/api/sdk.api.md +++ b/api/sdk.api.md @@ -24,10 +24,22 @@ export class Confidence implements EventSender, Trackable, FlagResolver { readonly contextChanges: Subscribe<string[]>; static create({ clientSecret, region, timeout, environment, fetchImplementation, logger, }: ConfidenceOptions): Confidence; get environment(): string; - evaluateFlag<T extends Value>(path: string, defaultValue: T): FlagEvaluation<Value.Widen<T>>; + evaluateFlag(path: string, defaultValue: string): FlagEvaluation<string>; + // (undocumented) + evaluateFlag(path: string, defaultValue: boolean): FlagEvaluation<boolean>; + // (undocumented) + evaluateFlag(path: string, defaultValue: number): FlagEvaluation<number>; + // (undocumented) + evaluateFlag<T extends Value>(path: string, defaultValue: T): FlagEvaluation<T>; get flagState(): State; getContext(): Context; - getFlag<T extends Value>(path: string, defaultValue: T): Promise<Value.Widen<T>>; + getFlag(path: string, defaultValue: string): Promise<string>; + // (undocumented) + getFlag(path: string, defaultValue: boolean): Promise<boolean>; + // (undocumented) + getFlag(path: string, defaultValue: number): Promise<number>; + // (undocumented) + getFlag<T extends Value>(path: string, defaultValue: T): Promise<T>; // Warning: (ae-forgotten-export) The symbol "AccessiblePromise" needs to be exported by the entry point index.d.ts protected resolveFlags(): AccessiblePromise<void>; setContext(context: Context): boolean; @@ -125,8 +137,14 @@ export type FlagEvaluation<T> = FlagEvaluation.Resolved<T> | FlagEvaluation.Stal // @public export interface FlagResolver extends Contextual<FlagResolver> { - evaluateFlag<T extends Value>(path: string, defaultValue: T): FlagEvaluation<Value.Widen<T>>; - getFlag<T extends Value>(path: string, defaultValue: T): Promise<Value.Widen<T>>; + evaluateFlag(path: string, defaultValue: string): FlagEvaluation<string>; + evaluateFlag(path: string, defaultValue: boolean): FlagEvaluation<boolean>; + evaluateFlag(path: string, defaultValue: number): FlagEvaluation<number>; + evaluateFlag<T extends Value>(path: string, defaultValue: T): FlagEvaluation<T>; + getFlag(path: string, defaultValue: string): Promise<string>; + getFlag(path: string, defaultValue: boolean): Promise<boolean>; + getFlag(path: string, defaultValue: number): Promise<number>; + getFlag<T extends Value>(path: string, defaultValue: T): Promise<T>; subscribe(onStateChange?: StateObserver): () => void; } @@ -178,7 +196,6 @@ export namespace Value { readonly [key: string]: Value; }; export type TypeName = 'number' | 'string' | 'boolean' | 'Struct' | 'List' | 'undefined'; - export type Widen<T extends Value> = T extends number ? number : T extends string ? string : T extends boolean ? boolean : T; } // @public diff --git a/packages/react/src/index.tsx b/packages/react/src/index.tsx index 80d4bf4c..17d92aef 100644 --- a/packages/react/src/index.tsx +++ b/packages/react/src/index.tsx @@ -119,12 +119,20 @@ export class ConfidenceReact implements EventSender, Trackable, FlagResolver { return new ConfidenceReact(this.delegate.withContext(context)); } /** Evaluates a flag */ - evaluateFlag<T extends Value>(path: string, defaultValue: T): FlagEvaluation<Value.Widen<T>> { + evaluateFlag(path: string, defaultValue: string): FlagEvaluation<string>; + evaluateFlag(path: string, defaultValue: boolean): FlagEvaluation<boolean>; + evaluateFlag(path: string, defaultValue: number): FlagEvaluation<number>; + evaluateFlag<T extends Value>(path: string, defaultValue: T): FlagEvaluation<T>; + evaluateFlag<T extends Value>(path: string, defaultValue: T): FlagEvaluation<T> { this.assertContext('evaluateFlag', 'useEvaluateFlag'); return this.delegate.evaluateFlag(path, defaultValue); } /** Returns flag value for a given flag */ - getFlag<T extends Value>(path: string, defaultValue: T): Promise<Value.Widen<T>> { + getFlag(path: string, defaultValue: string): Promise<string>; + getFlag(path: string, defaultValue: boolean): Promise<boolean>; + getFlag(path: string, defaultValue: number): Promise<number>; + getFlag<T extends Value>(path: string, defaultValue: T): Promise<T>; + getFlag<T extends Value>(path: string, defaultValue: T): Promise<T> { this.assertContext('getFlag', 'useFlag'); return this.delegate.getFlag(path, defaultValue); } @@ -142,12 +150,20 @@ export class ConfidenceReact implements EventSender, Trackable, FlagResolver { return useWithContext(context, this); } /** Hook to use EvaluateFlag functionality */ - useEvaluateFlag<T extends Value>(path: string, defaultValue: T): FlagEvaluation<Value.Widen<T>> { + useEvaluateFlag(path: string, defaultValue: string): FlagEvaluation<string>; + useEvaluateFlag(path: string, defaultValue: number): FlagEvaluation<number>; + useEvaluateFlag(path: string, defaultValue: boolean): FlagEvaluation<boolean>; + useEvaluateFlag<T extends Value>(path: string, defaultValue: T): FlagEvaluation<T>; + useEvaluateFlag<T extends Value>(path: string, defaultValue: T): FlagEvaluation<T> { this.assertContext('useEvaluateFlag', 'evaluateFlag'); return useEvaluateFlag(path, defaultValue, this); } /** Hook to use getFlag functionality */ - useFlag<T extends Value>(path: string, defaultValue: T): Value.Widen<T> { + useFlag(path: string, defaultValue: string): string; + useFlag(path: string, defaultValue: number): number; + useFlag(path: string, defaultValue: boolean): boolean; + useFlag<T extends Value>(path: string, defaultValue: T): T; + useFlag<T extends Value>(path: string, defaultValue: T): T { this.assertContext('useFlag', 'getFlag'); return useFlag(path, defaultValue, this); } @@ -233,12 +249,32 @@ export function useConfidenceContext(confidence = useConfidence()): Context { /** * Use EvaluateFlag * @public */ +export function useEvaluateFlag( + path: string, + defaultValue: string, + confidence?: ConfidenceReact, +): FlagEvaluation<string>; +export function useEvaluateFlag( + path: string, + defaultValue: number, + confidence?: ConfidenceReact, +): FlagEvaluation<number>; +export function useEvaluateFlag( + path: string, + defaultValue: boolean, + confidence?: ConfidenceReact, +): FlagEvaluation<boolean>; +export function useEvaluateFlag<T extends Value>( + path: string, + defaultValue: T, + confidence?: ConfidenceReact, +): FlagEvaluation<T>; export function useEvaluateFlag<T extends Value>( path: string, defaultValue: T, // eslint-disable-next-line react-hooks/rules-of-hooks confidence = useConfidence(), -): FlagEvaluation<Value.Widen<T>> { +): FlagEvaluation<T> { const evaluation = confidence.delegate.evaluateFlag(path, defaultValue); const [, setState] = useState(() => confidence.contextState); useEffect(() => { @@ -254,7 +290,11 @@ export function useEvaluateFlag<T extends Value>( * Use Flag * @public */ +export function useFlag(path: string, defaultValue: string, confidence?: ConfidenceReact): string; +export function useFlag(path: string, defaultValue: number, confidence?: ConfidenceReact): number; +export function useFlag(path: string, defaultValue: boolean, confidence?: ConfidenceReact): boolean; +export function useFlag<T extends Value>(path: string, defaultValue: T, confidence?: ConfidenceReact): T; // eslint-disable-next-line react-hooks/rules-of-hooks -export function useFlag<T extends Value>(path: string, defaultValue: T, confidence = useConfidence()): Value.Widen<T> { +export function useFlag<T extends Value>(path: string, defaultValue: T, confidence = useConfidence()): T { return useEvaluateFlag(path, defaultValue, confidence).value; } diff --git a/packages/sdk/src/Confidence.ts b/packages/sdk/src/Confidence.ts index 48a190ac..c27fd8dd 100644 --- a/packages/sdk/src/Confidence.ts +++ b/packages/sdk/src/Confidence.ts @@ -276,7 +276,11 @@ export class Confidence implements EventSender, Trackable, FlagResolver { } /** Evaluates a flag */ - evaluateFlag<T extends Value>(path: string, defaultValue: T): FlagEvaluation<Value.Widen<T>> { + evaluateFlag(path: string, defaultValue: string): FlagEvaluation<string>; + evaluateFlag(path: string, defaultValue: boolean): FlagEvaluation<boolean>; + evaluateFlag(path: string, defaultValue: number): FlagEvaluation<number>; + evaluateFlag<T extends Value>(path: string, defaultValue: T): FlagEvaluation<T>; + evaluateFlag<T extends Value>(path: string, defaultValue: T): FlagEvaluation<T> { let evaluation: FlagEvaluation<T>; // resolveFlags might update state synchronously if (!this.currentFlags && !this.pendingFlags) this.resolveFlags(); @@ -297,13 +301,17 @@ export class Confidence implements EventSender, Trackable, FlagResolver { ...evaluation, then, }; - return staleEvaluation as FlagEvaluation<Value.Widen<T>>; + return staleEvaluation; } - return evaluation as FlagEvaluation<Value.Widen<T>>; + return evaluation; } /** Returns flag value for a given flag */ - async getFlag<T extends Value>(path: string, defaultValue: T): Promise<Value.Widen<T>> { + getFlag(path: string, defaultValue: string): Promise<string>; + getFlag(path: string, defaultValue: boolean): Promise<boolean>; + getFlag(path: string, defaultValue: number): Promise<number>; + getFlag<T extends Value>(path: string, defaultValue: T): Promise<T>; + async getFlag<T extends Value>(path: string, defaultValue: any): Promise<T> { return (await this.evaluateFlag(path, defaultValue)).value; } diff --git a/packages/sdk/src/Value.ts b/packages/sdk/src/Value.ts index 6025568b..c05c8977 100644 --- a/packages/sdk/src/Value.ts +++ b/packages/sdk/src/Value.ts @@ -20,15 +20,6 @@ export namespace Value { /** Readonly List */ export type List = ReadonlyArray<number> | ReadonlyArray<string> | ReadonlyArray<boolean>; - /** Sets Confidence used Values to be implementations of primitive types */ - export type Widen<T extends Value> = T extends number - ? number - : T extends string - ? string - : T extends boolean - ? boolean - : T; - /** Asserts a Value */ export function assertValue(value: unknown): asserts value is Value { switch (typeof value) { diff --git a/packages/sdk/src/flags.ts b/packages/sdk/src/flags.ts index dbbef759..bc08849a 100644 --- a/packages/sdk/src/flags.ts +++ b/packages/sdk/src/flags.ts @@ -69,9 +69,21 @@ export interface FlagResolver extends Contextual<FlagResolver> { /** Subscribe to flag changes in Confidence */ subscribe(onStateChange?: StateObserver): () => void; + /** Evaluates a string flag */ + evaluateFlag(path: string, defaultValue: string): FlagEvaluation<string>; + /** Evaluates a boolean flag */ + evaluateFlag(path: string, defaultValue: boolean): FlagEvaluation<boolean>; + /** Evaluates a numeric flag */ + evaluateFlag(path: string, defaultValue: number): FlagEvaluation<number>; /** Evaluates a flag */ - evaluateFlag<T extends Value>(path: string, defaultValue: T): FlagEvaluation<Value.Widen<T>>; + evaluateFlag<T extends Value>(path: string, defaultValue: T): FlagEvaluation<T>; - /** Returns flag value for a given flag */ - getFlag<T extends Value>(path: string, defaultValue: T): Promise<Value.Widen<T>>; + /** Returns flag value for a string flag */ + getFlag(path: string, defaultValue: string): Promise<string>; + /** Returns flag value for a boolean flag */ + getFlag(path: string, defaultValue: boolean): Promise<boolean>; + /** Returns flag value for a numeric flag */ + getFlag(path: string, defaultValue: number): Promise<number>; + /** Returns flag value for a flag */ + getFlag<T extends Value>(path: string, defaultValue: T): Promise<T>; }