你如何在TypeScript中模拟名义输入?

问题描述 投票:2回答:1

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

我想强制执行以下功能正在采用预期的名义类型。

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

我知道打字稿使用结构类型,这就是为什么这不会“开箱即用”。

另外,我考虑过装箱变量并添加任意属性:

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个回答
11
投票

您可以使用品牌类型:

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对这个主题进行了更多的讨论。 typescript编译器也将此方法用于paths

© www.soinside.com 2019 - 2024. All rights reserved.