【问题标题】:How do you emulate nominal typing in TypeScript?你如何在 TypeScript 中模拟名义打字?
【发布时间】:2018-08-21 22:38:57
【问题描述】:

我的项目中有许多以数字为参数的函数;这个数字一半时间是数组的索引,另一半时间是光标位置(数组中两个条目之间的点)。这会导致混淆,即使使用命名约定也是如此。

我想强制以下函数采用预期的名义类型。

class Index extends Number {}
class CursorPosition extends Number {}

function getElement(i: Index) {}
function getRange(p1: CursorPosition, p2: CursorPosition) {}

const myIndex: Index = 6;
const myPosition: CursorPosition = 6;

getElement(1); // would like this to fail at compile time
getRange(2, 3); // would like this to fail at compile time
getElement(myPosition); // would like this to fail at compile time
getRange(myIndex, myIndex); // would like this to fail at compile time

getElement(myIndex); // would like this to pass at compile time
getRange(myPosition, myPosition); // would like this to pass at compile time

我知道 typescript 使用结构化类型,这就是为什么这不会“开箱即用”发生。

另外,我考虑了对变量进行装箱和添加任意属性:

class myNum extends Number { 
  l: "1";
}

或使用演员表。

class myNum { 
  arb: "arbitrary property value";
}

const mn2: myNum = <any>8;

function getElement2(a: any[], i: myNum) {
  return a[<any>i];
}

getElement2([], mn2);
getElement2([], 6);

有更好的想法吗?

【问题讨论】:

    标签: typescript casting type-conversion


    【解决方案1】:

    您可以使用品牌类型:

    type Index =  Number & { __type: 'Index'}
    type CursorPosition =  Number & { __type: 'CursorPosition'}
    
    
    function getElement(i: Index) {}
    function getRange(p1: CursorPosition, p2: CursorPosition) {}
    
    function indexFromNumber(n: number) :Index {
        return n as any;
    }
    
    function cursorPositionFromNumber(n: number): CursorPosition {
        return n as any;
    }
    
    const myIndex: Index = indexFromNumber(6);
    const myPosition: CursorPosition = cursorPositionFromNumber(6);
    
    getElement(1); // error
    getRange(2, 3);  // error
    getElement(myPosition);  // error
    getRange(myIndex, myIndex); // error
    
    getElement(myIndex); // ok 
    getRange(myPosition, myPosition); //ok 
    

    您需要定义一个辅助函数来创建类型的实例或使用类型断言 (const myIndex = 1 as any as Index),但如果您传递一个简单的数字,调用站点会出错。

    article 对此主题进行了更多讨论。打字稿编译器也将这种方法用于paths

    【讨论】:

    • TypeScript 在其路线图的“未来”部分中具有名义类型。 github.com/Microsoft/TypeScript/wiki/Roadmap
    • @bnieland 是的,票已经飘了一段时间了,我们看看会发生什么:)
    • 我已经使用了这个 q 几次并且对结果非常满意。通常,您可以使用名义类型代替基本类型,但不能反过来(不进行强制转换)。
    猜你喜欢
    • 1970-01-01
    • 2017-10-05
    • 2016-02-02
    • 1970-01-01
    • 2021-07-18
    • 1970-01-01
    • 2010-10-13
    • 1970-01-01
    相关资源
    最近更新 更多