Tri*_*Gao 8 type-safety typescript
这个数字是一个非常松散的表示,有时需要收紧.在我的情况下,我希望变量只能采用非负整数.有没有办法在TypeScript中强制执行此约束?
Hun*_*ler 52
是的,模板文字允许这样做;观察:
\ntype NonNegativeInteger<T extends number> =\n number extends T \n ? never \n : `${T}` extends `-${string}` | `${string}.${string}`\n ? never \n : T;\nRun Code Online (Sandbox Code Playgroud)\n请注意,number extends T有必要限制一般number type.
用法:
\nfunction negate<N extends number>(n: NonNegativeInteger<N>): number {\n return -n;\n}\n\n\nnegate(3); // success\nnegate(3.1); // failure\nnegate(-3); // failure\nnegate(-3.1); // failure\nRun Code Online (Sandbox Code Playgroud)\n回复 @ianstarz 评论:
\n\n\n您将如何在类字段或变量类型上使用它?myField: NonNegativeInteger = 42 似乎不起作用\xe2\x80\x94I\不确定在这种情况下要作为泛型类型传递什么。您能否提供一个示例来说明如何在这种情况下使用泛型?
\n
了解在 Typescript 中,文字本身被视为类型;示例:10可分配给 some let x: number,但只能10分配给 some let x: 10。此外,Typescript 拥有强大的类型推断系统,但它也只能做到这一点,否则就会成为开发的负担。上述类型的目标是执行以下两件事之一:
您的问题不仅适用于类字段,也适用于上述类型。Typescript 变量在声明时应用类型推断,而不是赋值;此推论不会扩展到变量的泛型。
\n为了演示泛型变量类型和函数调用之间的区别,请考虑使用泛型标识类型时的以下错误:
\ntype Identity<T> = Identity;\n\n// Generic type \'Example\' requires 1 type argument(s)\nlet x: Identity = 10;\nRun Code Online (Sandbox Code Playgroud)\n相比:
\ntype Identity<T> = Identity;\n\nfunction identity<T>(x: Identity<T>): T {\n return x;\n}\n\nlet y = identity(10); // Success, y has type `number`\nconst z = identity(10); // Success, z has type `10`\nRun Code Online (Sandbox Code Playgroud)\n请注意如何z假定文字类型。事实上,我们可以显式输入y相同的内容,但它只允许10作为一个值,而不是任何其他数字。
如果您有有限数量的整数值(例如文件描述符),请创建一个具有如下类型的字段:
\ntype EvenDigit = 0 | 2 | 4 | 6 | 8;\n\nlet x: EvenDigit = 2; // Success\nlet y: EvenDigit = 10; // Failure\nRun Code Online (Sandbox Code Playgroud)\n如果您很疯狂,请编写一个生成联合类型的脚本。请注意,联合类型的成员数量可能存在特定于版本的上限。
\n如果你想要超级元,类似这样的东西会生成一系列类型:
\n// Assumes, for simplicity, that arguments Start and End are integers, and\n// 0 < Start < End.\n// Examples:\n// Range<0, 5> -> 0 | 1 | 2 | 3 | 4 | 5\n// Only can calculate so much:\n// Range<0, 100> -> \'Type instantiation is excessively deep and possibly infinite.ts(2589)\'\n// Tail end recursion being introduced in Typescript 4.5 may improve this.\ntype Range<Start extends number, End extends number> = RangeImpl<Start, End>;\ntype RangeImpl<\n Start extends number,\n End extends number,\n T extends void[] = Tuple<void, Start>\n> = End extends T["length"]\n ? End\n : T["length"] | RangeImpl<Start, End, [void, ...T]>;\n\n// Helper type for creating `N` length tuples. Assumes `N` is an integer\n// greater than `0`. Example:\n// Tuple<number, 2 | 4> -> [number, number] | [number, number, number, number]\ntype Tuple<T, N extends number> = TupleImpl<T, N>;\n// prettier-ignore\ntype TupleImpl<T, N extends number, U extends T[] = []> =\n N extends U["length"]\n ? U\n : TupleImpl<T, N, [T, ...U]>;\n\nRun Code Online (Sandbox Code Playgroud)\n您可以创建一个带有赋值和检索方法的类(不是 getter/setter 对,因为An accessor cannot have type parameters ts(1094))。
例子:
\nclass MyClass {\n private _n: number = 42;\n \n // infers return type `number`\n getN() {\n return this._n;\n }\n\n setN<T>(n: NonNegativeInteger<T>) {\n // Optionally error check:\n if (Number.isInteger(n) || n <= 0) {\n throw new Error();\n }\n this._n = value;\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n
不,这是不可能的;uintJavaScript中没有* 或类似字符,因此TypeScript中没有相应的类型。有一个针对Contracts的开放功能请求,如果您实施了该请求,那么您将可以提供诸如此类的更可靠的断言。
*此类数据类型存在于“ 类型化数组”规范中,但它们是主要为WebGL设计的扩展,不是核心语言的一部分。
| 归档时间: |
|
| 查看次数: |
3111 次 |
| 最近记录: |