Skip to content

Suggestion: Units of measure #364

Description

This feature request is similar to units of measure in F#.

For example:

constmetres=125<m>;constseconds=2<s>;letspeed: number<m/s>;speed=metres/seconds;// validspeed=metres/seconds/10<s>;// error -- cannot convert m/s**2 to m/s

(Moved from work item 1715 on Codeplex.)

Proposal

Last Updated: 2016-06-09
Copied from:https://github.com/dsherret/Units-of-Measure-Proposal-for-TypeScript


Overview

Units of measure is a useful F# feature that provides the optional ability to create tighter constraints on numbers.

TypeScript could benefit from a similar feature that would add zero runtime overhead, increase type constraints, and help decrease programmer error when doing mathematical calculations that involve units. The feature should prefer explicity.

Defining Units of Measure

Units of measure should probably use syntax similar to type aliases (#957). More discussion is needed on this, but for the purpose of this document it will use the following syntax:

typemeasure<name>[=measureexpression];

The optional measure expression part can be used to define a new measures in terms of previously defined measures.

Example Definitions

typemeasurem;typemeasures;typemeasurea=m/s**2;

Units of measure can be defined in any order. For example, a in the example above could have been defined before m or s.

Circular Definitions

Circular definitions are NOT allowed. For example:

typemeasurea=b;typemeasureb=a;// error

Use with Number

Units of measure can be defined on a number type in any of the following ways:

typemeasurem;// 1. Explicitlyletdistance: number<m>=12<m>;// 2. Implictlyletdistance=12<m>;// 3. Using Number classletdistance=newNumber(10)<s>;

TODO: Maybe we shouldn't use the <m> syntax because it might conflict with jsx files.

Detailed Full Example

typemeasurem;typemeasures;typemeasurea=m/s**2;letacceleration=12<a>,time=10<s>;letdistance=1/2*acceleration*(time**2);// valid -- implicitly typed to number<m>letavgSpeed=distance/time;// valid -- implicitly typed to number<m/s>time+=5<s>;// validtime+=5;// error -- cannot convert number to number<s>time+=distance;// error -- cannot convert number<m> to number<s>// converting to another unit requires asserting to number then the measuretime+=(distanceasnumber)<s>;// validacceleration+=12<m/s**2>;// validacceleration+=10<a>;// validacceleration+=12<m/s**2>*10<s>;// error -- cannot convert number<m/s> to number<a>

Use With Non-Unit of Measure Number Types

Sometimes previously written code or external libraries will return number types without a unit of measure. In these cases, it is useful to allow the programmer to specify the unit like so:

typemeasures;lettime=3<s>;time+=MyOldLibrary.getSeconds();// error -- type 'number' is not assignable to type 'number<s>'time+=MyOldLibrary.getSeconds()<s>;// valid

Dimensionless Unit

A dimensionless unit is a unit of measure defined as number<1>.

letratio=10<s>/20<s>;// implicitly typed to number<1>lettime: number<s>;time=2<s>*ratio;// validtime=time/ratio;// validtime=(ratioasnumber)<s>;// validtime=2<s>+ratio;// error, cannot assign number<1> to number<s>time=ratio;// error, cannot assign number<1> to number<s>time=ratio<s>;// error, cannot assert number<1> to number<s>

Scope

Works the same way as type.

External and Internal Modules

Also works the same way as type.

In addition, if an external library has a definition for meters and another external library has a definition for meters then they should be able to be linked together by doing:

import{masmathLibraryMeterType}from"my-math-library";import{masmathOtherLibraryMeterType}from"my-other-math-library";typemeasurem=mathLibraryMeterType|mathOtherLibraryMeterType;

TODO: The above needs more thought though.

Definition File

Units of measure can be defined in TypeScript definition files ( .d.ts) and can be used by any file that references it. Defining units of measure in a definition file is done just the same as defining one in a .ts file.

Compilation

The units of measure feature will not create any runtime overhead. For example:

typemeasurecm;typemeasurem;letmetersToCentimeters=100<cm/m>;letlength: number<cm>=20<m>*metersToCentimeters;

Compiles to the following JavaScript:

varmetersToCentimeters=100;varlength=20*metersToCentimeters;

Math Library

Units of measure should work well with the current existing Math object.

Some examples:

Math.min(0<s>,4<m>);// error, cannot mix number<s> with number<m> -- todo: How would this constraint be defined?letvolume=Math.pow(2<m>,3)<m**3>;letlength=Math.sqrt(4<m^2>)<m>;

Metadata

Metadata

Assignees

No one assigned

    Labels

    Needs ProposalThis issue needs a plan that clarifies the finer details of how it could be implemented.SuggestionAn idea for TypeScript

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions