Skip to content

Commit

Permalink
refactor: remove the widen type (#193)
Browse files Browse the repository at this point in the history
* refactor: remove the widen type

* fixup! refactor: remove the widen type
  • Loading branch information
andreas-karlsson authored Aug 22, 2024
1 parent 1eb79c0 commit 99c9659
Show file tree
Hide file tree
Showing 6 changed files with 151 additions and 33 deletions.
62 changes: 56 additions & 6 deletions api/react.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,18 +40,42 @@ 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;
subscribe(onStateChange?: StateObserver | undefined): () => void;
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;
}
Expand All @@ -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;
Expand Down
27 changes: 22 additions & 5 deletions api/sdk.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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
Expand Down
52 changes: 46 additions & 6 deletions packages/react/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand All @@ -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);
}
Expand Down Expand Up @@ -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(() => {
Expand All @@ -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;
}
16 changes: 12 additions & 4 deletions packages/sdk/src/Confidence.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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;
}

Expand Down
9 changes: 0 additions & 9 deletions packages/sdk/src/Value.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
18 changes: 15 additions & 3 deletions packages/sdk/src/flags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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>;
}

0 comments on commit 99c9659

Please sign in to comment.