由于typescript 2.0 RC(甚至是beta?),因此可以使用数字文字类型,如type t = 1 | 2;
中所示。是否可以将类型限制为数字范围,例如0-255,没有在类型中写出256个数字?
在我的情况下,库接受0-255的调色板的颜色值,我更喜欢只列举几个,但将其限制为0-255:
const enum paletteColor {
someColor = 25,
someOtherColor = 133
}
declare function libraryFunc(color: paletteColor | 0-255); //would need to use 0|1|2|...
答案 0 :(得分:28)
如果你的范围很小,你总是可以这样写:
type MyRange = 5|6|7|8|9|10
let myVar:MyRange = 4; // oops, error :)
当然它只适用于整数而且很丑陋地说:)
答案 1 :(得分:10)
不,这是不可能的。这种精确的类型约束在typescript中没有(但是?)
只有运行时检查/断言才能实现:(
答案 2 :(得分:6)
暂时不可能,但是有一个open issue on GitHub。 目前,他们仍在等待提案,但是此功能可能有一天会出现。
简而言之,除非提出建议,否则您将无法使用一系列数字作为类型。
答案 3 :(得分:6)
是的,有可能但:
第一。解决方案将是肮脏的解决方案 第二。解决方案将是局部的(从x到y,其中y是一个小数,在我的情况下为43) 第三。该解决方案将是一个完整的解决方案,但在变形金刚,装饰器等方面确实会进步。
1。使用@ Adam-Szmyd解决方案的肮脏解决方案(最简便快捷的方法):
type RangeType = 1 | 2 | 3
如果您需要广泛的产品,只需打印并复制/粘贴即可:
// Easiest just incremental
let range = (max) => Array.from(Array(max).keys()).join(" | ");
console.log('Incremental')
console.log(range(20))
// With range and steps
let rangeS = (( min, max, step) => Array.from( new Array( max > min ? Math.ceil((max - min)/step) : Math.ceil((min - max)/step) ), ( x, i ) => max > min ? i*step + min : min - i*step ).join(" | "));
console.log('With range and steps')
console.log(rangeS(3,10,2))
您可能会喜欢做这样的事情
const data = [1, 2, 4, 5, 6, 7] as const;
type P = typeof data[number];
但是使用函数
const rangeType20 = Array.from(Array(20).keys()) as const;
但是目前这不起作用,只有在字面意义上才起作用。甚至错误也不是很正确。
2。部分解决方案(source)
type PrependNextNum<A extends Array<unknown>> = A['length'] extends infer T ? ((t: T, ...a: A) => void) extends ((...x: infer X) => void) ? X : never : never;
type EnumerateInternal<A extends Array<unknown>, N extends number> = { 0: A, 1: EnumerateInternal<PrependNextNum<A>, N> }[N extends A['length'] ? 0 : 1];
export type Enumerate<N extends number> = EnumerateInternal<[], N> extends (infer E)[] ? E : never;
export type Range<FROM extends number, TO extends number> = Exclude<Enumerate<TO>, Enumerate<FROM>>;
type E1 = Enumerate<43>;
type E2 = Enumerate<10>;
type R1 = Range<0, 5>;
type R2 = Range<0, 43>;
3。完整的解决方案,但实际上可以使用Transformers
,Decorators
等来实现。
使用第一个解决方案中的函数,您可以使用转换器用compiletime
的值替换这些值。同样,但在runtime
上使用修饰符。
答案 4 :(得分:4)
虽然不是最佳解决方案(因为一些检查将在运行时处理),但值得一提的是 "opaque types" 可以帮助强制您输入预期值。
举个例子:
type RGBColor = number & {_type_: "RGBColor"};
const rgb = (value: number): RGBColor => {
if (value < 0 || value > 255) {
throw new Error(`The value ${value} is not a valid color`);
}
return value as RGBColor;
};
// Compiler errors
const color1: RGBColor = 200; // fail - number is not RGBColor
const color2: RGBColor = 300; // fail - number is not RGBColor
// Runtime error
const color3: RGBColor = rgb(300); // fail - The value 300 is not a valid color
// Pass
const color4: RGBColor = rgb(100);
const color5: RGBColor = rgb(255);
答案 5 :(得分:3)
是否可以将类型限制为数字范围,例如0-255,而不写出256个数字吗?
到现在为止不可能,但是您可以进行一次生活破解,并用一行代码和复制/粘贴结果生成所需的序列
new Array(256).fill(0).map((_, i) => i).join(" | ")
答案 6 :(得分:2)
编辑:啊,我没有仔细阅读提供的答案! @titusfx 已经以另一种形式提供了这个答案。 与他的方法一样,这在您可以生成的数字数量方面受到限制。这不是一个实际的解决方案,而是一种适用于非常有限的数字范围的解决方法!
原答案:
对此有一个解决方法。借鉴答案 https://stackoverflow.com/a/52490977(将此解决方案限制为 TypeScript v 4.1 及更高版本):
type _NumbersFrom0ToN<
Nr extends number
> =
Nr extends Nr ?
number extends Nr ?
number :
Nr extends 0 ?
never :
_NumbersFrom0ToNRec<Nr, [], 0> :
never;
type _NumbersFrom0ToNRec<
Nr extends number,
Counter extends any[],
Accumulator extends number
> =
Counter['length'] extends Nr ?
Accumulator :
_NumbersFrom0ToNRec<Nr, [any, ...Counter], Accumulator | Counter['length']>;
type NrRange<
Start extends number,
End extends number
> =
Exclude<_NumbersFrom0ToN<End>, _NumbersFrom0ToN<Start>>;
let nrRange: NrRange<14, 20>;
创建 14 | 15 | 16 | 17 | 18 | 19
类型。为了完成这项工作,我们只需要利用 TypeScript 可以通过新改进的元组类型检查的长度属性进行计数的功能。所以我们只是扩展一个数组,只要数组的长度和输入的数字不一样。当我们扩展数组时,我们会记住我们已经访问过的长度。这反过来又会产生一个带有额外步骤的计数器。
编辑:我将这些类型放在一个包中以便于重用:https://www.npmjs.com/package/ts-number-range
答案 7 :(得分:1)
不使用静态类型检查,仅在运行时使用例如io-ts之类的库
例如,您可以在其中使用taggedUnion
的位置:
https://github.com/gcanti/io-ts/issues/313
答案 8 :(得分:0)
我建议使用类似这样的东西:
class Cinema {
private openingHour: number;
constructor(openingHour: 5 | 6 | 7) {
this.openingHour = openingHour;
}
}
let yesPlanet = new Cinema(9);
当您使用值“ 9”初始化yesPlanet时,会收到错误消息,因为它超出范围。 希望有帮助。
答案 9 :(得分:0)
我不认为仍然存在“简便”的方法。我在这里阅读了很多评论:https://github.com/microsoft/TypeScript/issues/15480一些非常好的主意,但有很多事情要考虑。
答案 10 :(得分:0)
现在可以使用 Typescript 4.1 Recursive Conditional Types
type Range<T extends number> = number extends T ? number :_Range<T, []>;
type _Range<T extends number, R extends unknown[]> = R['length'] extends T ? R['length'] : R['length'] | _Range<T, [T, ...R]>;
type R5 = Range<5>
const a: R5 = 3 // correct
const b: R5 = 8 // error. TS2322: Type '8' is not assignable to type '0 | 1 | 2 | 3 | 4 | 5'.
但不幸的是,如果你的长度太长,递归类型就会失败
type R23 = Range<23>
// TS2589: Type instantiation is excessively deep and possibly infinite.
嗯,它有效,但不是真的有效。 :)