【发布时间】:2022-06-10 23:17:32
【问题描述】:
我目前正在为我正在处理的项目编写一个复杂的自定义类型保护库,但我在理解函数签名为类型保护工作的方式时遇到了问题。
有一个通用的Is 函数采用以下形式:
type Is<A> = (a: unknown) => a is A
这使我可以编写表单的可组合类型保护
const isString: Is<string> = (u: unknown): u is string => typeof u === 'string'
const isNumber: Is<number> = (u: unknown): u is number => typeof u === 'number'
还有用于记录、结构、数组等的。比如数组一是
const isArray = <A>(isa: Is<A>) => (u: unknown): u is A[] => Array.isArray(u) && u.every(isa)
我有一个关于联合和交集类型的问题。
联合类型保护的签名是:
const isUnion<T extends Is<unknown>[]> = (...allTypeGuards: T): Is<T extends Array<Is<infer U>> ? U : never>
像这样称呼
const isStringOrNumber: Is<string | number> = isUnion(isString, isNumber)
对于交集是
function isIntersection<T, U extends Is<T>[]>(...args: U): Is<T>
例如:
const isFooAndBar: Is<{foo: string} & {bar: string}> = isIntersection(isStruct({foo: isString}),isStruct({bar: isString}))
我的问题是:为什么 isIntersection 和 isUnion 的签名是这样的?
对我来说,我会认为isIntersection 中的泛型isT 将是一个联合:如果您在打字稿中有一个数组['a', false, 1],那么该数组的类型是Array<string | boolean | number>,所以泛型T 将是 string, boolean, number,但 Is 函数的使用方式似乎有所不同。
同样使用 Union 函数,我不明白为什么需要使用 infer。
请原谅我的英语:我试图解决这个问题已经筋疲力尽,我很乐意提供澄清。
【问题讨论】:
-
isUnion 和 isIntersection 应该做什么?
-
这会提出多个问题;你能只关注其中一个吗?在任何情况下,这似乎都不是minimal reproducible example(并且您应该修复拼写错误,就像您对
isUnion的定义中发生的任何事情一样)。isIntersection()调用签名不能开箱即用,并导致Is<unknown>。我也不会像他们那样写isUnion()。修复它们看起来像this,虽然我可以解释 my 版本是如何工作的,但对于一些甚至没有演示的第三方代码,我不知道该说些什么。我们应该在这里做什么? -
@jcalz 非常感谢您的帮助。我已编辑问题以提供示例,并将库移至公共仓库以防万一:github.com/ByteLondon/byteguards。我理解你的 isUnion 签名,你能解释一下 isIntersection 吗?
标签: typescript typescript-generics