Last active
March 6, 2023 15:05
-
-
Save aparx/588007b77ddb651713489a6005d9d170 to your computer and use it in GitHub Desktop.
Little type & runtime utility useful for styling, providing utilities to map any kind of units (such as XXL, XL, numbers and more) into a specfic unit string with custom piping to mutate given values.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Example: | |
* | |
* | |
*/ | |
const ExampleUnitMap = { xl: 3.0, md: 1.0, sm: 0.5, }; | |
type ExampleUnit = keyof typeof ExampleUnitMap; | |
const testMapper = UnitMapper< | |
ExampleUnit /* type of "value" */, | |
number /* result of ExampleUnitMap[value]; type of "input" */, | |
number /* result of 8 * input */, | |
'px' /* kind of final representation unit (optional) */ | |
>( | |
// we transform a given unit into its number | |
(value) => ExampleUnitMap[value], | |
// we transform | |
(input) => 8 * input /* input * 8px */, | |
'px' | |
); | |
const spacingInPx = testMapper('xl'); | |
// ^? `${number}px` | |
const testCaseA = testMapper('xl'); // => 24px (8 * 3.0) | |
const testCaseB = testMapper('md'); // => 8px (8 * 1.0) | |
const testCaseC = testMapper('sm'); // => 4px (8 * 0.5) | |
/* | |
* <----> Implementation <----> | |
*/ | |
export type UnitMappingPipe<TValue, TOutput> = (value: TValue) => TOutput; | |
export type UnitMappingBase<TValue, TComputedValue, TOutput> = ( | |
value: TValue, | |
then?: UnitMappingPipe<TComputedValue, TComputedValue> | |
) => TOutput; | |
export type UnitMappingOutputType = string | undefined; | |
export type UnitMapperComputedValue = string | number; | |
export type UnitMapperOutput< | |
TOutUnitAppendix extends UnitMappingOutputType, | |
TComputedValue extends UnitMapperComputedValue | |
> = TOutUnitAppendix extends string ? `${TComputedValue}${TOutUnitAppendix}` : TComputedValue; | |
export type UnitMapper< | |
TValue, | |
TComputedValue extends UnitMapperComputedValue, | |
TOutUnitAppendix extends UnitMappingOutputType | |
> = UnitMappingBase<TValue, TComputedValue, UnitMapperOutput<TOutUnitAppendix, TComputedValue>>; | |
export type UnitAssociator<TValue, TTransformerInput> = (value: TValue) => TTransformerInput; | |
export type UnitTransformer<TTransformerInput, TComputedValue extends UnitMapperComputedValue> = ( | |
input: TTransformerInput | |
) => TComputedValue; | |
/* UnitMapper Constructor */ | |
export type UnitMapperConstructor = { | |
< | |
TValue, | |
TTransformerInput, | |
TComputedValue extends UnitMapperComputedValue, | |
TOutUnitAppendix extends UnitMappingOutputType | |
>( | |
associator: UnitAssociator<TValue, TTransformerInput>, | |
transformer: UnitTransformer<TTransformerInput, TComputedValue>, | |
displayUnit?: TOutUnitAppendix | |
): UnitMapper<TValue, TComputedValue, TOutUnitAppendix>; | |
<TValue, TTransformerInput, TComputedValue extends UnitMapperComputedValue>( | |
associator: UnitAssociator<TValue, TTransformerInput>, | |
transformer: UnitTransformer<TTransformerInput, TComputedValue> | |
): UnitMapper<TValue, TComputedValue, undefined>; | |
}; | |
export const UnitMapper = function < | |
TValue, | |
TTransformerInput, | |
TComputedValue extends UnitMapperComputedValue, | |
TOutUnitAppendix extends UnitMappingOutputType | |
>( | |
associator: UnitAssociator<TValue, TTransformerInput>, | |
transformer: UnitTransformer<TTransformerInput, TComputedValue>, | |
displayUnit: TOutUnitAppendix | |
): UnitMapper<TValue, TComputedValue, TOutUnitAppendix> { | |
return function ( | |
value: TValue, | |
then?: UnitMappingPipe<TComputedValue, TComputedValue> | |
): UnitMapperOutput<TOutUnitAppendix, TComputedValue> { | |
let computed: TComputedValue = transformer(associator(value)); | |
computed = then != null ? then(computed) : computed; | |
// prettier-ignore | |
return ( | |
displayUnit !== undefined ? `${computed}${displayUnit}` : computed | |
) as UnitMapperOutput<TOutUnitAppendix, TComputedValue>; | |
}; | |
} as UnitMapperConstructor; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment