Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/dsherret/units-of-measure-proposal-for-typescript


https://github.com/dsherret/units-of-measure-proposal-for-typescript

Last synced: 13 days ago
JSON representation

Awesome Lists containing this project

README

        

Units of Measure: Proposal for TypeScript
=========================================

[![experimental](http://badges.github.io/stability-badges/dist/experimental.svg)](http://github.com/badges/stability-badges)

[Read the issue](https://github.com/Microsoft/TypeScript/issues/364)

## Overview

Units of measure is a useful [F# feature](http://msdn.microsoft.com/en-us/library/dd233243.aspx) 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:

```typescript
type measure [ = measure expression ];
```

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

### Example Definitions

```typescript
type measure m;
type measure s;
type measure a = 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:

```typescript
type measure a = b;
type measure b = a; // error
```

## Use with Number

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

```typescript
type measure m;

// 1. Explicitly
let distance: number = 12;
// 2. Implictly
let distance = 12;
// 3. Using Number class
let distance = new Number(10);
```

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

## Detailed Full Example

```typescript
type measure m;
type measure s;
type measure a = m / s**2;

let acceleration = 12,
time = 10;

let distance = 1/2 * acceleration * (time ** 2); // valid -- implicitly typed to number
let avgSpeed = distance / time; // valid -- implicitly typed to number

time += 5; // valid
time += 5; // error -- cannot convert number to number
time += distance; // error -- cannot convert number to number

// converting to another unit requires asserting to number then the measure
time += (distance as number); // valid

acceleration += 12; // valid
acceleration += 10
; // valid
acceleration += 12 * 10; // error -- cannot convert number to number

```

### 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:

```typescript
type measure s;

let time = 3;

time += MyOldLibrary.getSeconds(); // error -- type 'number' is not assignable to type 'number'
time += MyOldLibrary.getSeconds(); // valid
```

## Dimensionless Unit

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

```typescript
let ratio = 10 / 20; // implicitly typed to number<1>
let time: number;

time = 2 * ratio; // valid
time = time / ratio; // valid
time = (ratio as number); // valid
time = 2 + ratio; // error, cannot assign number<1> to number
time = ratio; // error, cannot assign number<1> to number
time = ratio; // error, cannot assert number<1> to number
```

## 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:

```typescript
import {m as mathLibraryMeterType} from "my-math-library";
import {m as mathOtherLibraryMeterType} from "my-other-math-library";

type measure m = 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:

```typescript
type measure cm;
type measure m;

let metersToCentimeters = 100;
let length: number = 20 * metersToCentimeters;
```

Compiles to the following JavaScript:

```typescript
var metersToCentimeters = 100;
var length = 20 * metersToCentimeters;
```

## Math Library

Units of measure should work well with the current existing [Math object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math).

Some examples:

```typescript
Math.min(0, 4); // error, cannot mix number with number -- todo: How would this constraint be defined?

let volume = Math.pow(2, 3);
let length = Math.sqrt(4);
```