Skip to content

Commit

Permalink
Add StructuredCloneable/StructuredCloneableWeb types
Browse files Browse the repository at this point in the history
  • Loading branch information
Kate Corcoran committed Jun 24, 2024
1 parent e75dbe1 commit 4c117f3
Show file tree
Hide file tree
Showing 6 changed files with 455 additions and 0 deletions.
2 changes: 2 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ export type {Simplify} from './source/simplify';
export type {SimplifyDeep} from './source/simplify-deep';
export type {Jsonify} from './source/jsonify';
export type {Jsonifiable} from './source/jsonifiable';
export type {StructuredCloneable} from './source/structured-cloneable';
export type {StructuredCloneableWeb} from './source/structured-cloneable-web';
export type {Schema} from './source/schema';
export type {LiteralToPrimitive} from './source/literal-to-primitive';
export type {LiteralToPrimitiveDeep} from './source/literal-to-primitive-deep';
Expand Down
5 changes: 5 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,11 @@ type ShouldBeNever = IfAny<'not any', 'not never', 'never'>;
- [`JsonArray`](source/basic.d.ts) - Matches a JSON array.
- [`JsonValue`](source/basic.d.ts) - Matches any valid JSON value.

### Structured clone

- [`StructuredCloneable`](source/structured-cloneable.d.ts) - Matches a value that can be losslessly cloned using `structuredClone`.
- [`StructuredCloneableWeb`](source/structured-cloneable-web.d.ts) - Matches a value that can be losslessly cloned using `structuredClone` (includes web types like `Blob` and `DOMRect`).

### Async

- [`Promisable`](source/promisable.d.ts) - Create a type that represents either the value or the value wrapped in `PromiseLike`.
Expand Down
92 changes: 92 additions & 0 deletions source/structured-cloneable-web.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import type {TypedArray} from './typed-array';

type StructuredCloneableWebValue =
| Blob
| CryptoKey
| DOMException
| DOMMatrix
| DOMMatrixReadOnly
| DOMPoint
| DOMPointReadOnly
| DOMQuad
| DOMRect
| DOMRectReadOnly
| File
| FileList
| FileSystemDirectoryHandle
| FileSystemFileHandle
| FileSystemHandle
| ImageBitmap
| ImageData
| RTCCertificate
| VideoFrame;
// Missing types:
// | AudioData
// | CropTarget
// | GPUCompilationInfo
// | GPUCompilationMessage

type StructuredCloneablePrimitive =
| string
| number
| bigint
| boolean
| null
| undefined
| Boolean
| Number
| String;

type StructuredCloneableData =
| ArrayBuffer
| DataView
| Date
| Error
| RegExp
| TypedArray;

type StructuredCloneableCollection =
| readonly StructuredCloneableWeb[]
| {readonly [k: string]: StructuredCloneableWeb; readonly [k: number]: StructuredCloneableWeb}
| ReadonlyMap<StructuredCloneableWeb, StructuredCloneableWeb>
| ReadonlySet<StructuredCloneableWeb>;

/**
Matches a value that can be losslessly cloned using `structuredClone` (includes web types like `Blob` and `DOMRect`).
Can be used to type values that you expect to pass to `structuredClone`.
Note:
- Custom error types will be cloned as the base `Error` type
- This variant includes web-specific cloneable types (e.g. `Blob` and `DOMRect`)
@see `StructuredCloneable` for a version that doesn't include web types
@example
```
import type {StructuredCloneableWeb} from 'type-fest';
class CustomClass {}
// @ts-expect-error
const error: StructuredCloneableWeb = {
custom: new CustomClass(),
};
structuredClone(error);
//=> {custom: {}}
const good: StructuredCloneableWeb = {
blob: new Blob(["<div></div>"], { type: "text/html" }),
date: new Date(),
map: new Map<string, number>(),
}
good.map.set("key", 1)
structuredClone(good);
//=> {blob: Blob {size: 11, type: "text/html"}, date: Date(2022-10-17 22:22:35.920), map: Map {"key" -> 1}}
```
@category Structured clone
*/
export type StructuredCloneableWeb = StructuredCloneableWebValue | StructuredCloneablePrimitive | StructuredCloneableData | StructuredCloneableCollection;
66 changes: 66 additions & 0 deletions source/structured-cloneable.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import type {TypedArray} from './typed-array';

type StructuredCloneablePrimitive =
| string
| number
| bigint
| boolean
| null
| undefined
| Boolean
| Number
| String;

type StructuredCloneableData =
| ArrayBuffer
| DataView
| Date
| Error
| RegExp
| TypedArray;

type StructuredCloneableCollection =
| readonly StructuredCloneable[]
| {readonly [k: string]: StructuredCloneable; readonly [k: number]: StructuredCloneable}
| ReadonlyMap<StructuredCloneable, StructuredCloneable>
| ReadonlySet<StructuredCloneable>;

/**
Matches a value that can be losslessly cloned using `structuredClone`.
Can be used to type values that you expect to pass to `structuredClone`.
Note:
- Custom error types will be cloned as the base `Error` type
- This type doesn't include the web-specific cloneable types (e.g. `Blob` and `DOMRect`)
@see `StructuredCloneableWeb` for a version that includes the web-specific types
@example
```
import type {StructuredCloneable} from 'type-fest';
class CustomClass {}
// @ts-expect-error
const error: StructuredCloneable = {
custom: new CustomClass(),
};
structuredClone(error);
//=> {custom: {}}
const good: StructuredCloneable = {
num: 3,
date: new Date(),
map: new Map<string, number>(),
}
good.map.set("key", 1)
structuredClone(good);
//=> {num: 3, date: Date(2022-10-17 22:22:35.920), map: Map {"key" -> 1}}
```
@category Structured clone
*/
export type StructuredCloneable = StructuredCloneablePrimitive | StructuredCloneableData | StructuredCloneableCollection;
184 changes: 184 additions & 0 deletions test-d/structured-cloneable-web.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
import {expectAssignable, expectNotAssignable} from 'tsd';
import type {StructuredCloneableWeb} from '..';

/*
Source: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm
# Supported types
## JavaScript types
- Array
- ArrayBuffer
- Boolean
- DataView
- Date
- Error types (but see Error types below).
- Map
- Number
- Object objects: but only plain objects (e.g. from object literals).
- Primitive types, except symbol.
- RegExp: but note that lastIndex is not preserved.
- Set
- String
- TypedArray
## Error types
For Error types, the error name must be one of: Error, EvalError, RangeError, ReferenceError, SyntaxError, TypeError, URIError (or will be set to "Error").
## Web/API types
- AudioData
- Blob
- CropTarget
- CryptoKey
- DOMException: browsers must serialize the properties name and message. Other attributes may also be serialized/cloned.
- DOMMatrix
- DOMMatrixReadOnly
- DOMPoint
- DOMPointReadOnly
- DOMQuad
- DOMRect
- DOMRectReadOnly
- File
- FileList
- FileSystemDirectoryHandle
- FileSystemFileHandle
- FileSystemHandle
- GPUCompilationInfo
- GPUCompilationMessage
- ImageBitmap
- ImageData
- RTCCertificate
- VideoFrame
*/

// Date, Boolean, Number, String
expectAssignable<StructuredCloneableWeb>(new Date());
declare const booleanWrapperObject: Boolean;
expectAssignable<StructuredCloneableWeb>(booleanWrapperObject);
declare const numberWrapperObject: Number;
expectAssignable<StructuredCloneableWeb>(numberWrapperObject);
declare const stringWrapperObject: String;
expectAssignable<StructuredCloneableWeb>(stringWrapperObject);

// Primitive types, except symbol.
expectAssignable<StructuredCloneableWeb>(undefined);
expectAssignable<StructuredCloneableWeb>(null);
expectAssignable<StructuredCloneableWeb>(true);
expectAssignable<StructuredCloneableWeb>(1);
expectAssignable<StructuredCloneableWeb>(1n);
expectAssignable<StructuredCloneableWeb>('');
declare const symbolValue: symbol;
expectNotAssignable<StructuredCloneableWeb>(symbolValue);

// RegExp: but note that lastIndex is not preserved.
expectAssignable<StructuredCloneableWeb>(/foo/);

// ArrayBuffer, DataView
expectAssignable<StructuredCloneableWeb>(new ArrayBuffer(10));
expectAssignable<StructuredCloneableWeb>(new DataView(new ArrayBuffer(10)));

// TypedArray
expectAssignable<StructuredCloneableWeb>(new Int8Array(10));
expectAssignable<StructuredCloneableWeb>(new Uint8Array(10));
expectAssignable<StructuredCloneableWeb>(new Uint8ClampedArray(10));
expectAssignable<StructuredCloneableWeb>(new Int16Array(10));
expectAssignable<StructuredCloneableWeb>(new Uint16Array(10));
expectAssignable<StructuredCloneableWeb>(new Int32Array(10));
expectAssignable<StructuredCloneableWeb>(new Uint32Array(10));
expectAssignable<StructuredCloneableWeb>(new Float32Array(10));
expectAssignable<StructuredCloneableWeb>(new Float64Array(10));
expectAssignable<StructuredCloneableWeb>(new BigInt64Array(10));
expectAssignable<StructuredCloneableWeb>(new BigUint64Array(10));

// Error types
declare const error: Error;
expectAssignable<StructuredCloneableWeb>(error);
declare const evalError: EvalError;
expectAssignable<StructuredCloneableWeb>(evalError);
declare const rangeError: RangeError;
expectAssignable<StructuredCloneableWeb>(rangeError);
declare const referenceError: ReferenceError;
expectAssignable<StructuredCloneableWeb>(referenceError);
declare const syntaxError: SyntaxError;
expectAssignable<StructuredCloneableWeb>(syntaxError);
declare const typeError: TypeError;
expectAssignable<StructuredCloneableWeb>(typeError);
declare const uriError: URIError;
expectAssignable<StructuredCloneableWeb>(uriError);

// Object objects: but only plain objects (e.g. from object literals).
expectAssignable<StructuredCloneableWeb>({});
expectAssignable<StructuredCloneableWeb>({x: 10});
expectAssignable<StructuredCloneableWeb>({x: {y: 10}});
expectAssignable<StructuredCloneableWeb>({x: 10} as const);
class CustomType {}
expectNotAssignable<StructuredCloneableWeb>(new CustomType());

// Array
expectAssignable<StructuredCloneableWeb>([]);
expectAssignable<StructuredCloneableWeb>([1, 2, 3]);
expectAssignable<StructuredCloneableWeb>([1, 2, 3] as const);
expectAssignable<StructuredCloneableWeb>([[1, 2], [3, 4]]);
expectAssignable<StructuredCloneableWeb>([{x: 1}, {x: 2}]);

// Map
expectAssignable<StructuredCloneableWeb>(new Map<string, Date>());
expectAssignable<StructuredCloneableWeb>(new Map<Date, string[]>());
expectAssignable<StructuredCloneableWeb>(new Map<Date, Map<string, number>>());

// Set
expectAssignable<StructuredCloneableWeb>(new Set<number>());
expectAssignable<StructuredCloneableWeb>(new Set<string[]>());
expectAssignable<StructuredCloneableWeb>(new Set<Set<string>>());

// Web/API types
declare const blob: Blob;
expectAssignable<StructuredCloneableWeb>(blob);
declare const cryptoKey: CryptoKey;
expectAssignable<StructuredCloneableWeb>(cryptoKey);
declare const domException: DOMException;
expectAssignable<StructuredCloneableWeb>(domException);
declare const domMatrix: DOMMatrix;
expectAssignable<StructuredCloneableWeb>(domMatrix);
declare const domMatrixReadOnly: DOMMatrixReadOnly;
expectAssignable<StructuredCloneableWeb>(domMatrixReadOnly);
declare const domPoint: DOMPoint;
expectAssignable<StructuredCloneableWeb>(domPoint);
declare const domPointReadOnly: DOMPointReadOnly;
expectAssignable<StructuredCloneableWeb>(domPointReadOnly);
declare const domQuad: DOMQuad;
expectAssignable<StructuredCloneableWeb>(domQuad);
declare const domRect: DOMRect;
expectAssignable<StructuredCloneableWeb>(domRect);
declare const domRectReadOnly: DOMRectReadOnly;
expectAssignable<StructuredCloneableWeb>(domRectReadOnly);
declare const file: File;
expectAssignable<StructuredCloneableWeb>(file);
declare const fileList: FileList;
expectAssignable<StructuredCloneableWeb>(fileList);
declare const fileSystemDirectoryHandle: FileSystemDirectoryHandle;
expectAssignable<StructuredCloneableWeb>(fileSystemDirectoryHandle);
declare const fileSystemFileHandle: FileSystemFileHandle;
expectAssignable<StructuredCloneableWeb>(fileSystemFileHandle);
declare const fileSystemHandle: FileSystemHandle;
expectAssignable<StructuredCloneableWeb>(fileSystemHandle);
declare const imageBitmap: ImageBitmap;
expectAssignable<StructuredCloneableWeb>(imageBitmap);
declare const imageData: ImageData;
expectAssignable<StructuredCloneableWeb>(imageData);
declare const rtcCertificate: RTCCertificate;
expectAssignable<StructuredCloneableWeb>(rtcCertificate);
declare const videoFrame: VideoFrame;
expectAssignable<StructuredCloneableWeb>(videoFrame);

// Missing types:

/*
declare const audioData: AudioData;
expectAssignable<StructuredCloneableWeb>(audioData);
declare const cropTarget: CropTarget;
expectAssignable<StructuredCloneableWeb>(cropTarget);
declare const gpuCompilationInfo: GPUCompilationInfo;
expectAssignable<StructuredCloneableWeb>(gpuCompilationInfo);
declare const gpuCompilationMessage: GPUCompilationMessage;
expectAssignable<StructuredCloneableWeb>(gpuCompilationMessage);
*/
Loading

0 comments on commit 4c117f3

Please sign in to comment.