microsoft / microsoft/TypeScript
Suggestion: Units of measure
还没有人认领这个 Issue。
- 主要语言
- Go
- 星标
- 111k
- 派生
- 14.3k
- 平均合并
- 2 天 4 小时
- 30 天内合并 PR
- 132
描述
This feature request is similar to units of measure in F#.
For example:
const metres = 125<m>;
const seconds = 2<s>;
let speed: number<m/s>;
speed = metres / seconds; // valid
speed = 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:
type measure <name> [ = measure expression ];
The optional measure expression part can be used to define a new measures in terms of previously defined measures.
Example Definitions
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:
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:
type measure m;
// 1. Explicitly
let distance: number<m> = 12<m>;
// 2. Implictly
let distance = 12<m>;
// 3. Using Number class
let distance = new Number(10)<s>;
TODO: Maybe we shouldn't use the <m> syntax because it might conflict with jsx files.
Detailed Full Example
type measure m;
type measure s;
type measure a = m / s**2;
let acceleration = 12<a>,
time = 10<s>;
let distance = 1/2 * acceleration * (time ** 2); // valid -- implicitly typed to number<m>
let avgSpeed = distance / time; // valid -- implicitly typed to number<m/s>
time += 5<s>; // valid
time += 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 measure
time += (distance as number)<s>; // valid
acceleration += 12<m / s**2>; // valid
acceleration += 10<a>; // valid
acceleration += 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:
type measure s;
let time = 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>.
let ratio = 10<s> / 20<s>; // implicitly typed to number<1>
let time: number<s>;
time = 2<s> * ratio; // valid
time = time / ratio; // valid
time = (ratio as number)<s>; // valid
time = 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 {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:
type measure cm;
type measure m;
let metersToCentimeters = 100<cm / m>;
let length: number<cm> = 20<m> * metersToCentimeters;
Compiles to the following JavaScript:
var metersToCentimeters = 100;
var length = 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?
let volume = Math.pow(2<m>, 3)<m**3>;
let length = Math.sqrt(4<m^2>)<m>;
贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
调研方向
首先审阅提案中关于语法、类型检查、模块、定义文件、编译和 Math-library 的部分,包括标记为需要进一步思考的问题。在实现之前,先确定这些未解决设计问题的可接受行为和范围,然后定义能够展示所提议的有效示例和无效示例的测试。
由索引模型根据 Issue 内容生成。
评估
- 技术栈
- typescript
- 领域
- compilers
- Issue 类型
- 功能
- 难度
- 5/5
- 预计耗时
- 一周以上
- 活跃度
- 停滞
- 描述清晰度
- 需要澄清
- 新手友好度
- 20/100