숫자를 특정 범위로 제한할 수 있습니까?
2.0 RC(RC)는 숫자 리터럴타입을 할 수 .type t = 1 | 2;
256개의 숫자를 쓰지 않고 0~255 등 숫자 범위로 유형을 제한할 수 있습니까?
제 경우 라이브러리에서 팔레트의 색상 값을 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|...
편집: 오래된 답변입니다.TS > = 4.5에는 이 문제를 해결할 수 있는 도구가 제공되었지만, 사용 사례에 따라 제한되거나 제한되지 않을 수도 있습니다.작은 범위의 경우는, 다음의 답이 유효합니다.
type Enumerate<N extends number, Acc extends number[] = []> = Acc['length'] extends N
? Acc[number]
: Enumerate<N, [...Acc, Acc['length']]>
type IntRange<F extends number, T extends number> = Exclude<Enumerate<T>, Enumerate<F>>
type T = IntRange<20, 300>
----오래된 답변 ----
아니, 가능하지 않아요.그런 종류의 정확한 타입 제약은 타이프스크립트에서는 사용할 수 없습니다(아직은요?
런타임 체크/어세스먼트만이, 다음과 같이 할 수 있습니다.
범위가 작을 경우 항상 다음과 같이 쓸 수 있습니다.
type MyRange = 5|6|7|8|9|10
let myVar:MyRange = 4; // oops, error :)
물론 정수에 대해서만 작동하며 매우 추악합니다. :)
네, 그럴 수도 있어요.UT:
첫 번째.솔루션은 더러운 솔루션이 될 것입니다.두 번째.솔루션은 부분적입니다(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. 부분해법 (출처)
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.하지만, 는 3으로 됩니다.Transformers
,Decorators
등등.
의 함수를 하면, 에서수 있습니다.compiletime
이치노 단, 찬찬에서는runtime
데레데
현재로서는 불가능하지만 GitHub에 미해결 이슈가 있습니다.현재 제안서를 기다리고 있지만 언젠가 이 기능이 제공될 수 있습니다.
즉, 제안서가 나올 때까지 숫자 범위를 유형으로 사용할 수 없습니다.
갱신 - 2021년8월
제안이 존재합니다.자세한 내용은 구간 유형/부등식 유형을 참조하십시오.
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>
업데이트 1
이므로 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
오리진 답변
타입 스크립트 4.1 재귀 조건 타입을 사용하면 가능합니다.
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.
작동은 하지만 실제로 작동하지는 않습니다.:)
최적의 솔루션은 아니지만(일부 체크는 런타임에 처리되기 때문에) "opaque type"은 예상값을 입력하도록 강제하는 데 도움이 됩니다.
다음은 예를 제시하겠습니다.
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);
유효 범위 번호(양 및 정수 범위)가 있는 경우 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>;
음의 범위이지만 제약이 있습니다.범위는 리터럴입니다.왜 그런지 모르겠지만 나는 리터럴한 마이너스 수치를 얻을 수 없었다.아마 누군가는 알고 있을 거야
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>;
256개의 숫자를 입력하지 않고 예를 들어 0-255와 같은 숫자 범위로 유형을 제한할 수 있습니까?
지금까지는 불가능했지만, 라이프핵을 만들어 코드 한 줄과 복사/붙여넣기 결과로 원하는 시퀀스를 생성할 수 있습니다.
new Array(256).fill(0).map((_, i) => i).join(" | ")
편집: 아, 제공된 답변을 충분히 주의 깊게 읽지 않았습니다.@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
꼬리 재귀에 대한 나의 해결책
type BuildArray<
Length extends number,
Ele = unknown,
Arr extends unknown[] = []
> = Arr['length'] extends Length
? Arr
: BuildArray<Length, Ele, [...Arr, Ele]>;
type Add<Num1 extends number, Num2 extends number> = [...BuildArray<Num1>,...BuildArray<Num2>]['length'];
type Subtract<Num1 extends number, Num2 extends number> = BuildArray<Num1> extends [...arr1: BuildArray<Num2>, ...arr2: infer Rest] ? Rest['length'] : never;
type _RangeOf<start extends number, end extends number, R extends unknown[] = [start]> = R['length'] extends Subtract<end, start> ? [...R, end][number] : _RangeOf<start, end, [...R, Add<start, R['length']> ]> ;
type myRange = _RangeOf<2, 7>; // 2, 3, 4, 5, 6, 7
const myRange: myRange = 7;
const myRange2: myRange = 1; // error
const myRange2: myRange = 8; // error
여기를 온라인으로 시험해 보세요.
더 좋은 생각이 있어요.
type NumericRange<
START extends number,
END extends number,
ARR extends unknown[] = [],
ACC extends number = never
> = ARR['length'] extends END
? ACC | START | END
: NumericRange<START, END, [...ARR, 1], ARR[START] extends undefined ? ACC : ACC | ARR['length']>
정적 유형 검사 사용 안 함, 예를 들어 ioT와 같은 라이브러리를 사용할 수 있는 런타임에만 사용taggedUnion
예: https://github.com/gcanti/io-ts/issues/313
type IncrementMap = {
0: 1;
1: 2;
2: 3;
// ...
1233: 1234;
1234: 1234; // To make all values also Incrementable
};
type Incrementable = keyof IncrementMap;
type Increment<N extends Incrementable> = IncrementMap[N];
type Range<
F extends Incrementable,
T extends Incrementable,
A extends number[] = [],
> = F extends T ? A[number] | F : Range<Increment<F>, T, [...A, F]>;
let x: Range<1, 10> = 1;
x = 0; // Error
x = 11; // Error
지도 번호 목록은 여기에서 생성할 수 있습니다.
다른 솔루션과 비교했을 때 어떻습니까?분명한 단점은 이 존재한다는 것이다.IncrementMap
파일을 파일에 저장함으로써 이 문제를 완화합니다.하지만 독특한 장점은 천장이 없다는 것이다.각 범위는 여전히 999개로 제한되어 있지만 더 큰 범위로 구성할 수 있습니다.
type Foo = Range<0, 998> | Range<999, 1997>;
최대 10k까지 테스트했지만, 유일한 제한은 TypeScript가 객체 내에서 허용하는 속성 양이라고 생각합니다(한계치가 있는지는 확실하지 않지만 유일한 제한은 퍼포먼스일 수 있습니다).또한 10만 등 큰 숫자에도 사용할 수 있습니다(만일의 경우 0부터 끝까지 입력할 필요가 없습니다).물론 음수 또한 효과가 있다.
하지만 문자 그대로의 수학이 있으면 훨씬 더 좋을 텐데.
이것은 HTML 텍스트 영역의 높이를 제한하는 데 도움이 되었습니다.테스트 값이 5 범위까지 클리핑됩니다.20.
const rows = Math.min(Math.max(stringArray.length, 5), 20);
언급URL : https://stackoverflow.com/questions/39494689/is-it-possible-to-restrict-number-to-a-certain-range
'programing' 카테고리의 다른 글
mongodb에 json 파일 삽입 (0) | 2023.02.13 |
---|---|
입력 무선 요소를 반응 [material-ui]에서 수평으로 정렬하려면 어떻게 해야 합니까? (0) | 2023.02.13 |
Selenium 유무에 관계없이 Protractor를 실행하는 차이점 (0) | 2023.02.13 |
WordPress 및 정의되지 않은 함수 add_menu_page() 호출 (0) | 2023.02.13 |
고정 AppBar 아래의 콘텐츠 (0) | 2023.02.13 |