Typescript: 提案数倀タむプずしおの範囲

䜜成日 2017幎04月30日  Â·  106コメント  Â·  ゜ヌス: microsoft/TypeScript

タむプを定矩するずき、 |区切られた耇数の数倀を指定できたす。

type TTerminalColors = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15;

各数倀を䞀芧衚瀺する代わりに、数倀タむプを範囲ずしお指定できるようにしたす。

type TTerminalColors = 0..15;
type TRgbColorComponent = 0..255;
type TUInt = 0..4294967295;

たぶん、敎数には..を䜿甚し、浮動小数点数には...を䜿甚したす。

interface Math {
  random(): 0...1
}
In Discussion Suggestion

最も参考になるコメント

このアむデアは文字に拡匵できたす。たずえば、 "b".."d"は"b" | "c" | "d"たす。 文字セットを指定する方が簡単です。

党おのコメント106件

このアむデアは文字に拡匵できたす。たずえば、 "b".."d"は"b" | "c" | "d"たす。 文字セットを指定する方が簡単です。

これは拡匵しお、Haskellの範囲のような構文やセマンティクスを䜿甚できるず思いたす。

| 構文| 脱糖|
| -------------------------- | ---------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- ------------------------------------------ |
| type U = (e1..e3) | type U = \| e1 \| e1+1 \| e1+2 \| ...e3 \|
e1 > e3堎合、ナニオンはneverです|
| type U2 = (e1, e2..e3) | type U2 = \| e1 \| e1+i \| e1+2i \| ...e3 \| 、
ここで、増分iはe2-e1です。

増分が正たたはれロの堎合、次の芁玠がe3より倧きくなるず、ナニオンは終了したす。
e1 > e3堎合、和集合はneverです。

増分が負の堎合、次の芁玠がe3未満になるず、ナニオンは終了したす。
e1 < e3堎合、ナニオンはneverです。 |

@panuhorsmalahti "bb".."dd"を指定するずどうなりたすか

@streamich

たぶん、敎数には..を䜿甚し、浮動小数点数には...を䜿甚したす。

このような敎数型を生成するずいうアむデアは本圓に奜きですが、浮動小数点倀がどのように機胜するかわかりたせん。

@aluanhaddad確率を蚀う

type TProbability = 0.0...1.0;

@streamichで、そのタむプには理論的に無限の数の可胜な䜏民がいたすか

@aluanhaddadは、実際にはIEEE浮動小数点で無限にはほど遠いでしょう。 私の蚈算では、1,065,353,217人の䜏民がいるでしょう。

0.0...1.0  JSはIEEEdoubleを䜿甚したす。これは、53ビットのダむナミックレンゞです。 それがサポヌトされるずしたら、範囲はファヌストクラスの型でなければならず、それを組合に脱糖するこずは非珟実的ではありたせん。

@jcreadyは確かですが、 @ fatcerberusが指摘しおいるように、それを共甚䜓型ずしお実珟するこずは非垞に広倧です。

私が埗おいたのは、回りくどい方法で、これが蚀語に離散型ず連続型の抂念を導入するずいうこずでした。

共甚䜓型ずしおそれを実珟するこずは、法倖に広倧です。

@aluanhaddadはい。ただし、笊号なし敎数を和集合ずしお指定するこずでさえ、非垞にコストがかかりたす。

type TUInt = 0..4294967295;

今日のナニオンの実装は、これほど倧きなナニオンを実珟するにはたったく適しおいないため、これにはいく぀かの説埗力のあるナヌスケヌスが本圓に必芁です。 このようなこずを曞いたらどうなるか

type UInt = 0..4294967295;
var x: UInt = ......;
if (x !== 4) {
  x;
}

共甚䜓型0 | 1 | 2 | 3 | 5 | 6 | 7 | ...のむンスタンス化になりたす。

おそらく、それは数倀リテラルに察しおのみ機胜する可胜性がありたす。 リテラル以倖の数倀は、範囲内に存圚するず芋なされる前に、比范よりも倧きい/小さい倀で明瀺的に調敎する必芁がありたす。 敎数範囲には、远加のNumber.isInteger()チェックも必芁になりたす。 これにより、実際の共甚䜓型を生成する必芁がなくなりたす。

@RyanCavanaugh枛算タむプ 🌞

吊定型、型吊定。

文字列以倖のもの

type NotAString = !string;

れロ以倖の任意の数

type NonZeroNumber = number & !0;

@streamich枛算タむプは4183でカバヌされおいたす

私のナヌスケヌスは次のずおりです。パラメヌタを0たたは正の数配列むンデックスずしお入力したいず思いたす。

@RoyTinkerこれは間違いなくクヌルだず思いたすが、そのナヌスケヌスが議論に圹立぀かどうかはわかりたせん。
配列は単なるオブゞェクトであり、昇順のむンデックスは単なる慣䟋です。

let a = [];
for (let i = 0; i > -10; i -= 1) {
  a[i] = Math.random() * 10;
}

したがっお、最終的には同じチェックを実行する必芁がありたす

function withItem<T>(items: T[], index: number, f: (x: T) => void) {
  if (items[index]) {
    f(items[index]);
  }
}

秒、分、時、日、月などのタむプを定矩するのに非垞に圹立ちたす。

@Frikkiこれらのナニットは十分に制限された間隔にあるため、手で曞くのは実甚的で非垞に困難です。

type Hour =
   | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
   | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23;

@aluanhaddadしかし、unsigned intはありたせん

type UInt = 0..4294967295;

ああ、このようなタむプはどうですか

type Factorial<N extends number> = N > 2 ? Factorial<N - 1> * N : N;
type F1 = Factorial<1>; // 1
type F2 = Factorial<2>; // 1 | 2
type F3 = Factorial<3>; // 1 | 2 | 6
type FN = Factorial<number>; // 1 | 2 | 6 | ... 

@ aleksey-bykovコメントの*挔算子の䜿甚

type char = 0..255;
type word = char ** 2;
type int = word ** 2;
type bigint = int ** 2;

@streamichビットカりントを2倍にするこずは、2の乗算に察応したせん。これは、指数ずしお2を䜿甚するべき乗に䌌おいたす。 ただし、䞊限を匕き䞊げるべきではないため、ただ正しくありたせんが、゚ンコヌド可胜な数倀は重芁です。 党䜓ずしお、それは良い定矩戊略ではありたせん。

@streamich 、いく぀かのコメント

  • char 、 wordなどの甚語を䜿甚するず、他の蚀語の人々が静的定矩ず実行時の動䜜の違いに気付かない可胜性があるため、混乱する可胜性がありたす。
  • 提案された構文は䞋限を考慮しおいたせん-れロ以倖の堎合はどうなりたすか
  • 指数挔算子はすでにES2016に远加されおいるため、アンビ゚ント/タむプのコンテキストで䜿甚するためにべき乗挔算子を採甚するこずには泚意が必芁です。

型システムのチュヌリングを完了させお、 Ctrl + Shift + B達したずきの停止問題を楜しんでみたしょう。

@ aleksey-bykov確かにあなたはこの玠晎らしい問題を芚えおいたす😀

@aluanhaddad

それらの単䜍[時間単䜍]は十分に制限された間隔にあるため、手で曞くこずは実甚的で非垞に困難です。

https://github.com/Microsoft/TypeScript/issues/15480#issuecomment -349270853

さお、ミリ秒でそれを行いたすwink

この問題は死んでいたすか

@Palidそれは[Needs Proposal]タグ付けされおいるので、私

議論は楜しいものでしたが、私たちのほずんどは、説埗力のある実際のナヌスケヌスを提䟛できおいたせん。

https://github.com/Microsoft/TypeScript/issues/15480#issuecomment-324152700を参照しお

__ナヌスケヌス__

  1. TypeScriptのサブセットをWebAssemblyたたはその他のタヌゲットにコンパむルできるように、正確なint型を定矩できたす。

  2. 別の䜿甚䟋は、 UInt8Array 、 Int8Array 、 Uint16Arrayなどです。これらのTypeScriptからデヌタを読み曞きするず、゚ラヌがチェックされる可胜性がありたす。

const ab = new ArrayBuffer(1e3);
const uint8 = new UInt8Array(ab);

uint8[0] = 0xFFFFFFFF; // TSError: Number too big!
  1. OPでいく぀かのナヌスケヌスに぀いお説明したした。

  2. これを実装するず、TypeScriptコミュニティは䜕癟䞇ものナヌスケヌスを思い付くでしょう。

私は本圓に面癜いナヌスケヌスを持っおいたす、それは実際にここで提案された他のものに近いかもしれたせん。
APIはある範囲私の堎合は5-30の間の敎数を取り、そのためのSDKを実装する必芁がありたす。
䞋に手動で曞き蟌むこずは、25個の倀に察しお少し自動化するこずはできたすが面倒ですが、数癟たたは数千はどうでしょうか
type X = 5 | 6 | 7 | 8 | 9 | 10 ... | 30

@Palidこれは、この機胜に぀いお私が芋た䞭で最も簡単なケヌスです。

以䞋のような範囲ならば5..30ためのシンタックスシュガヌずしお定矩された5 | 6 | 7 ... | 30 同様に、それたでたたは機胜私は、これは簡単に勝぀だろう賭けたす。 ここでは、敎数の離散範囲を衚したす。

おそらく、離散ではなく連続範囲は、ピリオド付きの数倀 5.0..30.0 を䜿甚しお衚蚘できたす。

私は実際にTypescriptを芋おタむピング保護を実装するこずを怜蚎しおいたした
https://www.npmjs.com/package/memory-efficient-object

範囲タむピングを䜿甚するず、タむプチェック時に朜圚的なメモリオヌバヌフロヌを簡単に芋぀けるこずができたす。

ナニオン拡匵は実際には必芁ないようですが、範囲を比范するだけの包括的/排他的範囲定矩のようです

type TTerminalColors = int & [0,15];
// int && v >= 0 && v <= 15

これは、速床が0〜255の範囲のモヌタヌを制埡する堎合たずえば、Johnny-Fiveを䜿甚に非垞に圹立ちたす。

別の䜿甚䟋TypeScriptを䜿甚しおCanvasベヌスの描画プログラムを実装しおいお、䞍透明床0.0〜1.0の数倀である必芁がありたすの型チェックを行いたいず考えおいたす。

考えおいるだけです...これを適切に実装するには、本圓にすべおを尜くす必芁がありたす。

  • ランタむムタむプのガヌド機胜をサポヌトする
  • x <= 10ような条件の型の絞り蟌み
  • サポヌトstring | number範囲以降x == 5あるtrueのためにx === "5"数のみの範囲に加えお
  • おそらく、新しいintタむプ numberサブタむプのサポヌト、およびintのみずstring | int範囲のサポヌトです。 たた、 x|0ような匏の絞り蟌みも入力したす

玠晎らしいアむデアですが、それをカバヌするのは倧倉です

たぶん、ランタむムタむプガヌドは必芁ありたせん。 代わりに、コンパむル時をずっずガヌドするこずができたす

これには、代わりに耇雑な分岐予枬が必芁になりたす

仮定する

type TTerminalColors = int & [0,15];

function A(color: TTerminalColors):void
{

}

A(15); // OK
var x = 15;
A(x); // OK

function B(value: int) : void
{
    A(value); // ERROR!!!
    if(value >= 0 && value <= 15)
        A(value); // OK, because we check that it is in the range of TTerminalColors
}

function C(value: int) : void
{
    if(value < 0)
        value = 0;
    if(value > 15)
        value = 15;

    A(value); // OK, because is clamped. But maybe too hard to implemented
}

function ClampInt(value: int): TTerminalColors
{
    if(value >= 0 && value <= 15)
        return value; // Same as B(int)

    if(value > 15)
        return 15;

    return 0;
}

私のナヌスケヌス

export const ajax: (config: AjaxOptions) => void;

type Callback = Success | Error;
type Success = (data: any, statusText: string, xhr: XMLHttpRequest) => void;
type Error = (xhr: XMLHttpRequest, statusText: string) => void;

interface AjaxOptions {
  // ...
  statusCode: { [code: number]: Callback | Callback[] },
  // ...
}

statusCodeオプションのキヌを制限しお、コンパむル時にステヌタスコヌドが成功コヌドたたぱラヌコヌドに察応するかどうかを刀断できるようにするず䟿利です。

interface AjaxOptions {
  // ...
  statusCode: {
    200..300: Success,
    400..600: Error
  },
  // ...
}

IMOこれは、浮動小数点数ず敎数に制限する必芁があり、共甚䜓ずしお実装するのではなく、新しい範囲タむプずしお実装する必芁がありたす。 その堎合、型チェックは次のように簡単になりたす。

if (val >= range.start && val < range.end) {
  return match;
} else {
  return no_match;
}

私たちは、おそらく、Rubyの本から葉を取り、䜿甚するこずができたす..包括範囲に぀いお [start, stop] ず...非包括的範囲に぀いおは [start, stop) 。

もう1぀の䜿甚䟋は、デヌタベヌスレコヌドをタむプチェックするこずです。

もう1぀の䜿甚䟋は、Lat / Lon倀の型チェックです。

これは、8665の䞀般的な怜蚌メカニズムでカバヌできたす重耇ずしお閉じられた理由はわかりたせん。

type TTerminalColors (n: number) => Math.floor(n) == n && n >= 0 && n <= 15;
type TRgbColorComponent (n: number) => Math.floor(n) == n && n >= 0 && n <= 255;
type TUInt (n: number) => n >= 0 && n <= 0..4294967295;

たたは、4639で取埗し、笊号なし敎数型がuintずしお定矩されおいるず仮定したす。

type TTerminalColors (n: uint) => n <= 15;
type TRgbColorComponent (n: uint) => n <= 255;

私のナヌスケヌスはグロヌバル座暙です。 緯床ず経床を入力しお、特定の範囲-90から90および-180から180にのみ収たるようにしたす。

線集latずlongは負の範囲を持っおいたす

私のナヌスケヌスは、サむズがパラメヌタヌである固定サむズの配列の実装です。

たずえば、長さ2の文字列の配列の型を定矩したいず思いたす。

let d: FixedSizeArray<2, string>;
d = [ 'a', 'b' ]; // ok
d = [ 'a' ]; // type error
d = [ 'a', 'b', 'c' ]; // type error
d[0] = 'a1'; // ok
d[1] = 'b1'; // ok
d[2] = 'c1' // type error

TSの珟圚のバヌゞョンでは、䞊蚘の「仕様」に非垞に近いものを定矩するこずが可胜です。 䞻な問題はメンバヌアクセスです。たずえば、 d[1] = 'b1'は、正しい堎合でもタむプ゚ラヌを返したす。 ゚ラヌを回避するために、すべおの正圓なむンデックスのリストをFixedSizeArrayの定矩に手動でコンパむルする必芁がありたすが、これは退屈です。

range挔算子に䌌たkeyof挔算子がある堎合、次の型定矩で問題を解決できたす。

type FixedSizeArray<U extends number, T> = {
    [k in range(U)]: T;
} & { length: U };

ここで、 range(N)はrange(0,N)ショヌトカットです。

䞎えられた数倀リテラルナチュラルM、N、M <N、

type r = range(M, N); 

ず同等です

type r = M | M+1 | ... | N-1

より䞀般的なのは、述語ラムダを定矩しおそれらを型ずしお䜿甚できるかどうかです。 䟋

predicate mypredicate = (x) => x > 1 && x < 10 
let x: mypredicate = 11 // not ok
let x: mypredicate = 5 // ok

ラムダはすでに利甚可胜であるため、プロは構文の耇雑さが䜎くなりたす。必芁なのは、ラムダを型ずしお䜿甚する機胜だけです。型チェックは、ずにかく型スクリプト固有です「Javascriptぞのスヌパヌセット」の哲孊を念頭に眮いおください
短所は、述語の耇雑さがフィヌドバックを提䟛するためのツヌルのパフォヌマンスを決定するずいうこずです。

数倀/文字が等差数列に属するこずを確認するこずは、䞀般的なナヌスケヌスずしお適しおいたす。

// a is the starting element d is the difference between two elements and L is the last element
const belongsToAP = (a, d, L) => {
  return (x) => {
    if(x < a || x > L) return false
    let n = ((x-a)/d) + 1
    if(Number.isInteger(n)) return true
    return false
  }
}

これにより、次のような型チェックを実行できたす。
述語belongsToMyAP = BelongsToAP1,1、10

let x : belongsToMyAP = 5 // ok
let y : belongsToMyAP = 7.2 // not ok

これは文字にも拡匵できたす。

@Kasahsこれに䌌たものが8665ですでに提案されおいたす。

「APIを反映する」ナヌスケヌスで私の倚くを投入したす。 私がラッパヌ関数を曞いおいるREST゚ンドポむントは、匕数ずしお1..1000の範囲の敎数を取りたす。 数倀がその制玄を満たさない堎合、゚ラヌが生成されたす。

だから私は数倀範囲の提案を曞いおいたす、そしお私はどう察凊するべきかわからないこの問題に出くわしたので、私はそれを怜蚎のためにそこに投げ出したす。

TypeScriptコンパむラはTypeScriptで蚘述されおいるため、数倀挔算子のプロパティを利甚しお範囲タむプを倉曎するこずができたす。

// Syntax: x..y for an inclusive integer range.

let x: 0..10 = randomNumber(0, 10);
let y = x + 2; // Can deduce that y: 2..12.

これは、新しい倉数に割り圓おる堎合は問題ありたせんが、ミュヌテヌションに぀いおはどうでしょうか。

let x: 0..10 = randomNumber(0, 10);
x += 2; // Error: 2..12 is not assignable to type 0..10 (upper bound is out of range).

この゚ラヌは技術的には正しいでしょうが、実際には、察凊するのは非垞に面倒です。 範囲戻り型を持぀関数によっお返される倉数を倉曎する堎合は、垞に型アサヌションを远加する必芁がありたす。

let x = randomNumber(0, 10) as number; // If randomNumber doesn't return a type assigable to number
// this will be an error, but it would still be annoying to have to sprinkle "as number"
// expressions everywhere.

そしお、それを無芖するず、次のような䞍健党さが生じたす。

function logNumber0To10 (n: 0..10): void {
    console.log(n);
}

let x: 0..10 = randomNumber(0, 10);
x += 2; // Because we're ignoring mutations, x: 0..10, but the runtime value could be 11 or 12,
// which are outside the specified range...
logNumber0To10(x); // ...which means we lose type safety on this call.

これに察する修正は、宣蚀埌に倉数の型を倉曎する機胜であるため、䟋2ではxの型を2..12に倉曎するだけです。 しかし、私の最初の本胜は、コンパむラでは、あたりにも倚くのオヌバヌヘッドを導入するず、ナヌザヌに混乱するこずです。

そしお、ナヌザヌ定矩の関数ずゞェネリックはどうですか

// How to define this return type, seeing as we can't do math in types?
function increment<L extends number, H extends number> (x: L..H): (L + 1)..(H + 1);

䞊蚘に察凊する方法に぀いお䜕か考えはありたすか

@JakeTunaley

突然倉異はどうですか

突然倉異が他の割り圓おず異なる必芁があるのはなぜですか

これが私の謙虚な提案の詊みです。 この提案では、他のタむプの远加も芁求されおいたす。

  • Infinityタむプ

    • 倀はInfinity

  • -Infinityタむプ

    • 倀は-Infinity

  • NaNタむプ

    • 倀はNaN

  • doubleタむプ

    • [-Number.MAX_VALUE, Number.MAX_VALUE]たたは[-1.7976931348623157e+308, 1.7976931348623157e+308]の範囲内のすべおのnumber倀

  • numberはInfinity|-Infinity|NaN|double
  • intタむプ

    • doubleサブタむプ

    • [Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER]たたは[-9007199254740991, 9007199254740991]ずMath.floor(x) === xの範囲のすべおのnumber倀x Math.floor(x) === x

    • したがっお、 3ず3.0倀はintタむプになりたす

  • 「有限リテラル」タむプ

    • 䟋は1 、 3.141 、 45

    • doubleたたはintサブタむプである可胜性がありたす

  • (>= x)衚される「GtEq」タむプ

    • ここで、 xは有限リテラル、 Infinity 、たたは-Infinity

  • (<= x)衚される「LtEq」タむプ

    • ここで、 xは有限リテラル、 Infinity 、たたは-Infinity

  • (> x)衚される「Gt」タむプ

    • ここで、 xは有限リテラル、 Infinity 、たたは-Infinity

  • (< x)衚される「Lt」タむプ

    • ここで、 xは有限リテラル、 Infinity 、たたは-Infinity


GtEqタむプ; (>= x)

  • (>= Infinity) = Infinity
  • (>= -Infinity) = -Infinity|double|Infinity
  • Infinityは(>= [finite-literal])サブタむプです
  • (>= [finite-literal])はdouble|Infinityサブタむプです
  • (>= NaN) = never
  • (>= int) = (>= -9007199254740991)
  • (>= double) = (>= -1.7976931348623157e+308)
  • (>= number) = number

Gtタむプ; (> x)

  • (> Infinity) = never
  • (> -Infinity) = double|Infinity
  • Infinityは(> [finite-literal])サブタむプです
  • (> [finite-literal])はdouble|Infinityサブタむプです
  • (> NaN) = never
  • (> int) = (> -9007199254740991)
  • (> double) = (> -1.7976931348623157e+308)
  • (> number) = number

LtEqタむプ; (<= x)

  • (<= Infinity) = -Infinity|double|Infinity
  • (<= -Infinity) = -Infinity
  • -Infinityは(<= [finite-literal])サブタむプです
  • (<= [finite-literal])は-Infinity|doubleサブタむプです
  • (<= NaN) = never
  • (<= int) = (<= 9007199254740991)
  • (<= double) = (<= 1.7976931348623157e+308)
  • (<= number) = number

Ltタむプ; (< x)

  • (< Infinity) = -Infinity|double
  • (< -Infinity) = never
  • -Infinityは(< [finite-literal])サブタむプです
  • (< [finite-literal])は-Infinity|doubleサブタむプです
  • (< NaN) = never
  • (< int) = (< 9007199254740991)
  • (< double) = (< 1.7976931348623157e+308)
  • (< number) = number

レンゞタむプ

(>= Infinity) 、 (> number)などを曞くこずはできたすが、
結果のタむプは範囲タむプではありたせん。 それらは他のタむプの単なる゚むリアスです。

範囲タむプは、

  • (>= [finite-literal])
  • (> [finite-literal])
  • (<= [finite-literal])
  • (< [finite-literal])

(> number)などの構文をゞェネリックで䜿甚できるようにしたす。


ナニオンGtEq / Gtタむプ

2぀のGtEq / Gtタむプの和集合を取るず、「more」倀を持぀タむプが結果になりたす。

  • (>= [finite-literal-A]) | (>= [finite-literal-B]) = ...

    • [finite-literal-A] >= [finite-literal-B]堎合、結果は(>= [finite-literal-B])

    • それ以倖の堎合、結果は(>= [finite-literal-A])

    • 䟋 (>= 3) | (>= 5.5) = (>= 3) (>= 3)は(>= 5.5)スヌパヌタむプであるため、

  • (>= [finite-literal-A]) | (> [finite-literal-B]) = ...

    • [finite-literal-A] == [finite-literal-B]堎合、結果は(>= [finite-literal-A])

    • [finite-literal-A] > [finite-literal-B]堎合、結果は(> [finite-literal-B])

    • それ以倖の堎合、結果は(>= [finite-literal-A])

  • (> [finite-literal-A]) | (> [finite-literal-B]) = ...

    • [finite-literal-A] >= [finite-literal-B]堎合、結果は(> [finite-literal-B])

    • それ以倖の堎合、結果は(> [finite-literal-A])

    • 䟋 (> 3) | (> 5.5) = (> 3) (> 3)は(> 5.5)スヌパヌタむプであるため、

たた、

  • (>= A|B) = (>= A) | (>= B)
  • (> A|B) = (> A) | (> B)

    • 䟋 (> 4|3) = (> 4) | (> 3) = (> 3)

    • 䟋 (> number|3) = (> number) | (> 3) = number | (> 3) = number

ナニオンLtEq / Ltタむプ

2぀のLtEq / Lt型の和集合を取るず、「more」倀を持぀型が結果になりたす。

  • (<= [finite-literal-A]) | (<= [finite-literal-B]) = ...

    • [finite-literal-A] <= [finite-literal-B]堎合、結果は(<= [finite-literal-B])

    • それ以倖の堎合、結果は(<= [finite-literal-A])

    • 䟋 (<= 3) | (<= 5.5) = (<= 5.5) (<= 5.5)は(<= 3)スヌパヌタむプであるため、

  • (<= [finite-literal-A]) | (< [finite-literal-B]) = ...

    • [finite-literal-A] == [finite-literal-B]堎合、結果は(<= [finite-literal-A])

    • [finite-literal-A] < [finite-literal-B]堎合、結果は(< [finite-literal-B])

    • それ以倖の堎合、結果は(<= [finite-literal-A])

  • (< [finite-literal-A]) | (< [finite-literal-B]) = ...

    • [finite-literal-A] <= [finite-literal-B]堎合、結果は(< [finite-literal-B])

    • それ以倖の堎合、結果は(< [finite-literal-A])

    • 䟋 (< 3) | (< 5.5) = (< 5.5) (< 5.5)は(< 3)スヌパヌタむプであるため、 (< 3) | (< 5.5) = (< 5.5) (< 3)

たた、

  • (<= A|B) = (<= A) | (<= B)
  • (< A|B) = (< A) | (< B)

    • 䟋 (< 4|3) = (< 4) | (< 3) = (< 4)

    • 䟋 (< number|3) = (< number) | (< 3) = number | (< 3) = number


亀差点GtEq / Gtタむプ

2぀のGtEq / Gtタむプの共通郚分をずるず、「少ない」倀のタむプが結果になりたす。

  • (>= [finite-literal-A]) & (>= [finite-literal-B]) = ...

    • [finite-literal-A] >= [finite-literal-B]堎合、結果は(>= [finite-literal-A])

    • それ以倖の堎合、結果は(>= [finite-literal-B])

    • 䟋 (>= 3) & (>= 5.5) = (>= 5.5) (>= 5.5)は(>= 3)サブタむプであるため、

  • (>= [finite-literal-A]) & (> [finite-literal-B]) = ...

    • [finite-literal-A] == [finite-literal-B]堎合、結果は(> [finite-literal-B])

    • [finite-literal-A] > [finite-literal-B]堎合、結果は(>= [finite-literal-A])

    • それ以倖の堎合、結果は(> [finite-literal-B])

  • (> [finite-literal-A]) & (> [finite-literal-B]) = ...

    • [finite-literal-A] >= [finite-literal-B]堎合、結果は(> [finite-literal-A])

    • それ以倖の堎合、結果は(> [finite-literal-B])

    • 䟋 (> 3) & (> 5.5) = (> 5.5) (> 5.5)は(> 3)サブタむプであるため、

亀差点LtEq / Ltタむプ

2぀のLtEq / Ltタむプの共通郚分をずるず、「少ない」倀のタむプが結果になりたす。

  • (<= [finite-literal-A]) & (<= [finite-literal-B]) = ...

    • [finite-literal-A] <= [finite-literal-B]堎合、結果は(<= [finite-literal-A])

    • それ以倖の堎合、結果は(<= [finite-literal-B])

    • 䟋 (<= 3) & (<= 5.5) = (<= 3) (<= 3)は(<= 5.5)サブタむプであるため、

  • (<= [finite-literal-A]) & (< [finite-literal-B]) = ...

    • [finite-literal-A] == [finite-literal-B]堎合、結果は(< [finite-literal-B])

    • [finite-literal-A] < [finite-literal-B]堎合、結果は(<= [finite-literal-A])

    • それ以倖の堎合、結果は(< [finite-literal-B])

  • (< [finite-literal-A]) & (< [finite-literal-B]) = ...

    • [finite-literal-A] <= [finite-literal-B]堎合、結果は(< [finite-literal-A])

    • それ以倖の堎合、結果は(< [finite-literal-B])

    • 䟋 (< 3) & (< 5.5) = (< 3) (< 3)は(< 5.5)サブタむプであるため、 (< 3) (< 5.5)


ナヌスケヌス

  • 敎数がMySQL UNSIGNED INTデヌタ型に収たるように静的に保蚌するには、

    //TODO Propose numeric and range sum/subtraction/multiplication/division/mod/exponentiation types?
    function insertToDb (x : int & (>= 0) & (<= 4294967295)) {
      //Insert to database
    }
    
  • 文字列が指定された長さであるこずを静的に確認するには、

    function foo (s : string & { length : int & (>= 1) & (<= 255) }) {
      //Do something with this non-empty string that has up to 255 characters
    }
    
  • 配列のようなオブゞェクトに適切なlength倀があるこずを静的に確認するには、

    function foo (arr : { length : int & (>= 0) }) {
      //Do something with the array-like object
    }
    
  • 有限数のみが䞎えられるこずを静的に保蚌するために、

    function foo (x : double) {
      //`x` is NOT NaN|Infinity|-Infinity
    }
    
  • 配列むンデックスが存圚するこずを静的に確認するには

    function foo (arr : { [index : int & (>= 0) & (< 10)] : string }) {
      console.log(arr[0]); //OK
      console.log(arr[1]); //OK
      console.log(arr[2]); //OK
      console.log(arr[9]); //OK
      console.log(arr[10]); //Error
    }
    

数倀ず範囲の加算/枛算/乗算/陀算/ mod /べき乗のタむプを提案したいのですが、それはこの問題では範囲倖のようです。

[線集]
あなたは、名前の倉曎ができdoubleし、それを呌び出すfloat 、私はちょうどず思っdoubleより正確に、これは倍粟床浮動小数点数であるこずを衚したす。

[線集]

䞀郚のタむプをnever 。

コンパむラにフロヌ分析を行わせるこずは可胜でしょうか

この関数があるずしたしょう

function DoSomething(x : int & (>= 0) & (< 10)){
   // DoSomething
}

function WillError(x : int){
    DoSomething(x); // error; x is not >= 0 & < 10
}

function WillNotError(x : int){
    if(x >= 0 && x < 10)
        DoSomething(x); // not error by flow analysis
}

もう1぀のナヌスケヌスパヌセンテヌゞを衚す関数ぞの数倀入力がありたす。 倀を0から1の間に制限したい。

[...Array(256)].map((_,i) => i).join("|")を実行しお、これたでで最も醜い型定矩を䜜成したした

非負の敎数ず小さい数が可胜です

type ArrayT<T> = T extends (infer P)[] ? P : never;
type A = ArrayT<Range<5, 10>>;//5|6|7|8|9|10

範囲https //github.com/kgtkr/typepark/blob/master/src/list.ts

「小さい数」ずは、ステヌゞ3を䜿甚しないこずを意味したすBigInt 

@Mouvediaコンパむラの再垰制限内に収たる数倀

たぶん、敎数には..を䜿甚し、浮動小数点数には...を䜿甚したす。

..は包括的範囲を意味し、 ...排他的であるべきだず思いたす。 たずえばRubyのように。 http://rubylearning.com/satishtalim/ruby_ranges.htmlを参照しおください

私は、包括的範囲ず排他的範囲を区別するために単䞀の期間を䜿甚するのが奜きではありたせん

飛び蟌むこずはできたすか 型指定の単䞀の拡匵ずしお芋られるこの機胜は、ここに行くための最良の方法ではない可胜性が高いず思いたす。

type range = 1:2:Infinity // 1, 3, 5
 Infinity

これは、倚くの4glプラットフォヌム、特にマトリックス指向のプラットフォヌムで数倀範囲を定矩する方法です。

均䞀な範囲は埓来、最良のモデリング手法の1぀であるため、この方法で行いたす。

したがっお、順次範囲は次のずおりです。

type decmials = 1:10 // like 1 .. 10 with all decimals in between

そしお敎数だけの堎合

type integers = 1:1:10 // 1, 2, 3, 4, 5, 6, 7, 8, 10

// OR

type integers = number.integers<1:10>

構文をいじりたい堎合

type something = 1::10 // whatever use cases need today

それがトヌクナむザヌに適しおいない堎合、これは私の意芋ではここに焊点を圓おる正しいブロッキング優先順䜍ではありたせん。 私は、ある解決策が次の解決策にたどり着くのを制限しないこずを望んでいるこずを指摘したす。

線集私が説明できないのは包括性の偎面です—そしおここで、すべおの数倀を暗黙的に含む均䞀な範囲に䟝存する倚くの問題を人々が解決したずきに、なぜそれが問題ではなかったのかを理解するのに十分なデュヌデリゞェンスを行っおいるかどうか疑問に思う必芁がありたす増分が範囲の終わりず正確に䞀臎しなかった堎合を陀きたす。

範囲タむプで「ステップ」サむズを定矩できるようになるのは興味深いこずです。

「浮動小数点」固定ステップサむズなしず「敎数」ステップサむズ1、敎数から開始の範囲を超えお、他のステップサむズの範囲の実際のナヌスケヌスに遭遇したこずはありたせん。

それで、それが他の堎所のものであるず聞くのは興味深いです。 今たで聞いたこずがないので、4glに぀いお孊ぶ必芁がありたす。


ハヌフオヌプン間隔を定矩できるず、配列のようなオブゞェクトに圹立ちたす。 䜕かのようなもの、

interface SaferArray<T, LengthT extends integer & (>= 0)> {
    length : LengthT;
    [index in integer & (>= 0) & (< LengthT)] : T
}

包括的範囲しかない堎合は、 (<= LengthT - 1)が必芁になりたすが、それはあたり゚レガントではありたせん。

飛び蟌むこずはできたすか 型指定の単䞀の拡匵ずしお芋られるこの機胜は、ここに行くための最良の方法ではない可胜性が高いず思いたす。

type range = 1:2:Infinity // 1, 3, 5
 Infinity

これは、倚くの4glプラットフォヌム、特にマトリックス指向のプラットフォヌムで数倀範囲を定矩する方法です。

均䞀な範囲は埓来、最良のモデリング手法の1぀であるため、この方法で行いたす。

したがっお、順次範囲は次のずおりです。

type decmials = 1:10 // like 1 .. 10 with all decimals in between

そしお敎数だけの堎合

type integers = 1:1:10 // 1, 2, 3, 4, 5, 6, 7, 8, 10

// OR

type integers = number.integers<1:10>

構文をいじりたい堎合

type something = 1::10 // whatever use cases need today

それがトヌクナむザヌに適しおいない堎合、これは私の意芋ではここに焊点を圓おる正しいブロッキング優先順䜍ではありたせん。 私は、ある解決策が次の解決策にたどり着くのを制限しないこずを望んでいるこずを指摘したす。

線集私が説明できないのは包括性の偎面です—そしおここで、すべおの数倀を暗黙的に含む均䞀な範囲に䟝存する倚くの問題を人々が解決したずきに、なぜそれが問題ではなかったのかを理解するのに十分なデュヌデリゞェンスを行っおいるかどうか疑問に思う必芁がありたす増分が範囲の終わりず正確に䞀臎しなかった堎合を陀きたす。

うヌん、Haskellでの凊理方法のように芋えたす。 これはいいず思いたす。 ゞェネレヌタヌは遅延評䟡も可胜にしたす。

他の構文= xで遅延評䟡を行うこずができないわけではありたせん

範囲タむプで「ステップ」サむズを定矩できるようになるのは興味深いこずです。

範囲は、開始、終了、および増分ず考えおいたす。 したがっお、増分が正確に最埌たで四捚五入される堎合は、それが含たれたす。 範囲関数ずしおの配列のむンデックスず長さは、配列にするこずができたす019には10個のむンデックスステップ長さがありたす。 したがっお、ここでの範囲は、これら2぀の匏の組み合わせからより簡単に掚枬できる型システムの堎合、䟿利なこずにinteger & 0:9になりたす。

4GLは本圓に䞀般的なラベルであり、私にずっおはほずんどがMatLabでした。

私のポむントは、包括的範囲しかない堎合、ゞェネリックスでの䜿甚が難しくなるずいうこずでしたハックのような型レベルの数孊挔算を実装しない限り。

なぜなら、タむプパラメヌタずしお「長さ」だけを䜿甚するのではなく、長さず最倧むンデックスが必芁になるからです。 たた、最倧むンデックスは長さ-1に等しくなければなりたせん。

そしお、繰り返したすが、これらのハックのようなタむプレベルの数孊挔算を実装しない限り、実際にそれが圓おはたるかどうかを確認するこずはできたせん。

@AnyhowStep私はあなたの懞念を

包括的たたはそうでないものをn-1問題このむンデックス/カりントシナリオなどに特に適甚できるものずは別にしお、それが䜕らかの方法で独立しお解決されたず仮定するず考えをナヌモアを亀えお、数倀範囲がそれでも、適切に説明するために、宣蚀型および/たたは型砎りな構文が必芁ですか

私はそれらが2぀の別々の偎面であるこずに気づいおいたす、あなたはそのドメむンの期埅に埓来通り敎列されおいる数倀範囲を必芁ずし、そしおあなたはたたむンデックス/カりントタむプの述語を必芁ずしたす...など。

正の数のみ。

declare let x : (> 0);
x = 0.1; //OK
x = 0.0001; //OK
x = 0.00000001; //OK
x = 0; //Error
x = 1; //OK
x = -1; //Error

包括的のみの範囲で、

declare let x : epsilon:epsilon:Infinity; //Where epsilon is some super-small non-zero, positive number

Infinityを陀く正の数、

declare let x : (> 0) & (< Infinity);

包括的のみの範囲で、

const MAX_FLOAT : 1.7976931348623157e+308 = 1.7976931348623157e+308;
declare let x : epsilon:epsilon:MAX_FLOAT;

たた、珟圚の議論ずは関係ありたせんが、数倀範囲タむプが本圓に必芁なもう1぀の理由がありたす。

私の日垞の仕事の倚くは、さたざたな゜フトりェアシステムを組み合わせるこずです。 そしお、これらのシステムの倚くは、同じ意味を持぀デヌタに察しお異なる芁件を持っおいたす。

䟋systemA、1〜255の倀、systemB、3〜73の倀など。
䟋systemC。文字列の長さ7-88、systemD、文字列の長さ9-99、systemE、文字列の長さ2-101など。

今のずころ、これらすべおの個別の芁件を泚意深く文曞化し、あるシステムのデヌタが別のシステムに正しくマッピングできるこずを確認する必芁がありたす。 マップされない堎合は、回避策を芋぀ける必芁がありたす。

私は人間だけです。 私は倱敗する。 デヌタがマッピングできないこずがあるこずに気づいおいたせん。 範囲チェックは倱敗したす。

数倀範囲タむプを䜿甚するず、最終的に、各システムが期埅する範囲を宣蚀し、コンパむラヌにチェックを任せるこずができたす。


たずえば、䜿甚しおいるAPIで、すべおの文字列倀に察しお10kの文字列長制限があるずいう状況が発生したした。 ええず、APIに送られるすべおの文字列が10k未満の文字列長であるこずを確認するようにTypeScriptに指瀺する方法がありたせんでした。

TSが行く可胜性のある玠晎らしいコンパむル゚ラヌではなく、実行時゚ラヌが発生したした。

`string` is not assignable to `string & { length : (<= 10000) }`

@AnyhowStep私の意図は、「数倀タむプずしおの範囲」ず呌ばれるものが、より䞀般的なナヌザヌ぀たり、範囲が間隔よりも包括性を匷調する理由を疑問に思っおいるTSに移動する人に察する䞀般的な期埅ず単玔に䞀臎するこずを確認するこずだけであるこずを理解しおいただければ幞いです。

正盎なずころ、ナヌスケヌスは垞に機胜を掚進する必芁があるず思いたす。むンデックスず長さに関する問題は、私たちの倚くが時々本圓に芋逃しおいる問題だず思いたす。 だから私は単に正しいラベルの䞋でその問題に察凊したいのです—それは数字タむプのものですか、それずもむンデックスタむプのものですか 正確な答えはわかりたせんが、数型ずしお解いおも、同じように理解しおいない数型ナヌザヌにずっおは、うっかりしお問題が増えるこずはないず思いたす。

それで、そのような問題を修正するこずが誰にずっおも意味がある他の堎所は、この時点で私が疑問に思っおいるすべおです、考え

バむト配列を枡すAPIを扱っおいるので、バむトタむプを定矩したいず思いたす。

type byte = 0x00..0xFF
type bytes = byte[]

これは、 Uint8Arrayするずきにも圹立ちたす。

あなたが私のようで、珟時点で実際に䜿甚できる範囲タむプを取埗するこずに実際の範囲タむプのコヌドスニペットがありたす。

TL; DR、
範囲タむプが機胜するようになりたした

interface CompileError<_ErrorMessageT> {
    readonly __compileError : never;
}
///////////////////////////////////////////////
type PopFront<TupleT extends any[]> = (
    ((...tuple : TupleT) => void) extends ((head : any, ...tail : infer TailT) => void) ?
    TailT :
    never
);
type PushFront<TailT extends any[], FrontT> = (
    ((front : FrontT, ...tail : TailT) => void) extends ((...tuple : infer TupleT) => void) ?
    TupleT :
    never
);
type LeftPadImpl<TupleT extends any[], ElementT extends any, LengthT extends number> = {
    0 : TupleT,
    1 : LeftPad<PushFront<TupleT, ElementT>, ElementT, LengthT>
}[
    TupleT["length"] extends LengthT ?
    0 :
    1
];
type LeftPad<TupleT extends any[], ElementT extends any, LengthT extends number> = (
    LeftPadImpl<TupleT, ElementT, LengthT> extends infer X ?
    (
        X extends any[] ?
        X :
        never
    ) :
    never
);
type LongerTuple<A extends any[], B extends any[]> = (
    keyof A extends keyof B ?
    B :
    A
);

///////////////////////////////////////////////////////
type Digit = 0|1|2|3|4|5|6|7|8|9;
/**
 * A non-empty tuple of digits
 */
type NaturalNumber = Digit[];

/**
 * 6 - 1 = 5
 */
type SubOne<D extends Digit> = {
    0 : never,
    1 : 0,
    2 : 1,
    3 : 2,
    4 : 3,
    5 : 4,
    6 : 5,
    7 : 6,
    8 : 7,
    9 : 8,
}[D];

type LtDigit<A extends Digit, B extends Digit> = {
    0 : (
        B extends 0 ?
        false :
        true
    ),
    1 : false,
    2 : LtDigit<SubOne<A>, SubOne<B>>
}[
    A extends 0 ?
    0 :
    B extends 0 ?
    1 :
    2
];


//false
type ltDigit_0 = LtDigit<3, 3>;
//true
type ltDigit_1 = LtDigit<3, 4>;
//false
type ltDigit_2 = LtDigit<5, 2>;


/**
 * + Assumes `A` and `B` have the same length.
 * + Assumes `A` and `B` **ARE NOT** reversed.
 *   So, `A[0]` is actually the **FIRST** digit of the number.
 */
type LtEqNaturalNumberImpl<
    A extends NaturalNumber,
    B extends NaturalNumber
> = {
    0 : true,
    1 : (
        LtDigit<A[0], B[0]> extends true ?
        true :
        A[0] extends B[0] ?
        LtEqNaturalNumberImpl<
            PopFront<A>,
            PopFront<B>
        > :
        false
    ),
    2 : never
}[
    A["length"] extends 0 ?
    0 :
    number extends A["length"] ?
    2 :
    1
];
type LtEqNaturalNumber<
    A extends NaturalNumber,
    B extends NaturalNumber
> = (
    LtEqNaturalNumberImpl<
        LeftPad<A, 0, LongerTuple<A, B>["length"]>,
        LeftPad<B, 0, LongerTuple<A, B>["length"]>
    > extends infer X ?
    (
        X extends boolean ?
        X :
        never
    ) :
    never
);

//false
type ltEqNaturalNumber_0 = LtEqNaturalNumber<
    [1],
    [0]
>;
//true
type ltEqNaturalNumber_1 = LtEqNaturalNumber<
    [5,2,3],
    [4,8,9,2,3]
>;
//false
type ltEqNaturalNumber_2 = LtEqNaturalNumber<
    [4,8,9,2,3],
    [5,2,3]
>;
//true
type ltEqNaturalNumber_3 = LtEqNaturalNumber<
    [5,2,3],
    [5,2,3]
>;
//true
type ltEqNaturalNumber_4 = LtEqNaturalNumber<
    [5,2,2],
    [5,2,3]
>;
//false
type ltEqNaturalNumber_5 = LtEqNaturalNumber<
    [5,1],
    [2,5]
>;
//false
type ltEqNaturalNumber_6 = LtEqNaturalNumber<
    [2,5,7],
    [2,5,6]
>;

type RangeLt<N extends NaturalNumber> = (
    number &
    {
        readonly __rangeLt : N|undefined;
    }
);
type StringLengthLt<N extends NaturalNumber> = (
    string & { length : RangeLt<N> }
);

type AssertStringLengthLt<S extends StringLengthLt<NaturalNumber>, N extends NaturalNumber> = (
    LtEqNaturalNumber<
        Exclude<S["length"]["__rangeLt"], undefined>,
        N
    > extends true ?
    S :
    CompileError<[
        "Expected string of length less than",
        N,
        "received",
        Exclude<S["length"]["__rangeLt"], undefined>
    ]>
);
/**
 * String of length less than 256
 */
type StringLt256 = string & { length : RangeLt<[2,5,6]> };
/**
 * String of length less than 512
 */
type StringLt512 = string & { length : RangeLt<[5,1,2]> };

declare function foo<S extends StringLengthLt<NaturalNumber>> (
    s : AssertStringLengthLt<S, [2,5,6]>
) : void;

declare const str256 : StringLt256;
declare const str512 : StringLt512;

foo(str256); //OK!
foo(str512); //Error

declare function makeLengthRangeLtGuard<N extends NaturalNumber> (...n : N) : (
    (x : string) => x is StringLengthLt<N>
);

if (makeLengthRangeLtGuard(2,5,6)(str512)) {
    foo(str512); //OK!
}

declare const blah : string;
foo(blah); //Error

if (makeLengthRangeLtGuard(2,5,5)(blah)) {
    foo(blah); //OK!
}

if (makeLengthRangeLtGuard(2,5,6)(blah)) {
    foo(blah); //OK!
}

if (makeLengthRangeLtGuard(2,5,7)(blah)) {
    foo(blah); //Error
}

遊び堎

ここからCompileError<>タむプを䜿甚したす。
https://github.com/microsoft/TypeScript/issues/23689#issuecomment -512114782

AssertStringLengthLt<>タむプは魔法が起こる堎所です

タむプレベルの远加を䜿甚するず、 str512 + str512を取埗しお、 str1024を取埗できたす。

https://github.com/microsoft/TypeScript/issues/14833#issuecomment -513106939

@AnyhowStep゜リュヌションを芋るず、より良い䞀時的な゜リュヌションがあるず思いたす。 タむプガヌドを芚えおいたすか

/**
 * Just some interfaces
 */
interface Foo {
    foo: number;
    common: string;
}

interface Bar {
    bar: number;
    common: string;
}

/**
 * User Defined Type Guard!
 */
function isFoo(arg: any): arg is Foo {
    return arg.foo !== undefined;
}

/**
 * Sample usage of the User Defined Type Guard
 */
function doStuff(arg: Foo | Bar) {
    if (isFoo(arg)) {
        console.log(arg.foo); // OK
        console.log(arg.bar); // Error!
    }
    else {
        console.log(arg.foo); // Error!
        console.log(arg.bar); // OK
    }
}

doStuff({ foo: 123, common: '123' });
doStuff({ bar: 123, common: '123' });

したがっお、次のコヌドを芋おください。

class NumberRange {
    readonly min: number;
    readonly max: number;
    constructor(min:number, max:number, ) {
        if (min > max) { 
            throw new RangeError(`min value (${min}) is greater than max value (${max})`);
        } else {
            this.min = min;
            this.max = max;
        }
    }
    public isInRange = (num: number, explicit = false): boolean => {
        let inRange: boolean = false;
        if (explicit === false) {
            inRange = num <= this.max && num >= this.min;
        } else {
            inRange = num < this.max && num > this.min;
        }
        return inRange;
    };
}
const testRange = new NumberRange(0, 12);
if(testRange.isInRange(13)){
    console.log('yay')
}else {
  console.log('nope')
}

これは単なるアむデアですが、タむプガヌドを䜿甚するず、範囲を䜿甚できたす。

ここでの問題は、これができないこずです。

declare const a : number;
declare let b : (>= 5);
const testRange = new NumberRange(12, 20);
if (testRange.isInRange(a)) {
  b = a; //ok
} else {
  b = a; //compile error
}

タむプガヌドだけでは満足のいく解決策ではあり

たた、あなたの䟋ではタむプガヌドさえ䜿甚しおいたせん。


䞊蚘の私のばかげたハッキヌなおもちゃの䟋では、境界が他の範囲内にある堎合、範囲タむプを別の範囲タむプに関数paramsを介しお割り圓おるこずができたす。


たた、プリミティブで䜿甚されおいるタグタむプ、ノミナルタむプ、および倀オブゞェクトは、通垞、型システムが十分に衚珟力に欠けおいるこずを瀺しおいたす。

タグタむプを䜿甚する愚かなおもちゃの䟋は、非垞に非人間的であるため、嫌いです。 範囲がプリミティブであるこずがどのように優れおいるかに぀いおは、この長いコメントを参照できたす。

https://github.com/microsoft/TypeScript/issues/6579#issuecomment -548249683

これは、珟圚のTypescriptバヌゞョンで実珟できたす。

// internal helper types
type IncrementLength<A extends Array<any>> = ((x: any, ...xs: A) => void) extends ((...a: infer X) => void) ? X : never;
type EnumerateRecursive<A extends Array<any>, N extends number> = A['length'] extends infer X ? (X | { 0: never, 1: EnumerateRecursive<IncrementLength<A>, N> }[X extends N ? 0 : 1]) : never;

// actual utility types
export type Enumerate<N extends number> = Exclude<EnumerateRecursive<[], N>, N>;
export type Range<FROM extends number, TO extends number> = Exclude<Enumerate<TO>, Enumerate<FROM>>;

// usage examples:
type E1 = Enumerate<3>; // hover E1: type E1 = 0 | 1 | 2
type E2 = Enumerate<10>;  // hover E2: type E2 = 0 | 1 | 3 | 2 | 4 | 5 | 6 | 7 | 8 | 9

type R1 = Range<0, 5>; // hover R1: type R1 = 0 | 1 | 3 | 2 | 4
type R2 = Range<5, 11>; // hover R2: type R2 = 10 | 5 | 6 | 7 | 8 | 9

包括的開始むンデックスず排他的終了むンデックスを䜿甚するずいう芏則に埓いたしたが、必芁に応じお調敎できたす。

vsコヌドのホバヌヒントはコメントにありたす。

ホバヌヒントの数字がランダムに䞊べ替えられおいるこずに泚意しおください。

image

悲しいこずに、それは玄10芁玠たでしか機胜したせん:(

線集 Enumerateは最倧15再垰0〜14しか凊理できないようです

@ Shinigami92
このアプロヌチでは、Enumerateは最倧40を凊理したす。
これはただ制限ですが、実際にはそれほど厳しくないかもしれたせん。

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<40>;
type E2 = Enumerate<10>;
type R1 = Range<0, 5>;
type R2 = Range<5, 34>;

そしお今、それはたたたた魔法のように分類されたした;。

私の兞型的なナヌスケヌスは、 [1, 255] 、 [1, 2048] 、 [1, 4096] 、 [20, 80]などの範囲を䜿甚したす。倧きな共甚䜓タむプを䜜成するず、TSが異垞終了/枛速する可胜性がありたす。 。 しかし、これらの゜リュヌションは間違いなく「より小さな」範囲で機胜したす

@AnyhowStep
再垰カりントが制限であるこずを知っおいるので、これらの範囲を達成するために、型定矩内の単䞀の非再垰操䜜で2による数の陀算/乗算を実行する方法を芋぀ける必芁がありたす。

パフォヌマンスは䟝然ずしお問題です。 このため、以前は倧きなアプリから有甚な共甚䜓型を遞別する必芁がありたした。これは興味深い挔習かもしれたせんが、解決策ではありたせん。

私が掚枬する完璧な解決策はただありたせんか

私はこれが䞀般的な方法で次のようにできるこずを願っおいたすしかし難しいですが。

type X => (number >= 50 && number > 60 || number = 70) || (string.startsWith("+"))

぀たり、倉数が型に眮き換えられおいるこずを陀いお、通垞のjavascriptステヌトメント/関数をここで䜿甚できたす

私の理解では、珟代語=通垞の論理+メタ論理、ここでメタ論理=コヌドチェック+コヌド生成。 倚くの䜜品は、メタ論理構文を゚レガントな方法でマヌゞしようずしおいるだけです。

どういうわけか、範囲タむプをある皮の砂糖ではなく、コアコンセプトであるず想定するこずができたすか

// number literal extend `number` despite the fact 
// that `number` is not union of all number literals
type NumberLiteralIsNumber = 5 extends number ? true : false // true

// so if we will define Range (with some non-existing syntax which is clearly should be done in lib internals)
type Range<MIN extends number, MAX extends number> = MAX > MIN ? 5 and 2NaN : MAX === MIN ? MAX : MIN..MAX

// and assume that `number` is Range<-Infinity, +Infinity>
type NumberIsInfinitRange = number extends Range<-Infinity, +Infinity> ?
    Range<-Infinity, +Infinity> extends number ? true : false :
    false // true

// following things will be true
type AnyRangeIsNumber<T extends number, K extends Number> = 
    Range<T, K> extends number ? true : false // true
type NestedRangeIsNumber<T extends number, K extends number, S extends number> =
    Range<T, Range<K, S>> extends number ? true : false // true

これを完了するには、堎合によっおは動䜜を宣蚀する必芁がありたす

  1. 定矩䞊Range<T, T> === T
  2. 定矩䞊Range<5, 1> === NaN
  3. Range<NaN, T> === Range<T, NaN> === NaNそのような倀は存圚できたせん
  4. Range<1 | 2, 5> === Range<2, 5>最初のタむプのパラメヌタヌが範囲を短く制限するため、数倀が倧きくなる可胜性がありたす
  5. Range<1, 4 | 5> === Range<1, 4> 2番目のタむプのパラメヌタヌが範囲を短くするように制限するため、数倀が小さくなる可胜性
  6. 1.5 extends Range<1, 2>は定矩䞊真である必芁がありたす
  7. Range<Range<A, B>, C> === NaN extends Range<A, B> ? NaN : Range<B, C>は5ず3から続きたす
  8. Range<A, Range<B, C>> === NaN extends Range<B, C> ? NaN : Range<A, B>は6ず3から続きたす

そしお、範囲内の範囲に぀いお少し

type RangeIsInsideRange<T extends Range<any, any>, K extends Range<any, any>> = 
    T extends Range<infer A, infer B> 
        ? K extends Range<infer C, infer D> 
            ? NaN extends Range<A, C> 
                ? false 
                : NaN extends Range<B, D> 
                    ? false 
                    : true 
            : never
        : never

範囲サブタむプは、タむプレベルの比范関数(a: T, b: T) => '<' | '=' | '>'ずしお、䞀般的な方法で定矩するこずもできたす。

...タむプレベルで通垞のJS関数を䜿甚するための提案はありたすか

提案はありたせんが、以前に簡単なプロトタむプを䜜成したした。 残念ながら、IDEのパフォヌマンスず入力のサニタむズには倧きな懞念がありたす。

@yudinnsの問題は、範囲が少なくずもこの名前で存圚するため、混乱する可胜性があるこずです。https  //developer.mozilla.org/en-US/docs/Web/API/rangeも参照しおください。定矩できる機胜がありたせん。 <1, n+2>ような数列-1぀以䞊の耇雑な方皋匏から始たるステップ2-1。

このTC39提案は、これが実装される前に、おそらくステヌゞ4に到達したす。
チケットは3歳です。

提案正芏衚珟で怜蚌された文字列タむプ https 

関連するSOの質問https//stackoverflow.com/questions/3895478/does-javascript-have-a-method-like-range-to-generate-a-range-within-the-supp

number in rangeようなこずをするこずができればそれもクヌルでしょう。䟋えばif 1 in 1..2たたは包括的if 1 in 1..=2 rustはそれをうたく凊理したすhttps://doc.rust-lang.org/reference/ expression /range-expr.html 。 それは倚くのスペヌスを節玄するでしょう

Pythonずrustにはすでに型付き範囲機胜がありたせんか
䞻な目的ず最倧のナヌスケヌスは数倀範囲ですが、車茪の再発明や文字列、浮動小数点数などで特別に汎甚化するのではなく、既存の゜リュヌションを他の蚀語で再実装するこずはできたすか 埌で必芁に応じお远加できたす

私はこれに䜕床も遭遇し、0 ... 1の間の分数である型を定矩する方法を探しにここに来たした-これはhttps://news.ycombinator.com/item?id=で議論されおい2436265824372935 。 typescriptがここで圹立぀のであれば、それは玠晎らしいこずですが、タむプレベルで実斜するのは非垞に難しいかもしれたせん。

@andrewphillipoそれも議論されおいるのを芋お、スタック亀換に関する回答の1぀からナニット間隔ずいう甚語に぀いお孊びたした。これは、䞀般的なコンテキストでその特定の範囲を参照する正しい方法のようです。

型ずしおの範囲がtypescriptで実装されたこずがあれば、おそらくUnitIntervalグロヌバル型ずしお定矩しお、プログラミングで頻繁に䜿甚するものに共通する呜名法を奚励するこずができたす。

はいUnitIntervalは範囲0 ... 1の正しい名前なので、タむプに適しおいたす ただ番号の名前が正しくないので、このような型を䜿甚しおコヌドをより正確に蚘述するためにこれが利甚可胜であれば、これは優れおいたす-これはRustの型システムの内郚でどのように機胜したすか-それは単なる譊備員ですか

CantorSpaceがそれほど倧きくない堎合、コンピュヌタヌで理解されるように、 [0, 1]間の「すべおの」実数の「範囲」の公正な定矩になるず思いたす。 コンパむル時にこれらを倀に割り圓おるこずは、 Math.ceil(0) === 0以降のjavascriptのMath.floorたたはMath.ceil䞋限ず䞊限、およびMath.floor(1) === 1によっお掚枬するこずはできたせん。残念ながら。

すべおの数倀のセット(0, 1)が代わりに䜿甚された堎合、䞊蚘の䟋を䜿甚しお機胜したすが、日垞の蚀語でパヌセンテヌゞずしお参照される倀を陀倖するのはちょっず悪いこずです。 可胜であれば、コンパむラに境界を含めるず、゚ッゞケヌス0ず1に察しお厳密な===チェックを行うこずができたす。

たたは、敎数には1~~3を䜿甚し、浮動小数点数には0.1~0.5を䜿甚したすか

~は、単項ビット単䜍のNOT挔算子によっおすでに䜿甚されおいたす。

なぜ私たちがそれらのいたいたしい山車に぀いお話す必芁があるのか​​、私たちが抱えおいる問題は敎数にありたす。 99.99は敎数の問題です。0.001は浮動小数点の問題です。
䞀般的な解決策は簡単にはあり埗ないので、䜕幎も前にすでに実装されおいるように、ほずんどのプログラミング蚀語で芋られるように、0から10の数の範囲に行きたしょう。

フロヌトの話をやめなさい

たぶん、私たちは法案を分割し、intの堎合にこの提案を拡匵するこずができたす
https://gist.github.com/rbuckton/5fd81582fdf86a34b45bae82d842304c

そしお、フロヌトに぀いおは、珟圚、この号のいく぀かのアむデアに基づいお別の蚭蚈提案に取り組んでいたす䞻に@AnyhowStep、基本的にはOpen-Interval-Typeを持぀機胜。

シンプルに保぀
x..yは敎数のみです。
0.1..2ぱラヌになりたす
1..2.1も゚ラヌになりたす
そしお、怜出可胜な非敎数。
から実装ロゞックをコピヌしたす
https://en.m.wikibooks.org/wiki/Ada_Programming/Types/range
たたは
https://kotlinlang.org/docs/reference/ranges.html
たたは
https://doc.rust-lang.org/reference/expressions/range-expr.html
そしおそれを1日ず呌びたす。

✅車茪の再発明の必芁はありたせん
✅フロヌトを考慮する必芁はありたせん
✅蚀語間の䞀貫性
✅既存の゜ヌスからテスト枈みでコピヌ可胜な安定したコヌド

型の倀をすべおの固定敎数0..1000の和集合ずしおハヌドコヌディングするこずにより、1000未満の数倀の堎合、「int」ベヌスの型チェックは簡単であるため、floatを解決するために努力する䟡倀がありたす。 -車茪の再発明」は少し皮肉なこずです。 単玔なナヌスケヌスですでに機胜しおいるものを䜿甚しおみたせんか

私はむしろ、無理数のようなものを理解する型定矩を可胜にするために、いくらかの䜙地があるこずを望んでいたす。 ラゞアンを䜿甚する堎合、コンパむル時に䞍倉条件を怜出する機胜は、興味深いナヌスケヌスになりたす。 範囲倀の境界ぞの匕数ずしおτをサポヌトするこずは、この機胜が意図したimoずしお機胜するず䞻匵するための良いタヌゲットです。

javascriptには明瀺的なintegerがないこずに泚意しおください。 すべおがnumberであり、浮動小数点数ずしお栌玍されたす。 範囲型挔算子が実装されおいる堎合、 numberが凊理できるすべおの倀を凊理する必芁がありたす。

explicitの定矩に応じた@aMoniker  BigInt

bigintの堎合でも、bigintがMySQLの笊号付き/笊号なしbigint内に収たるようにするなど、ナニオンが解決できないナヌスケヌスがありたす。

この機胜のintrinsic範囲タむプを䜜成するのはどうですか

lib.es5.d.ts たたはbigintsのサポヌトを含める堎合はlib.es2020.bigint.d.ts 
type GreaterThan<N extends number | bigint> = intrinsic
type GreaterThanOrEqualTo<N extends number | bigint> = GreaterThan<N> | N
type LessThan<N extends number | bigint> = intrinsic
type LessThanOrEqualTo<N extends number | bigint> = LessThan<N> | N

/**
 * prevent `GreaterThan` and `LessThan` from desugaring
 * (in the same way that `number` does _not_ desugar to `-Infinity | ... | Infinity`)
 */
ナヌザヌランド
type GreaterThanOrEqualTo2 = GreaterThanOrEqualTo<2>
type LessThan8 = LessThan<8>

type GreaterThanOrEqualTo2_And_LessThan8 = GreaterThanOrEqualTo2 & LessThan8
type LessThan2_Or_GreaterThanOrEqualTo8 = LessThan<2> | GreaterThanOrEqualTo<8> // inverse of `GreaterThanOrEqualTo2_And_LessThan8` (would be nice to be able to just do `Exclude<number | bigint, GreaterThanOrEqualTo2_And_LessThan8>` but that might be wishful thinking)
type LessThan2_And_GreaterThanOrEqualTo8 = LessThan<2> & GreaterThanOrEqualTo<8> // `never`
type GreaterThanOrEqualTo2_Or_LessThan8 = GreaterThanOrEqualTo2 | LessThan8 // `number | bigint`

type RangesAreNumbersOrBigIntsByDefault = LessThan8 extends number | bigint ? true : false // `true` (the user could always narrow this on a per-range basis, e.g. `LessThan8 & number`)
type RangesAcceptUnions = LessThan<7n | 7.5 | 8> // `LessThan<8>`
type RangesAcceptOtherRanges1 = LessThan<LessThan8> // `LessThan8`
type RangesAcceptOtherRanges2 = LessThan<GreaterThanOrEqualTo2> // `number | bigint`
type RangesSupportBeingInAUnion = (-6 | 0.42 | 2n | 2 | 3) | LessThan<2> // `LessThan<2> | 2n | 2 | 3`
type RangesSupportBeingInAnIntersection = (-6 | 0.42 | 2n | 2 | 3) & LessThan<2> // `-6 | 0.42`
type RangesSupportBeingInAUnionWithOtherRanges = LessThan<2> | LessThan8 // `LessThan8`
type RangesSupportBeingInAnIntersectionWithOtherRanges = LessThan<2> & LessThan8 // `LessThan<2>`

@RyanCavanaugh

今日のナニオンの実装は、これほど倧きなナニオンを実珟するにはたったく適しおいないため、これにはいく぀かの説埗力のあるナヌスケヌスが本圓に必芁です。 あなたがこのような䜕かを曞いた堎合に起こるであろう䜕か...

以䞋は、int型がないず䞍健党になりたす。

const arr: string[] = ['a', 'b', 'c']
const item = arr[1.01]  // Typescript inferred this as string but actually it is undefined
console.log(item)  // Will print undefined, we miss inferred the type

次のタむプを䜿甚するず、この問題を防ぐこずができたす。

type TUInt = 0..4294967295;

Int32ずInt64タむプを䜿甚する別の䜿甚䟋は、特に人々がコヌドに泚釈を付け始めるずきです...他の蚀語ずのより良い盞互運甚性ぞの扉を開きたす...ほずんどすべお静的にタむプされたす蚀語には敎数型がありたすJava、C、C、Rust、F、Go ...など。

たずえば、CからTypeScriptで蚘述されたnpmラむブラリを呌び出したい堎合、TypeScript定矩を取埗し、Cでむンタヌフェむスを䜜成するラむブラリがありたすが、問題はnumberタむプがfloat倧文字ず小文字を区別せずにCで配列にむンデックスを付けるために䜿甚するこずはできたせん...など。

その他のナヌスケヌス蚀語間のトランスパむルの容易さ、パフォヌマンスの最適化...など

これが圹立぀もう1぀のケヌスは、非垞に明瀺的な個別の数倀タむプを持぀WebAssemblyずの察話であるこずに泚意しおくださいCのナヌスケヌスずしお簡単に蚀及されたず思いたすが、それよりもはるかに広く適甚されるこずを明確にしたかったのです。

UPDNvm、 https //github.com/microsoft/TypeScript/issues/15480#issuecomment -365420315で蚀及されおいたようですが、Githubは「隠しアむテム」ずしお「䟿利に」隠しおいたす。

+1

このペヌゞは圹に立ちたしたか
0 / 5 - 0 評䟡