node-argon2
node-argon2 copied to clipboard
Cannot convert literal false to boolean type when calling overloaded hash function with defined options
Welcome to the issues section if it's your first time!
Steps to reproduce
- Install typescript 3 or later
- Enable strict type checking for typescript
- Enable strict null checks for typescript
- Attempt a hash with an options object:
tsc
// This must be in a function body so await keyword below works. Can't use await in a module body.
import {argon2id, hash, Options} from "argon2";
const secretBuffer = new Buffer("example-pepper", "ascii");
const options: Options = {
hashLength: 32,
saltLength: 16,
type: argon2id,
memoryCost: 1<<14,
parallelism: 1,
timeCost: 2,
secret: secretBuffer,
}
const password = "password";
const hashString: string = await hash(password, options)
Expected behaviour
Should hash password
Actual behaviour
error TS2769: No overload matches this call.
Overload 1 of 2, '(plain: string | Buffer, options: Options & { raw: true; }): Promise<Buffer>', gave the following error.
Argument of type 'Options' is not assignable to parameter of type 'Options & { raw: true; }'.
Type 'Options' is not assignable to type '{ raw: true; }'.
Types of property 'raw' are incompatible.
Type 'boolean | undefined' is not assignable to type 'true'.
Type 'undefined' is not assignable to type 'true'.
Overload 2 of 2, '(plain: string | Buffer, options?: (Options & { raw?: false | undefined; }) | undefined): Promise<string>', gave the following error.
Argument of type 'Options' is not assignable to parameter of type 'Options & { raw?: false | undefined; }'.
Type 'Options' is not assignable to type '{ raw?: false | undefined; }'.
Types of property 'raw' are incompatible.
Type 'boolean | undefined' is not assignable to type 'false | undefined'.
Type 'true' is not assignable to type 'false | undefined'.
66 const hash: string = await hash(password, options)
Environment
Operating system: Windows 10 Pro 21H1 build 19043.1052
Node version: v16.4.0
Compiler version: Microsoft (R) C/C++ Optimizing Compiler Version 19.29.30038.1 for x64
This may be a limitation of typescript and if so a workaround would be changing this:
export interface Options {
hashLength?: number;
timeCost?: number;
memoryCost?: number;
parallelism?: number;
type?: 0 | 1 | 2;
version?: number;
salt?: Buffer;
saltLength?: number;
raw?: boolean;
secret?: Buffer;
associatedData?: Buffer;
}
To this:
export interface Options {
hashLength?: number;
timeCost?: number;
memoryCost?: number;
parallelism?: number;
type?: 0 | 1 | 2;
version?: number;
salt?: Buffer;
saltLength?: number;
raw?: true|false;
secret?: Buffer;
associatedData?: Buffer;
}
I'm not sure if that'll work though, nor how backwards compatible is. I've worked around it with a // ts-ignore when calling hash.
The problem is that the output type changes depending on the raw parameter, which makes it cumbersome to type.
However, we have automated testing for the Typescript interface and it tests all the parameter values, so it may be a misconfigured option on your side
The issue is defining the variable using just the Options
type from the library, because of the typing issue mentioned above. I did try coming up with some new type definitions but the closest I got was deleting & {raw?: false}
from the hash function type that had options
as an optional parameter:
export function hash(plain: Buffer | string, options: Options & {raw: true}): Promise<Buffer>;
export function hash(plain: Buffer | string, options?: Options): Promise<string>;
This at least lets the code above compile, however a caveat of this is that if you pass in a variable with type Options
and not Options & {raw: true}
it will need to be casted to a Buffer
as TypeScript will then match the latter type regardless of what, if anything, raw
is set to. That said - if it's an anonymous object (i.e., passed in directly, then the typing works correctly so it's a small price to pay I guess).
As a workaround for an individual project using the library, you can simply append either & { raw?: false }
or & { raw: true }
to the Options
type from argon2
- or even have both objects to hand, as shown below:
import { argon2id, Options as Argon2HashingOptions } from "argon2";
export const myAppHashingOptions: Argon2HashingOptions & { raw?: false } = {
type: argon2id,
timeCost: 8,
raw: false,
};
export const myAppRawHashingOptions: Argon2HashingOptions & { raw: true } = {
...clubGuardHashingOptions,
// Will override 'raw: false' from the other object.
raw: true
};
This problem shouldn't happen anymore with the latest version, and the types have been improved.