Skip to content

Commit

Permalink
Add StructuredCloneable type (#897)
Browse files Browse the repository at this point in the history
  • Loading branch information
thecodewarrior authored Jun 26, 2024
1 parent dc35412 commit 737550b
Show file tree
Hide file tree
Showing 4 changed files with 238 additions and 0 deletions.
1 change: 1 addition & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ 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 {Schema} from './source/schema';
export type {LiteralToPrimitive} from './source/literal-to-primitive';
export type {LiteralToPrimitiveDeep} from './source/literal-to-primitive-deep';
Expand Down
4 changes: 4 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,10 @@ 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`.

### Async

- [`Promisable`](source/promisable.d.ts) - Create a type that represents either the value or the value wrapped in `PromiseLike`.
Expand Down
89 changes: 89 additions & 0 deletions source/structured-cloneable.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
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
| Blob
| File;
// DOM exclusive types
// | AudioData
// | CropTarget
// | CryptoKey
// | DOMException
// | DOMMatrix
// | DOMMatrixReadOnly
// | DOMPoint
// | DOMPointReadOnly
// | DOMQuad
// | DOMRect
// | DOMRectReadOnly
// | FileList
// | FileSystemDirectoryHandle
// | FileSystemFileHandle
// | FileSystemHandle
// | GPUCompilationInfo
// | GPUCompilationMessage
// | ImageBitmap
// | ImageData
// | RTCCertificate
// | VideoFrame

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

/**
Matches a value that can be losslessly cloned using `structuredClone`.
Note:
- Custom error types will be cloned as the base `Error` type
- This type doesn't include types exclusive to the TypeScript DOM library (e.g. `DOMRect` and `VideoFrame`)
@see https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm
@example
```
import type {StructuredCloneable} from 'type-fest';
class CustomClass {}
// @ts-expect-error
const error: StructuredCloneable = {
custom: new CustomClass(),
};
structuredClone(error);
//=> {custom: {}}
const good: StructuredCloneable = {
number: 3,
date: new Date(),
map: new Map<string, number>(),
}
good.map.set('key', 1);
structuredClone(good);
//=> {number: 3, date: Date(2022-10-17 22:22:35.920), map: Map {'key' -> 1}}
```
@category Structured clone
*/
export type StructuredCloneable = StructuredCloneablePrimitive | StructuredCloneableData | StructuredCloneableCollection;
144 changes: 144 additions & 0 deletions test-d/structured-cloneable.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
import {expectAssignable, expectNotAssignable} from 'tsd';
import type {StructuredCloneable} 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: 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
- Blob
- File
## DOM exclusive types (not included)
- AudioData
- 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
- FileList
- FileSystemDirectoryHandle
- FileSystemFileHandle
- FileSystemHandle
- GPUCompilationInfo
- GPUCompilationMessage
- ImageBitmap
- ImageData
- RTCCertificate
- VideoFrame
*/

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

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

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

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

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

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

// Object: but only plain objects (e.g. from object literals).
expectAssignable<StructuredCloneable>({});
expectAssignable<StructuredCloneable>({x: 10});
expectAssignable<StructuredCloneable>({x: {y: 10}});
expectAssignable<StructuredCloneable>({x: 10} as const);
class CustomType {}
expectNotAssignable<StructuredCloneable>(new CustomType());
class CustomTypeWithProperties {
foo = 'wow';
bar = 1;
}
expectNotAssignable<StructuredCloneable>(new CustomTypeWithProperties());

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

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

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

// Web/API types
declare const blob: Blob;
expectAssignable<StructuredCloneable>(blob);
declare const file: File;
expectAssignable<StructuredCloneable>(file);

0 comments on commit 737550b

Please sign in to comment.