Skip to content

Commit

Permalink
feat: improve type checking of the default variant identifier using `…
Browse files Browse the repository at this point in the history
…NoInfer` utility type
  • Loading branch information
mateuszkulpa committed Mar 24, 2024
1 parent 56e1d3c commit 27e2e19
Show file tree
Hide file tree
Showing 5 changed files with 30 additions and 12 deletions.
8 changes: 4 additions & 4 deletions src/runtime/components/ABTest.vue
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
<script setup lang="ts" generic="TVariantValue extends JSONValue">
<script setup lang="ts" generic="TVariantKey extends string, TVariantValue extends JSONValue">
import { useABTest } from '../composables/useABTest'
import type { JSONValue, Variant } from '../types'
import { useSlots } from '#imports'
const props = withDefaults(
defineProps<{
id: string
variants: Variant<TVariantValue>[]
variants: Variant<TVariantKey, TVariantValue>[]
enabled?: boolean
default?: string
default?: NoInfer<TVariantKey>
}>(),
{
enabled: undefined,
default: undefined,
}
)
const { result } = useABTest<TVariantValue>({
const { result } = useABTest({
id: props.id,
variants: props.variants,
enabled: props.enabled,
Expand Down
4 changes: 2 additions & 2 deletions src/runtime/composables/useABTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { resolveABTestVariant } from '../core/variants'

const STORAGE_KEY_PREFIX = 'ab-test'

export function useABTest<TVariantValue extends JSONValue>(
abTest: ABTest<TVariantValue>
export function useABTest<TVariantKey extends string, TVariantValue extends JSONValue>(
abTest: ABTest<TVariantKey, TVariantValue>
): ABTestResult<TVariantValue> {
const storageId = `${STORAGE_KEY_PREFIX}:${abTest.id}`

Expand Down
2 changes: 1 addition & 1 deletion src/runtime/core/variants.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { ABTest, ABTestResult, JSONValue } from '~/src/runtime/types'

export function resolveABTestVariant<TVariantValue extends JSONValue>(
abTest: ABTest<TVariantValue>
abTest: ABTest<string, TVariantValue>
): ABTestResult<TVariantValue> {
if (abTest.variants.every(variant => variant.weight === undefined)) {
return {
Expand Down
13 changes: 8 additions & 5 deletions src/runtime/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ export interface JSONObject {
}
export type JSONArray = JSONValue[]

export interface Variant<TVariantValue extends JSONValue> {
id: string
export interface Variant<TVariantKey extends string, TVariantValue extends JSONValue> {
id: TVariantKey
value: TVariantValue
weight?: number
}
Expand All @@ -39,9 +39,12 @@ export type ABTestResult<TVariantValue extends JSONValue> =
| ABTestResultEnabled<TVariantValue>
| ABTestResultDisabled<TVariantValue>

export interface ABTest<TVariantValue extends JSONValue = JSONValue> {
export interface ABTest<
TVariantKey extends string = string,
TVariantValue extends JSONValue = JSONValue,
> {
id: string
variants: Variant<TVariantValue>[]
variants: Variant<TVariantKey, TVariantValue>[]
/**
* Indicates whether the A/B test is enabled or not.
* By default, the test is considered to be enabled.
Expand All @@ -53,5 +56,5 @@ export interface ABTest<TVariantValue extends JSONValue = JSONValue> {
* The id of the default variant to use when the test is not enabled (`enabled` is `false`).
* This property is required when `enabled` is `false` to specify which variant should be considered the default.
*/
default?: string
default?: NoInfer<TVariantKey>
}
15 changes: 15 additions & 0 deletions test/variants.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,19 @@ describe('useABTest', () => {

expect(result).toEqual({ enabled: false, result: undefined })
})

test("doesn't return default value when default is wrong identifier", () => {
const result = useABTest({
id: 'test-id',
variants: [
{ id: 'a', value: 'a' },
{ id: 'b', value: 'b' },
],
enabled: false,
// @ts-expect-error
default: 'c',
})

expect(result).toEqual({ enabled: false, result: undefined })
})
})

0 comments on commit 27e2e19

Please sign in to comment.