Skip to content

Add type definitions for Uint8Array to/from base64 methods #61696

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions src/compiler/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1780,6 +1780,12 @@ export const getScriptTargetFeatures: () => ScriptTargetFeatures = /* @__PURE__
"toSpliced",
"with",
],
esnext: [
"toBase64",
"setFromBase64",
"toHex",
"setFromHex",
],
})),
Uint8ClampedArray: new Map(Object.entries({
es2022: [
Expand Down Expand Up @@ -1908,6 +1914,12 @@ export const getScriptTargetFeatures: () => ScriptTargetFeatures = /* @__PURE__
"cause",
],
})),
Uint8ArrayConstructor: new Map(Object.entries({
esnext: [
"fromBase64",
"fromHex",
],
})),
}))
);

Expand Down
70 changes: 70 additions & 0 deletions src/lib/esnext.array.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,73 @@ interface ArrayConstructor {
*/
fromAsync<T, U>(iterableOrArrayLike: AsyncIterable<T> | Iterable<T> | ArrayLike<T>, mapFn: (value: Awaited<T>, index: number) => U, thisArg?: any): Promise<Awaited<U>[]>;
}

interface Uint8ArrayConstructor {
/**
* Creates a new `Uint8Array` from a base64-encoded string.
* @param string The base64-encoded string.
* @param options If provided, specifies the alphabet and handling of the last chunk.
* @returns A new `Uint8Array` instance.
* @throws {SyntaxError} If the input string contains characters outside the specified alphabet, or if the last
* chunk is inconsistent with the `lastChunkHandling` option.
*/
fromBase64: (
string: string,
options?: {
alphabet?: "base64" | "base64url";
lastChunkHandling?: "loose" | "strict" | "stop-before-partial";
},
) => Uint8Array;

/**
* Creates a new `Uint8Array` from a base16-encoded string.
* @returns A new `Uint8Array` instance.
*/
fromHex: (
string: string,
) => Uint8Array;
}

interface Uint8Array<TArrayBuffer extends ArrayBufferLike> {
/**
* Converts the `Uint8Array` to a base64-encoded string.
* @param options If provided, sets the alphabet and padding behavior used.
* @returns A base64-encoded string.
*/
toBase64: (options?: {
alphabet?: "base64" | "base64url";
omitPadding?: boolean;
}) => string;

/**
* Sets the `Uint8Array` from a base64-encoded string.
* @param string The base64-encoded string.
* @param options If provided, specifies the alphabet and handling of the last chunk.
* @returns An object containing the number of bytes read and written.
* @throws {SyntaxError} If the input string contains characters outside the specified alphabet, or if the last
* chunk is inconsistent with the `lastChunkHandling` option.
*/
setFromBase64: (string: string, options?: {
alphabet?: "base64" | "base64url";
lastChunkHandling?: "loose" | "strict" | "stop-before-partial";
}) => {
read: number;
written: number;
};

/**
* Converts the `Uint8Array` to a base16-encoded string.
* @returns A base16-encoded string.
*/
toHex: () => string;

/**
* Sets the `Uint8Array` from a base16-encoded string.
* @param string The base16-encoded string.
* @returns An object containing the number of bytes read and written.
*/
setFromHex: (string: string) => {
read: number;
written: number;
};
}
4 changes: 2 additions & 2 deletions tests/baselines/reference/findLast(target=esnext).symbols
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ new Int8Array().findLast((item) => item === 0);

new Uint8Array().findLast((item) => item === 0);
>new Uint8Array().findLast : Symbol(Uint8Array.findLast, Decl(lib.es2023.array.d.ts, --, --), Decl(lib.es2023.array.d.ts, --, --))
>Uint8Array : Symbol(Uint8Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 3 more)
>Uint8Array : Symbol(Uint8Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 4 more)
>findLast : Symbol(Uint8Array.findLast, Decl(lib.es2023.array.d.ts, --, --), Decl(lib.es2023.array.d.ts, --, --))
>item : Symbol(item, Decl(findLast.ts, 3, 27))
>item : Symbol(item, Decl(findLast.ts, 3, 27))
Expand Down Expand Up @@ -117,7 +117,7 @@ new Int8Array().findLastIndex((item) => item === 0);

new Uint8Array().findLastIndex((item) => item === 0);
>new Uint8Array().findLastIndex : Symbol(Uint8Array.findLastIndex, Decl(lib.es2023.array.d.ts, --, --))
>Uint8Array : Symbol(Uint8Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 3 more)
>Uint8Array : Symbol(Uint8Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 4 more)
>findLastIndex : Symbol(Uint8Array.findLastIndex, Decl(lib.es2023.array.d.ts, --, --))
>item : Symbol(item, Decl(findLast.ts, 17, 32))
>item : Symbol(item, Decl(findLast.ts, 17, 32))
Expand Down
2 changes: 1 addition & 1 deletion tests/baselines/reference/indexAt(target=esnext).symbols
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ new Int8Array().at(0);

new Uint8Array().at(0);
>new Uint8Array().at : Symbol(Uint8Array.at, Decl(lib.es2022.array.d.ts, --, --))
>Uint8Array : Symbol(Uint8Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 3 more)
>Uint8Array : Symbol(Uint8Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 4 more)
>at : Symbol(Uint8Array.at, Decl(lib.es2022.array.d.ts, --, --))

new Uint8ClampedArray().at(0);
Expand Down
2 changes: 1 addition & 1 deletion tests/baselines/reference/subclassUint8Array.symbols
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@
=== subclassUint8Array.ts ===
class CustomBuffer extends Uint8Array {
>CustomBuffer : Symbol(CustomBuffer, Decl(subclassUint8Array.ts, 0, 0))
>Uint8Array : Symbol(Uint8Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 3 more)
>Uint8Array : Symbol(Uint8Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 4 more)
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
toFromHexBase64.ts(1,25): error TS2550: Property 'fromBase64' does not exist on type 'Uint8ArrayConstructor'. Do you need to change your target library? Try changing the 'lib' compiler option to 'esnext' or later.
toFromHexBase64.ts(2,25): error TS2550: Property 'fromBase64' does not exist on type 'Uint8ArrayConstructor'. Do you need to change your target library? Try changing the 'lib' compiler option to 'esnext' or later.
toFromHexBase64.ts(3,25): error TS2550: Property 'fromHex' does not exist on type 'Uint8ArrayConstructor'. Do you need to change your target library? Try changing the 'lib' compiler option to 'esnext' or later.
toFromHexBase64.ts(12,20): error TS2550: Property 'setFromBase64' does not exist on type 'Uint8Array<ArrayBuffer>'. Do you need to change your target library? Try changing the 'lib' compiler option to 'esnext' or later.
toFromHexBase64.ts(13,20): error TS2550: Property 'setFromBase64' does not exist on type 'Uint8Array<ArrayBuffer>'. Do you need to change your target library? Try changing the 'lib' compiler option to 'esnext' or later.
toFromHexBase64.ts(14,20): error TS2550: Property 'setFromBase64' does not exist on type 'Uint8Array<ArrayBuffer>'. Do you need to change your target library? Try changing the 'lib' compiler option to 'esnext' or later.
toFromHexBase64.ts(20,20): error TS2550: Property 'setFromHex' does not exist on type 'Uint8Array<ArrayBuffer>'. Do you need to change your target library? Try changing the 'lib' compiler option to 'esnext' or later.


==== toFromHexBase64.ts (7 errors) ====
const arr1 = Uint8Array.fromBase64("AAAAAA==");
~~~~~~~~~~
!!! error TS2550: Property 'fromBase64' does not exist on type 'Uint8ArrayConstructor'. Do you need to change your target library? Try changing the 'lib' compiler option to 'esnext' or later.
const arr2 = Uint8Array.fromBase64("AAAAAA", { alphabet: "base64url" });
~~~~~~~~~~
!!! error TS2550: Property 'fromBase64' does not exist on type 'Uint8ArrayConstructor'. Do you need to change your target library? Try changing the 'lib' compiler option to 'esnext' or later.
const arr3 = Uint8Array.fromHex("000000");
~~~~~~~
!!! error TS2550: Property 'fromHex' does not exist on type 'Uint8ArrayConstructor'. Do you need to change your target library? Try changing the 'lib' compiler option to 'esnext' or later.

const encodedBase64_1 = arr1.toBase64();
const encodedBase64_2 = arr1.toBase64({ alphabet: "base64" });
const encodedBase64_3 = arr1.toBase64({ alphabet: "base64url", omitPadding: true });

const encodedHex_1 = arr1.toHex();

const target1 = new Uint8Array(10);
const r1 = target1.setFromBase64("AAAAAA==");
~~~~~~~~~~~~~
!!! error TS2550: Property 'setFromBase64' does not exist on type 'Uint8Array<ArrayBuffer>'. Do you need to change your target library? Try changing the 'lib' compiler option to 'esnext' or later.
const r2 = target1.setFromBase64("AAAAAA==", { lastChunkHandling: "strict" });
~~~~~~~~~~~~~
!!! error TS2550: Property 'setFromBase64' does not exist on type 'Uint8Array<ArrayBuffer>'. Do you need to change your target library? Try changing the 'lib' compiler option to 'esnext' or later.
const r3 = target1.setFromBase64("AAAAAA", {
~~~~~~~~~~~~~
!!! error TS2550: Property 'setFromBase64' does not exist on type 'Uint8Array<ArrayBuffer>'. Do you need to change your target library? Try changing the 'lib' compiler option to 'esnext' or later.
alphabet: "base64url",
lastChunkHandling: "stop-before-partial"
});

const target2 = new Uint8Array(10);
const r4 = target2.setFromHex("000000");
~~~~~~~~~~
!!! error TS2550: Property 'setFromHex' does not exist on type 'Uint8Array<ArrayBuffer>'. Do you need to change your target library? Try changing the 'lib' compiler option to 'esnext' or later.

const totalWritten = r1.written + r2.written + r3.written + r4.written;
const totalRead = r1.read + r2.read + r3.read + r4.read;

47 changes: 47 additions & 0 deletions tests/baselines/reference/toFromHexBase64(target=es2024).js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
//// [tests/cases/conformance/esnext/toFromHexBase64.ts] ////

//// [toFromHexBase64.ts]
const arr1 = Uint8Array.fromBase64("AAAAAA==");
const arr2 = Uint8Array.fromBase64("AAAAAA", { alphabet: "base64url" });
const arr3 = Uint8Array.fromHex("000000");

const encodedBase64_1 = arr1.toBase64();
const encodedBase64_2 = arr1.toBase64({ alphabet: "base64" });
const encodedBase64_3 = arr1.toBase64({ alphabet: "base64url", omitPadding: true });

const encodedHex_1 = arr1.toHex();

const target1 = new Uint8Array(10);
const r1 = target1.setFromBase64("AAAAAA==");
const r2 = target1.setFromBase64("AAAAAA==", { lastChunkHandling: "strict" });
const r3 = target1.setFromBase64("AAAAAA", {
alphabet: "base64url",
lastChunkHandling: "stop-before-partial"
});

const target2 = new Uint8Array(10);
const r4 = target2.setFromHex("000000");

const totalWritten = r1.written + r2.written + r3.written + r4.written;
const totalRead = r1.read + r2.read + r3.read + r4.read;


//// [toFromHexBase64.js]
const arr1 = Uint8Array.fromBase64("AAAAAA==");
const arr2 = Uint8Array.fromBase64("AAAAAA", { alphabet: "base64url" });
const arr3 = Uint8Array.fromHex("000000");
const encodedBase64_1 = arr1.toBase64();
const encodedBase64_2 = arr1.toBase64({ alphabet: "base64" });
const encodedBase64_3 = arr1.toBase64({ alphabet: "base64url", omitPadding: true });
const encodedHex_1 = arr1.toHex();
const target1 = new Uint8Array(10);
const r1 = target1.setFromBase64("AAAAAA==");
const r2 = target1.setFromBase64("AAAAAA==", { lastChunkHandling: "strict" });
const r3 = target1.setFromBase64("AAAAAA", {
alphabet: "base64url",
lastChunkHandling: "stop-before-partial"
});
const target2 = new Uint8Array(10);
const r4 = target2.setFromHex("000000");
const totalWritten = r1.written + r2.written + r3.written + r4.written;
const totalRead = r1.read + r2.read + r3.read + r4.read;
82 changes: 82 additions & 0 deletions tests/baselines/reference/toFromHexBase64(target=es2024).symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
//// [tests/cases/conformance/esnext/toFromHexBase64.ts] ////

=== toFromHexBase64.ts ===
const arr1 = Uint8Array.fromBase64("AAAAAA==");
>arr1 : Symbol(arr1, Decl(toFromHexBase64.ts, 0, 5))
>Uint8Array : Symbol(Uint8Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 3 more)

const arr2 = Uint8Array.fromBase64("AAAAAA", { alphabet: "base64url" });
>arr2 : Symbol(arr2, Decl(toFromHexBase64.ts, 1, 5))
>Uint8Array : Symbol(Uint8Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 3 more)
>alphabet : Symbol(alphabet, Decl(toFromHexBase64.ts, 1, 46))

const arr3 = Uint8Array.fromHex("000000");
>arr3 : Symbol(arr3, Decl(toFromHexBase64.ts, 2, 5))
>Uint8Array : Symbol(Uint8Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 3 more)

const encodedBase64_1 = arr1.toBase64();
>encodedBase64_1 : Symbol(encodedBase64_1, Decl(toFromHexBase64.ts, 4, 5))
>arr1 : Symbol(arr1, Decl(toFromHexBase64.ts, 0, 5))

const encodedBase64_2 = arr1.toBase64({ alphabet: "base64" });
>encodedBase64_2 : Symbol(encodedBase64_2, Decl(toFromHexBase64.ts, 5, 5))
>arr1 : Symbol(arr1, Decl(toFromHexBase64.ts, 0, 5))
>alphabet : Symbol(alphabet, Decl(toFromHexBase64.ts, 5, 39))

const encodedBase64_3 = arr1.toBase64({ alphabet: "base64url", omitPadding: true });
>encodedBase64_3 : Symbol(encodedBase64_3, Decl(toFromHexBase64.ts, 6, 5))
>arr1 : Symbol(arr1, Decl(toFromHexBase64.ts, 0, 5))
>alphabet : Symbol(alphabet, Decl(toFromHexBase64.ts, 6, 39))
>omitPadding : Symbol(omitPadding, Decl(toFromHexBase64.ts, 6, 62))

const encodedHex_1 = arr1.toHex();
>encodedHex_1 : Symbol(encodedHex_1, Decl(toFromHexBase64.ts, 8, 5))
>arr1 : Symbol(arr1, Decl(toFromHexBase64.ts, 0, 5))

const target1 = new Uint8Array(10);
>target1 : Symbol(target1, Decl(toFromHexBase64.ts, 10, 5))
>Uint8Array : Symbol(Uint8Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 3 more)

const r1 = target1.setFromBase64("AAAAAA==");
>r1 : Symbol(r1, Decl(toFromHexBase64.ts, 11, 5))
>target1 : Symbol(target1, Decl(toFromHexBase64.ts, 10, 5))

const r2 = target1.setFromBase64("AAAAAA==", { lastChunkHandling: "strict" });
>r2 : Symbol(r2, Decl(toFromHexBase64.ts, 12, 5))
>target1 : Symbol(target1, Decl(toFromHexBase64.ts, 10, 5))
>lastChunkHandling : Symbol(lastChunkHandling, Decl(toFromHexBase64.ts, 12, 46))

const r3 = target1.setFromBase64("AAAAAA", {
>r3 : Symbol(r3, Decl(toFromHexBase64.ts, 13, 5))
>target1 : Symbol(target1, Decl(toFromHexBase64.ts, 10, 5))

alphabet: "base64url",
>alphabet : Symbol(alphabet, Decl(toFromHexBase64.ts, 13, 44))

lastChunkHandling: "stop-before-partial"
>lastChunkHandling : Symbol(lastChunkHandling, Decl(toFromHexBase64.ts, 14, 24))

});

const target2 = new Uint8Array(10);
>target2 : Symbol(target2, Decl(toFromHexBase64.ts, 18, 5))
>Uint8Array : Symbol(Uint8Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 3 more)

const r4 = target2.setFromHex("000000");
>r4 : Symbol(r4, Decl(toFromHexBase64.ts, 19, 5))
>target2 : Symbol(target2, Decl(toFromHexBase64.ts, 18, 5))

const totalWritten = r1.written + r2.written + r3.written + r4.written;
>totalWritten : Symbol(totalWritten, Decl(toFromHexBase64.ts, 21, 5))
>r1 : Symbol(r1, Decl(toFromHexBase64.ts, 11, 5))
>r2 : Symbol(r2, Decl(toFromHexBase64.ts, 12, 5))
>r3 : Symbol(r3, Decl(toFromHexBase64.ts, 13, 5))
>r4 : Symbol(r4, Decl(toFromHexBase64.ts, 19, 5))

const totalRead = r1.read + r2.read + r3.read + r4.read;
>totalRead : Symbol(totalRead, Decl(toFromHexBase64.ts, 22, 5))
>r1 : Symbol(r1, Decl(toFromHexBase64.ts, 11, 5))
>r2 : Symbol(r2, Decl(toFromHexBase64.ts, 12, 5))
>r3 : Symbol(r3, Decl(toFromHexBase64.ts, 13, 5))
>r4 : Symbol(r4, Decl(toFromHexBase64.ts, 19, 5))

Loading