Skip to content

Commit 98907f9

Browse files
Sprinkles: Optionally return RequiredConditionalValue from utils (#158)
1 parent ba65efc commit 98907f9

File tree

3 files changed

+70
-3
lines changed

3 files changed

+70
-3
lines changed

.changeset/sweet-crews-kiss.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@vanilla-extract/sprinkles': patch
3+
---
4+
5+
Ensure `normalizeConditionalValue` and `mapConditionalValue` return `RequiredConditionalValue` types when a `RequiredConditionalValue` type is provided

packages/sprinkles/src/createUtils.ts

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,20 @@ export type RequiredConditionalValue<
7878

7979
export function createNormalizeValueFn<AtomicStyles extends Conditions<string>>(
8080
atomicStyles: AtomicStyles,
81-
): <Value extends string | number>(
82-
value: ConditionalValue<AtomicStyles, Value>,
83-
) => Partial<Record<ExtractConditionNames<AtomicStyles>, Value>> {
81+
): <Value extends ConditionalValue<AtomicStyles, string | number>>(
82+
value: Value,
83+
) => Value extends RequiredConditionalValue<AtomicStyles, infer PrimitiveValue>
84+
? RequiredConditionalObject<
85+
Exclude<ExtractDefaultCondition<AtomicStyles>, false>,
86+
Exclude<
87+
ExtractConditionNames<AtomicStyles>,
88+
Exclude<ExtractDefaultCondition<AtomicStyles>, false>
89+
>,
90+
PrimitiveValue
91+
>
92+
: Value extends ConditionalValue<AtomicStyles, infer PrimitiveValue>
93+
? Partial<Record<ExtractConditionNames<AtomicStyles>, PrimitiveValue>>
94+
: never {
8495
const { conditions } = atomicStyles;
8596

8697
if (!conditions) {
@@ -135,6 +146,15 @@ export function createMapValueFn<AtomicStyles extends Conditions<string>>(
135146
) => OutputValue,
136147
) => Value extends string | number
137148
? OutputValue
149+
: Value extends RequiredConditionalValue<AtomicStyles, string | number>
150+
? RequiredConditionalObject<
151+
Exclude<ExtractDefaultCondition<AtomicStyles>, false>,
152+
Exclude<
153+
ExtractConditionNames<AtomicStyles>,
154+
Exclude<ExtractDefaultCondition<AtomicStyles>, false>
155+
>,
156+
OutputValue
157+
>
138158
: Partial<Record<ExtractConditionNames<AtomicStyles>, OutputValue>> {
139159
const { conditions } = atomicStyles;
140160

tests/sprinkles/spinkles-type-tests.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@ import {
2020
// @ts-expect-error Unused args
2121
const noop = (...args: Array<any>) => {};
2222

23+
// @ts-expect-error Unused args
24+
const isString = (arg: string) => {};
25+
26+
// @ts-expect-error Unused args
27+
const isNumber = (arg: number) => {};
28+
2329
() => {
2430
const atoms = createAtomsFn(
2531
atomicWithShorthandStyles,
@@ -128,6 +134,18 @@ const noop = (...args: Array<any>) => {};
128134
// @ts-expect-error - Too many responsive array options
129135
normalizeValue(['one', 'two', 'three', 'four']);
130136

137+
// Valid value - default condition is provided
138+
isString(normalizeValue({ mobile: 'hello' }).mobile);
139+
140+
// Valid value - default condition is provided
141+
isString(normalizeValue({ mobile: 'hello', tablet: 'world' }).mobile);
142+
143+
// @ts-expect-error - condition is potentially undefined when not default condition
144+
isString(normalizeValue({ tablet: 'hello' }).tablet);
145+
146+
// @ts-expect-error - condition is potentially undefined when not default condition
147+
isString(normalizeValue({ mobile: 'hello', tablet: 'world' }).tablet);
148+
131149
normalizeValue({
132150
// @ts-expect-error - Incorrect conditional keys
133151
mobille: '',
@@ -139,6 +157,27 @@ const noop = (...args: Array<any>) => {};
139157
// @ts-expect-error - Numbers shouldn't map to objects
140158
mapValue(3, () => 4).mobile;
141159

160+
isString(mapValue({ mobile: 123 }, () => 'abc').mobile);
161+
isNumber(mapValue({ mobile: 'abc' }, () => 123).mobile);
162+
163+
// @ts-expect-error - Mobile should be potentially undefined since it wasn't provided
164+
isString(mapValue({ tablet: 123 }, () => 'abc').mobile);
165+
166+
// @ts-expect-error - Tablet should be potentially undefined since it's not the default condition
167+
isString(mapValue({ tablet: 123 }, () => 'abc').tablet);
168+
169+
// @ts-expect-error - Tablet should be potentially undefined since it's not the default condition
170+
isString(mapValue({ mobile: 123, tablet: 456 }, () => 'abc').tablet);
171+
172+
// @ts-expect-error - Mobile should be potentially undefined since it wasn't provided
173+
isNumber(mapValue({ tablet: 'abc' }, () => 123).mobile);
174+
175+
// @ts-expect-error - Tablet should be potentially undefined since it's not the default condition
176+
isNumber(mapValue({ tablet: 'abc' }, () => 123).tablet);
177+
178+
// @ts-expect-error - Tablet should be potentially undefined since it's not the default condition
179+
isNumber(mapValue({ mobile: 'abc', tablet: 'def' }, () => 123).tablet);
180+
142181
const mapValueWithoutDefaultCondition = createMapValueFn(
143182
conditionalStylesWithoutDefaultCondition,
144183
);
@@ -149,6 +188,9 @@ const noop = (...args: Array<any>) => {};
149188
// @ts-expect-error - Should force conditional value as no default condition
150189
normalizeValueWithoutDefaultCondition('test');
151190

191+
// @ts-expect-error - Should potentially be undefined
192+
isString(normalizeValueWithoutDefaultCondition({ active: 'yo' }).active);
193+
152194
// @ts-expect-error - Should force conditional value as no default condition
153195
mapValueWithoutDefaultCondition('test');
154196

0 commit comments

Comments
 (0)