由于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|...
Run Code Online (Sandbox Code Playgroud)
Gui*_*tio 58
Typescript 4.5 可以对条件类型进行尾递归消除。
type Enumerate<N extends number, Acc extends number[] = []> = Acc['length'] extends N
? Acc[number]
: Enumerate<N, [...Acc, Acc['length']]>
type Range<F extends number, T extends number> = Exclude<Enumerate<T>, Enumerate<F>>
type T = Range<20, 100>
Run Code Online (Sandbox Code Playgroud)
Ada*_*myd 36
如果你的范围很小,你总是可以这样写:
type MyRange = 5|6|7|8|9|10
let myVar:MyRange = 4; // oops, error :)
Run Code Online (Sandbox Code Playgroud)
当然它只适用于整数而且很丑陋:)
tit*_*sfx 26
是的,这是可能的,但是:
第一个。解决方案将是一个肮脏的解决方案 2。解决方案将是部分的(从 x 到 y,其中 y 是一个小数,在我的情况下为 43) 第三个。解决方案将是一个完整的解决方案,但真正推进变压器、装饰器等。
1.使用@Adam-Szmyd解决方案的肮脏解决方案(最简单快速的方法):
type RangeType = 1 | 2 | 3
Run Code Online (Sandbox Code Playgroud)
如果您需要广泛的范围,只需打印和复制/粘贴:
type RangeType = 1 | 2 | 3
Run Code Online (Sandbox Code Playgroud)
你可能不愿意做这样的事情
const data = [1, 2, 4, 5, 6, 7] as const;
type P = typeof data[number];
Run Code Online (Sandbox Code Playgroud)
而是使用函数
const rangeType20 = Array.from(Array(20).keys()) as const;
Run Code Online (Sandbox Code Playgroud)
但目前这不起作用,只有在是文字时才有效。甚至错误也不完全正确。
2.部分解决方案(来源)

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>;
Run Code Online (Sandbox Code Playgroud)
3.完整的解决方案,但真正与推进Transformers,Decorators等等。
使用第一个解决方案中的函数,您可以compiletime使用转换器将 at 替换为值。同样,但runtime使用装饰器。
Dea*_* Xu 21
从 typescript v4.5 开始添加tail recursive evaluation of conditional types.问题链接
现在最大数量可以是998。这对于你的问题来说已经足够了。
type Ran<T extends number> = number extends T ? number :_Range<T, []>;
type _Range<T extends number, R extends unknown[]> = R['length'] extends T ? R[number] : _Range<T, [R['length'], ...R]>;
type R5 = Ran<998>
const a: R5 = 3 // correct
const b: R5 = 999 // wrong
Run Code Online (Sandbox Code Playgroud)
现在可以使用 Typescript 4.1递归条件类型
type Ran<T extends number> = number extends T ? number :_Range<T, []>;
type _Range<T extends number, R extends unknown[]> = R['length'] extends T ? R[number] : _Range<T, [R['length'], ...R]>;
type R5 = Ran<998>
const a: R5 = 3 // correct
const b: R5 = 999 // wrong
Run Code Online (Sandbox Code Playgroud)
但不幸的是,如果你的长度太长,递归类型就会失败
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'.
Run Code Online (Sandbox Code Playgroud)
嗯,它有效,但实际上并不有效。:)
Ale*_*exG 19
不,这是不可能的.打字稿中没有这种精确的类型约束(但是?)
只有运行时检查/断言才能实现:(
虽然不是最好的解决方案(因为一些检查将在运行时处理),但值得一提的是“不透明类型”可以帮助强制您输入预期值。
下面是一个例子:
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);
Run Code Online (Sandbox Code Playgroud)
带验证范围数字(正数和整数范围) ts 4.6.3
type IsPositive<N extends number> = `${N}` extends `-${string}` ? false : true;
type IsInteger<N extends number> = `${N}` extends `${string}.${string}`
? never
: `${N}` extends `-${string}.${string}`
? never
: number;
type IsValid<N extends number> = IsPositive<N> extends true
? IsInteger<N> extends number
? number
: never
: never;
type PositiveNumber<
N extends number,
T extends number[] = []
> = T["length"] extends N ? T[number] : PositiveNumber<N, [...T, T["length"]]>;
type Range<N1 extends IsValid<N1>, N2 extends IsValid<N2>> = Exclude<
PositiveNumber<N2>,
PositiveNumber<N1>
>;
type RangeType = Range<1, 5>;
Run Code Online (Sandbox Code Playgroud)
这里的范围为负,但有一些限制。范围是文字。我不知道为什么,但我无法得到不是字面上的负数。也许有人知道warraround
type IsInteger<N extends number> = `${N}` extends `${string}.${string}`
? never
: `${N}` extends `-${string}.${string}`
? never
: number;
type NegativeLiteralNumbers<
N extends number,
T extends string[] = []
> = `${N}` extends `-${string}`
? `-${T["length"]}` extends `${N}`
? T[number]
: NegativeLiteralNumbers<N, [...T, `-${T["length"]}`]>
: never;
type PositiveLiteralNumber<
N extends number,
T extends string[] = []
> = `${N}` extends `${string}`
? T["length"] extends N
? T[number]
: PositiveLiteralNumber<N, [...T, `${T["length"]}`]>
: never;
type RangeLiteralNegative<F extends number, T extends number> = Exclude<
NegativeLiteralNumbers<F>,
NegativeLiteralNumbers<T>
>;
type RangeLiteralPositive<F extends number, T extends number> = Exclude<
PositiveLiteralNumber<T>,
PositiveLiteralNumber<F>
>;
type RangeLiteral<N1 extends IsInteger<N1>, N2 extends IsInteger<N2>> =
| (`${N1}` extends `-${string}`
? RangeLiteralNegative<N1, 0>
: `${N1}` extends `${string}`
? RangeLiteralPositive<0, N1>
: never)
| (`${N2}` extends `-${string}`
? RangeLiteralNegative<N2, 0>
: `${N2}` extends `${string}`
? RangeLiteralPositive<0, N2>
: never);
type RangeLiteralType = RangeLiteral<-5, 3>;
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
14786 次 |
| 最近记录: |