对我来说,大多数时候需要动态检查来验证获取响应。我在想,这是否可以通过用户定义的typeguard以通用的方式来完成,用于任何类型的具有多个属性和附加检查的对象,因此它可以像这样使用:
打字操场。
Here is an example with sample object, but i want a function without it.
// ================= shared exported =================
type Writer = {
name: string
age: number
}
type Book = {
id: number
name: string
tags: string[] | null
writers: Writer[]
}
// function to check object with multiple props general shape, to not do it by hand
function ofType<T>(obj: any): obj is T {
if (!obj) return false;
// how to?
return true // or false
}
// ================= used and defined in components =================
function isBook(obj: any): obj is Book {
if (!ofType<Book>(obj)) return false //checking for shape and simple types
// cheking for specific values and ranges
if (obj.id < 1) return false
if (obj.writers && obj.writers.some(( { age } )=> age < 5 || age > 150)) return false
return true
}
const book = {
id: 1,
name: 'Avangers',
tags: ['marvel', 'fun'],
writers: [ {name: 'Max', age: 25}, {name: 'Max', age: 25}]
}
console.log(isBook(book)) // true or false
5条答案
按热度按时间iovurdzv1#
实际上有许多模块试图将TypeScript类型信息转换为可用于验证数据结构的运行时信息。
我将尝试在这里列出并比较各种解决方案。(大致按照我估计它们的有效性/通用性排序;是的,这有点主观!)
Core features: (marked with ✔️yes, ❌no, ⚙️partial, ❔unknown)
溶液
**Core features:**ts-base: ✔️class : ❌func: ❌guard: ✔️auto: ⚙️
typescript-json-schema(+架构验证器,例如ajv)
**Core features:**ts-base: ✔️class: ✔️func: ❌guard: ❌auto: ❌
∮ ∮ ∮ ∮ ∮
**Core features:**ts-base: ✔️class: ✔️func: ✔️guard: ❌auto: ❌
∮ ∮ ∮ ∮ ∮
**Core features:**ts-base: ✔️class: ✔️func: ✔️guard: ❌auto: ❌
∮ ∮ ∮ ∮ ∮
**Core features:**ts-base: ✔️class: ✔️func: ✔️guard: ✔️auto: ✔️
(单独给药)
**Core features:**ts-base: ❌class: ❌func: ❌guard: ✔️auto: ❌
io-ts-transformer(用于io-ts的扩展)
**Core features:**ts-base: ✔️class: ❌func: ❌guard: ✔️auto: ❌
**Core features:**ts-base: ✔️class: ❔func: ❌guard: ✔️auto: ❌
∮ ∮ ∮ ∮ ∮
**Core features:**ts-base: ✔️class: ❔func: ❌guard: ✔️auto: ❌
**Core features:**ts-base: ✔️class: ❔func: ❌guard: ✔️auto: ❌
免责声明
我不是这里列出的任何一个解决方案的创建者或维护者,我创建这个列表是为了帮助开发者在一组一致的标准上比较不同的解决方案,同时添加一些有用的信息,比如GitHub星和NPM每周下载量。(欢迎定期编辑这些值以保持最新--尽管记住要修改最后更新时间标签!)
对于那些有足够声誉的人,请随意添加您遇到的其他解决方案。(尽管请尽量保持新条目的文本与现有条目一致)
xtfmy6hx2#
TypeScript的类型系统在编译为JavaScript时被擦除,这意味着任何使用标准
tsc
编译器自身从type
或interface
定义生成运行时类型保护的努力都不会成功;在运行时,这些定义中没有任何东西可以使用,因此ofType<T>()
无法实现。那你能做什么呢?
如果你愿意在你的构建系统中使用一些其他的编译步骤,你可以编写或使用一个转换器,在这些定义被擦除之前为你提供类型保护,例如
typescript-is
就可以做到这一点。或者可以使用
class
定义;这使得在运行时检查变得很容易(只需要使用instanceof
),但是困难的部分是将JSON反序列化为一个类示例,并在反序列化时捕获错误,而不需要自己手动编写。所有这一切都是将问题从实现ofType<Book>(someObj)
转移到实现myDeserializerFunction(Book, someObj)
,其中Book
是一个类构造函数。在这里,至少你可以使用装饰器和类元数据来生成编程反序列化所需的代码,你可以自己编写,或者使用现有的库,比如
json2typescript
。最后,您可能决定从类型保护开始,并让TypeScript从它们 * 推断 * 您的
type
定义,也就是说,不是定义Book
并希望从中获得类型保护bookGuard()
,而是编写类型保护bookGuard()
并根据typeof bookGuard
定义Book
。这个类型保护可以通过组合现有的更简单的类型保护来构建,所以它看起来更像是一个声明性的类型定义,而不是一个数据检查函数。你可以自己编写,或者使用现有的库,比如
io-ts
或zod
。对于这种方法,了解一下如何编写这样的库是很有启发性的。下面是一个可能的实现:
这里我们导出了一些类型保护和函数,它们组成了现有的类型保护。
gString()
、gNumber()
、gBoolean()
和gNull()
函数只是类型保护,而gObject()
、gArray()
、和gUnion()
利用现有类型的防护装置来制造新型防护装置。您可以看到gObject()
如何获取一个充满类型保护属性的对象,并创建一个新的类型保护,其中每个属性都根据相应的保护进行检查。您可以添加其他复合函数,如gIntersection()
或gPartial()
,但这里的函数对于您的示例来说已经足够了。现在你的
Book
和Writer
定义如下所示(假设上面的定义已经作为命名空间G
导入):如果你仔细看一下,你会发现它类似于你的示例
Writer
和Book
定义,但是在我们的例子中,基本对象是类型保护gWriter
和gBook
,类型Writer
和Book
是从它们派生出来的,然后你可以直接使用gBook
来代替不存在的ofType<Book>()
:好吧,希望能有所帮助;祝你好运!
Playground代码链接
fjaof16o3#
您可以使用类代替类型,并检查
instanceOf
请检查示例
https://stackblitz.com/edit/types-in-runtime
希望这能帮到你
jq6vz3qz4#
下面是如何使用TypeOnly
安装
typeonly
和@typeonly/checker
:在
package.json
文件中,添加typeonly
命令。例如,假设TypeScript配置为在dist/
目录中输出:在代码中,将这些类型放在单独的定义文件中:
然后,在代码中导入类型和检查器:
用
npm run build
构建,那么它应该可以工作。另请参阅:https://github.com/tomko-team/typeonly
b1payxdu5#
为了完成几乎详尽的jcalz' answer,在与外部API通信的情况下,我们可以使用生成的TypeScript客户端:强类型,带ou但不带typeguard,取决于生成器/技术,例如: