typescript - 强类型工作者
问题描述
我正在玩一些逻辑来创建一个强类型的工作者,它应该能够只接受一组预定义的消息,并在给定消息的情况下以适当的响应类型进行响应。
类似于以下内容
type MsgStruct<T, P, R> = {
type: T
payload: P
response: R
}
type FooMsg = MsgStruct<'foo', number, number>
type BarMsg = MsgStruct<'bar', boolean, string>
type BazMsg = MsgStruct<'baz', string, boolean[]>
// Messages that can be handled by the worker
type WorkerMsg =
| FooMsg
| BarMsg
| BazMsg
// Creation logic
type StronglyTypedWorker<T> = T extends { type: infer A, payload: infer B, response: infer C } ? {
postMessage: (msg: { type: A, payload: B }) => Promise<C>
} : never
declare const worker: Worker
declare const createWorker: <T extends MsgStruct<unknown, unknown, unknown>>(worker: Worker) => StronglyTypedWorker<T>
// Example
const strongWorker = createWorker<WorkerMsg>(worker)
declare const foo: FooMsg
const fooRes = strongWorker.postMessage(foo)
.then(res => {}) // expecting `res` to be of type `number` here
tsc
正如抱怨的那样,这不起作用
'FooMsg' 类型的参数不能分配给'never' 类型的参数。交集 '{ type: "foo"; 有效载荷:数字;} & { 类型:“酒吧”;有效载荷:布尔值;} & { 类型:“baz”;有效载荷:字符串;}' 被简化为 'never' 因为属性 'type' 在某些成分中具有冲突类型.ts(2345)
有一个更好的方法吗?或者更确切地说,一个有效的?
解决方案
你快到了。
问题在于createWorker
返回类型,它是函数的联合。
当您想调用函数联合时,它们的参数将相交/合并。因为函数参数处于逆变位置。这就是为什么你有never
类型。
你可以在我的文章中阅读更多关于它的信息
您需要做的就是产生函数重载,换句话说,您应该派生函数的交集而不是联合:
type MsgStruct<T, P, R> = {
type: T
payload: P
response: R
}
type FooMsg = MsgStruct<'foo', number, number>
type BarMsg = MsgStruct<'bar', boolean, string>
type BazMsg = MsgStruct<'baz', string, boolean[]>
// Messages that can be handled by the worker
type WorkerMsg =
| FooMsg
| BarMsg
| BazMsg
// Creation logic
type StronglyTypedWorker<T> = T extends { type: infer A, payload: infer B, response: infer C } ? {
postMessage: (msg: { type: A, payload: B }) => Promise<C>
} : never
declare const worker: Worker
// credits goes to https://stackoverflow.com/a/50375286
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (
k: infer I
) => void
? I
: never;
declare const createWorker: <T extends MsgStruct<unknown, unknown,unknown>>(worker: Worker) => UnionToIntersection<StronglyTypedWorker<T>>
// Example
const strongWorker = createWorker<WorkerMsg>(worker)
declare const foo: FooMsg
const fooRes = strongWorker.postMessage(foo)
.then(res => { }) // res is number
顺便说一句,大多数时候你不需要函数的联合
推荐阅读
- javascript - JSX 不接受三元语句(意外标记“?”)
- r - R从括号内的字符串中提取多个数字正则表达式
- sql - 我可以从 Terraform 脚本填充数据库吗(对于 GCP)
- google-kubernetes-engine - 带有自定义 SSL 证书的 Traefik 2.3 将不起作用
- python - 长度不匹配:预期轴有 0 个元素,新值有 6 个元素
- sql - 如何查找跨 JSON 数组存在重复值的行
- c++ - execvp 做 ps 每次都会给出相同的结果
- lua - 在 Windows 上正确设置 LuaBinaries 文件?
- python - Python 硒网络驱动程序
- r - 尝试使用 R 整理 Excel 工作表