能否在TypeScript中精准定义结构化可克隆类型?
结构化克隆兼容的TypeScript类型定义与问题分析
我需要定义一套可通过结构化克隆算法传递的TypeScript类型集合,用于约束那些需要通过postMessage、structuredClone传递,或通过history.pushState、IndexedDB持久化的数据,避免触发DataCloneError。目前我主要在IndexedDB场景中使用这个类型。
奇怪的是TypeScript并没有在Web API家族中内置该类型——虽然它不属于ECMAScript规范,但属于HTML规范,而且Node、Deno、Bun等环境都支持。可能因为普通开发者对这类API的需求较少,所以官方没有内置。
初步类型定义
type TypedArray = | Int8Array | Uint8Array | Uint8ClampedArray | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array | Float64Array | BigInt64Array | BigUint64Array; type StructureClonableError = | Error | EvalError | RangeError | ReferenceError | SyntaxError | TypeError | URIError; /** 兼容的Web API类型 */ type WebClonableObjects = // | AudioData | Blob // | CropTarget | CryptoKey | DOMException | DOMMatrix | DOMMatrixReadOnly | DOMPoint | DOMPointReadOnly | DOMQuad | DOMRect | DOMRectReadOnly | File | FileList | FileSystemDirectoryHandle | FileSystemFileHandle | FileSystemHandle // | GPUCompilationInfo // | GPUCompilationMessage | ImageBitmap | ImageData | RTCCertificate | VideoFrame; /** 结构化克隆兼容类型 */ export type StructureClonable = | string | number | boolean | bigint | null | undefined | StructureClonable[] | readonly StructureClonable[] | { [key: string]: StructureClonable } | Set<StructureClonable> | Map<StructureClonable, StructureClonable> | Date | ArrayBuffer | StructureClonableError | RegExp | TypedArray | WebClonableObjects;
类型校验案例
我写了一个测试函数来验证类型约束效果:
function hasToBeStructureClonable(value: StructureClonable) { worker.postMessage(value) } // 简写 const htbsc = hasToBeStructureClonable // 正常校验场景(符合预期) htbsc({ foo: "bar" }) // 合法值,校验通过 ✅ htbsc(document) // 非法值,校验拦截 ✅ htbsc({ element: document.createElement("div") }) // 非法值,校验拦截 ✅ htbsc(() => {}) // 非法值,校验拦截 ✅ htbsc({ [Symbol()]: "symbols are not ok" }) // 非法值,校验拦截 ✅ htbsc(new Date) // 合法值,校验通过 ✅ htbsc(new class {}) // 非法值,校验拦截 ✅ htbsc(new Error) // 合法值,校验通过 ✅ // 存在漏洞的场景(不符合预期) htbsc(Object.assign(new Date, { document })) // 非法值,但校验通过 ❌ // 自定义继承内置类的实例无法被序列化 htbsc(new class MyError extends Error {}) // 非法值,但校验通过 ❌ htbsc(Object.assign([1,2,3], { document })) // 非法值,但校验通过 ❌ htbsc({ get foo() { return "bar" } }) // getter会被丢弃,校验无提示 ⚠️
无法解决的局限性
结构化克隆算法会忽略属性描述符、移除写入限制,还会丢弃getter/setter函数,导致克隆后的对象结构和原对象不一致。由于TypeScript无法追踪属性是存储值还是通过getter定义,这类问题目前没有办法通过类型约束解决。
内容的提问来源于stack exchange,提问作者Link0
相关产品推荐
相关产品推荐

