Typescript 5.9.x introduced changes to the ArrayBuffer type
See: https://devblogs.microsoft.com/typescript/announcing-typescript-5-9-rc/#notable-behavioral-changes
Notably, many standard APIs that expect a BufferSource will fail at a type-level when supplied with a default Uint8Array instead of Uint8Array<ArrayBuffer>.
For example the following code does not compile anymore in Typescript 5.9.x:
function createBuffer1(): Uint8Array {
return new Uint8Array(1);
}
fetch('url', { body: createBuffer1() });
But the following one does:
function createBuffer2(): Uint8Array<ArrayBuffer> {
return new Uint8Array(1);
}
fetch('url', { body: createBuffer2() });
See: https://www.typescriptlang.org/play/?#code/GYVwdgxgLglg9mABBATgUwIZTQIRMYNFARgAoBKALkQFUYwoAOAQRRQwE9EBvAKEQGJ0UECiRg0Ad1r0mrdh1LFyAbl4BfXr0JQIAC1IByUQBtDAGh6IARnAAmHaqkzY8BImXKJ1qraEiwCMjoWLj4hCgATBTUdAwsbJwAPPKcbhEAfDz8gsKi4lIy8amKymqa2mi6BsYoZpbcNvaOwS5h7lEU3r5AA
In particular the @noble/hashes library specifies the return types of the functions that return buffers as type Uint8Array, which then requires the library consumers to explicitly type-cast to Uint8Array<ArrayBuffer>, which is not best practice.
Would there be any chance to update the return types to Uint8Array<ArrayBuffer> ?
Do you have any alternative examples besides the code you’ve provided?
Would there be any chance to update the return types to Uint8Array<ArrayBuffer>
No because that would make code unusable in ts 5.5. Not everyone uses latest ts. Maybe in the future when most people switch to latest ts but definitely not in 2025.
This is piece of shit backwards incompatible change and I don’t agree with it from ts perspective. A bit of work was required to ensure the code works seamlessly between old and new ts. It’s so stupid, undocumented, and no one cares. See https://github.com/microsoft/TypeScript/issues/62240
Agreed, this backwards incompatible change is a mess and I agree that there is no way to write code that's working for both TS < 5.6 and TS >= 5.6.
For reference, it looks like this BufferSource type is being used a bit everywhere in the Web API wherever a buffer is expected. Here are some places in my codes where it fails:
function createBuffer1(): Uint8Array {
return new Uint8Array(1);
}
function createBuffer2(): Uint8Array<ArrayBuffer> {
return new Uint8Array(1);
}
async function test() {
await fetch('url', { body: createBuffer1() }); //fails
await fetch('url', { body: createBuffer2() });
const key1 = await crypto.subtle.importKey('raw', createBuffer1(), 'PBKDF2', false, ['deriveBits']); //fails
await crypto.subtle.deriveBits({ name: 'PBKDF2', hash: 'SHA-256', salt: createBuffer1(), iterations: 2048 }, key1, 256); //fails
crypto.subtle.encrypt({ name: 'AES-GCM', iv: createBuffer1() }, key1, createBuffer1()); //fails
const key2 = await crypto.subtle.importKey('raw', createBuffer2(), 'PBKDF2', false, ['deriveBits']);
await crypto.subtle.deriveBits({ name: 'PBKDF2', hash: 'SHA-256', salt: createBuffer2(), iterations: 2048 }, key1, 256);
crypto.subtle.encrypt({ name: 'AES-GCM', iv: createBuffer2() }, key2, createBuffer2());
await crypto.subtle.importKey('pkcs8', createBuffer1(), { name: 'RSASSA-PKCS1-v1_5', hash: 'SHA-256' }, false, ['sign']); //fails
await crypto.subtle.importKey('pkcs8', createBuffer2(), { name: 'RSASSA-PKCS1-v1_5', hash: 'SHA-256' }, false, ['sign']);
new Blob([createBuffer1()]); //fails
new Blob([createBuffer2()]);
new CompressionStream('gzip').writable.getWriter().write(createBuffer1()); //fails
new CompressionStream('gzip').writable.getWriter().write(createBuffer2());
}
Here is a link to a typescript playground with that same code: https://www.typescriptlang.org/play/?#code/GYVwdgxgLglg9mABBATgUwIZTQIRMYNFARgAoBKALkQFUYwoAOAQRRQwE9EBvAKEQGJ0UECiRg0Ad1r0mrdh1LFyAbl4BfXr1CRYCZOiy58hFACYK1OgxZtOAHnmc8BIgD4e-QcNHipMmydFZTVNXgwAZw5IRB1oeCRsCKgKT0FEDEkMGChYtCgIAAtSAHJRABsSgBoeRAAjOAATDmpUTGwXUzJyRHVVRAB6AeBs8oivAUzs3MIC4rKUSprueqaWg3bjV3NUvrUJ5ARkxABrNA5iRABeDKycgw4AByg4ADoIkDqocrRXmABbR5wFBQADS51K7Ek1Q2Rk6RG6NRKAAUcKCACIAMTMMJGYzQNQA2iVGkQYAA3XA5CIlAC6-SGIxgYwOU3uqCeL3en2+v1JKApVKgEVIKzAGH+aGoKLRWJxNUKkUK0oAygAJZgAWjMAFYAGwwiIYcpQVqGDomBEUGo5IhYBIRahmAAMABZGL0amcLjVdXqGcNRuN0hznm8Pl8fq80JAUJzRYhxZLpcwAKIqzUAcQAwgBZGEUs2beEkXZe87EGptOGW0vkANMlkHCBHXLeszXW7TB5h7mR34AoEg8GKEpQmHVi3bCzkJGojHY3HGiIExDE-mCnDUumqVl3XKhrkR3mvDeUrfChNJqWIGUL+WIRURZW39Vav2G42m2FT0wzm3YOwehgI6iAuu6nqnBWvr6ruIZxr2x5RjGh5XhKN4lGmGY5vmNrkkWNbTmWUEcGYVbmlsf4ULue7doe4Y8lGg7AmCEIlI8JwQBEjAThRJaIrU17SgASiqzAqmJmrIqC2YqsQmrksQAD6Oowk+L4lG+2r6iUkF4iuRIlBEMAAOZgDuKiDIGzLBoIbIHghR6MQOgIsSOpQcVxPHkcWtb-oJ6EiWJElatJsnyYpKlqUqqoatpBp6cuq7EsZZkWQcBwSNIODlHAdSkISk6UVa5D0pZjJBpl-g5XlBVFSWM5lVo6RZYg2ZwIC6ARMZCAqlAhj-KUJkAF4wI8JTkK8kgClAGB1FGJn5AA6jNRAUFNq2kPVtbdA2lUtf47WdWg3UJH1A1DaN42TdNORzQty2rSg623dgW18X51GhLwQA
For crypto.subtle we have new webcrypto submodule which simplifies everything. Strongly recommend it.