types - Represent Adobe's Number-like `UnitValue` in TypeScript -
adobe's extendscript features unitvalue
type, representing on-screen distance. type similar to, distinct from, number
type.
- each
unitvalue
object carriestype
string, example"cm"
or"ft"
. - arithmetic operations between
unitvalue
objects carrying differenttype
values involves implicit coercion; arithmetic operations betweenunitvalue
object , plainnumber
happens as-is, returningunitvalue
. - each
unitvalue
object carries number of miscellaneous fields;unitvalue
prototype implements bunch of methods. - a
unitvalue
object built constructor -var x = unitvalue(4, "cm")
.
how best represent in typescript?
it technically possible implement units using generic , literal types in typescript:
// union of possible unit types type unittype = 'cm' | 'm'; interface unitconversion<from extends unittype, extends unittype> { from: from; to: to; convert(value: unitvalue<from>): unitvalue<to>; } function conversion<from extends unittype, extends unittype>( from: from, to: to, convert: (value: unitvalue<from>) => unitvalue<to> ): unitconversion<from, to> { return { from, to, convert }; } function identity<t extends unittype>(t: t): unitconversion<t, t> { return { from: t, to: t, convert: v => v }; } // conversion table each pair of unit types const implicit_conversions = { 'cm': { 'cm': identity('cm'), 'm': conversion('cm', 'm', v => new unitvalue(v.value * 0.1, 'm')), }, 'm': { 'cm': conversion('m', 'm', v => new unitvalue(v.value * 10, 'cm')), 'm': identity('m'), }, }; type implicitconversions< left extends unittype, right extends unittype > = (typeof implicit_conversions)[left][right]['to']; function convert(conversion: unitconversion<any, any>, value: unitvalue<any>) { return value.type === conversion.to ? value : conversion.convert(value); } type unitpair<t extends unittype> = { left: unitvalue<t>; right: unitvalue<t>; }; function converttocommontype<left extends unittype, right extends unittype>( left: unitvalue<left>, right: unitvalue<right> ): unitpair<implicitconversions<left, right>> { const conversion = implicit_conversions[left.type][right.type]; return { left: convert(conversion, left), right: convert(conversion, right) }; } class unitvalue<type extends unittype> { constructor( readonly value: number, readonly type: type, ) { } /** type-safe unit addition */ add<t extends unittype>(value: unitvalue<t>): unitvalue<implicitconversions<type, t>> { const { left, right } = converttocommontype(this, value); return new unitvalue(left.value + right.value, left.type); } }
then use this:
const common = converttocommontype( new unitvalue(3, 'cm'), new unitvalue(10, 'm') ); // => result type: unitvalue<'m'> const z = new unitvalue(4, 'cm').add(new unitvalue(5, 'm')); // => result type: unitvalue<'m'>
however, argued introduces complexity.
Comments
Post a Comment