扩展Number以获得带有实例方法的标志类型



我想创建一个标志枚举,并在其上放置实例方法。由于这是不可能直接与enum结构,我决定做以下实验:

class SelectionsMade extends Number implements Number {
constructor(value: any) {
super(value);
}
static get None(): SelectionsMade { return new SelectionsMade(0); }
static get StartDate(): SelectionsMade { return new SelectionsMade(1 << 0); }
static get StartTime(): SelectionsMade { return new SelectionsMade(1 << 1); }
static get EndDate(): SelectionsMade { return new SelectionsMade(1 << 2); }
static get EndTime(): SelectionsMade { return new SelectionsMade(1 << 3); }
static startDate(made: boolean): SelectionsMade { return made ? this.StartDate : this.None; }
static startTime(made: boolean): SelectionsMade { return made ? this.StartTime : this.None; }
static endDate(made: boolean): SelectionsMade { return made ? this.EndDate : this.None; }
static endTime(made: boolean): SelectionsMade { return made ? this.EndTime : this.None; }
inclStartDate(): boolean {
return (this.valueOf() & SelectionsMade.StartDate.valueOf()) == SelectionsMade.StartDate.valueOf();
}
inclStartTime(): boolean {
return (this.valueOf() & SelectionsMade.StartTime.valueOf()) == SelectionsMade.StartTime.valueOf();
}
inclEndDate(): boolean {
return (this.valueOf() & SelectionsMade.EndDate.valueOf()) == SelectionsMade.EndDate.valueOf();
}
inclEndTime(): boolean {
return (this.valueOf() & SelectionsMade.EndTime.valueOf()) == SelectionsMade.EndTime.valueOf();
}
removeStartDate(): SelectionsMade {
return new SelectionsMade(this.valueOf() & ~SelectionsMade.StartDate.valueOf());
}
removeStartTime(): SelectionsMade {
return new SelectionsMade(this.valueOf() & ~SelectionsMade.StartTime.valueOf());
}
removeEndDate(): SelectionsMade {
return new SelectionsMade(this.valueOf() & ~SelectionsMade.EndDate.valueOf());
}
removeEndTime(): SelectionsMade {
return new SelectionsMade(this.valueOf() & ~SelectionsMade.EndTime.valueOf());
}
}
let s = new SelectionsMade(SelectionsMade.StartDate | SelectionsMade.EndDate);
console.log(s);

是的,它是一个扩展Number的类,有静态getter来模仿枚举值,还有一些有用的实例方法。这确实在TS playground中打印5,尽管您必须对unknown进行中间强制转换,因此类型检查器是沉默的。

关于这个解决方案我有三个问题:

  1. 如何避免警告,你需要调用valueOf显式TS接受类作为一个数字(解决方法是类型断言,也不太好)?
  2. [意见]你会认为这是一个有效的数字扩展,或者你宁愿去静态的辅助功能,尽管如此?
  3. 有办法写修改函数吗?例如,我有remove*方法,创建一个新值,而不是修改它们的值,尽管后者是可取的。

如何避免警告,您需要显式调用valueOf才能使TS接受类作为数字…

你不能。您的实例是对象,而不是原始数字。您需要使用valueOf(或一元+或类似的)来获得底层的原始数。

…(解决方法是类型断言,也不太好)?

使用类型断言将SelectionsMade的实例视为原语数是不正确的。它只会让TypeScript认为它是一个原始数字,而实际上它仍然是一个对象。这对涉及它的某些操作有影响(不仅仅是typeof n将成为"object"而不是"number")。

有办法写修改函数吗?例如,我有remove*方法来创建一个新值,而不是修改它们所在的值,尽管后者更可取。

Number实例是不可变的。没有办法改变包装实例的基础原语数。你必须创建一个新的实例。

最新更新