Correct JSDoc signature for is_string function? - jsdoc

I have the following function of type (obj:any)=>boolean that determines whether an object is string or not.
I want the JsDoc to be "smart" so that whenever I use if(isString(x)){ ...block... }, the highlighter treats x inside the block as a string.
So far I tried this without success:
/** #type {((obj:string)=>true)|((obj:any)=>false)} */
function isString(obj) {
return Object.prototype.toString.call(obj) === "[object String]";
}
How can I do it properly?

The following should do the trick. It uses the Typescript's narrowing with type predicates.
/** #type {(obj: any) => obj is String} */
function isString(obj) {
return Object.prototype.toString.call(obj) === "[object String]";
}

Related

Ethers how to encode data to bytes parameters

I'm trying to test a piece of generic solidity code, I'm trying to figure out how to encode data properly for bytes parameters.
I have a function in a smart contract which looks like so:
function validateAdditionalCalldata(bytes calldata resolverOptions) external view;
function resolve(uint256 amountIn, bytes calldata resolverOptions) public override returns (uint256 amountOut) {
// Decode the additional calldata as a SwapResolverOptions struct
(SwapResolverOptions memory swapResolverOptions) = abi.decode(resolverOptions, (SwapResolverOptions));
return resolveImplementation(amountIn, swapResolverOptions);
}
This solidity code will generate code which takes in a PromiseOrValue<BytesLike>:
resolve(
amountIn: PromiseOrValue<BigNumberish>,
resolverOptions: PromiseOrValue<BytesLike>,
overrides?: Overrides & { from?: PromiseOrValue<string> }
): Promise<ContractTransaction>;
export type SwapResolverOptionsStruct = {
path: PromiseOrValue<BytesLike>;
deadline: PromiseOrValue<BigNumberish>;
amountIn: PromiseOrValue<BigNumberish>;
amountOutMinimum: PromiseOrValue<BigNumberish>;
inputTokenAddress: PromiseOrValue<string>;
targetAddress: PromiseOrValue<string>;
destinationAddress: PromiseOrValue<string>;
};
I'm wondering how I can encode a specific parameter so I can pass it along to ethers. In typescript I have a set of options that looks like this:
const resolverOptions: SwapResolverOptionsStruct = {
path: '0x00',
//This parameter will be removed in the next deployment
deadline: BigNumber.from(1000),
amountIn: BigNumber.from(100000000),
amountOutMinimum: BigNumber.from(0),
inputTokenAddress: WMATIC_MUMBAI,
destinationAddress: owner.address,
targetAddress: ADDRESS_ZERO,
};
I'm trying to encode this parameters in the following way:
import { defaultAbiCoder } from "#ethersproject/abi";
encodedResolverOptions = defaultAbiCoder.encode(
['SwapResolverOptionsStruct'],
[resolverOptions]
);
However when I try to encode it gets and error:
Error: invalid type (argument="type", value="SwapResolverOptionsStruct",
Note: in my paticular use case I cannot just encoded the whole function call.
I would like to pass my data to the validateAdditionalCalldata how ever the parameter is PromiseOrValue<BytesLike>
How can I encoded my resolverOptions so I can pass it as bytes?
I figured out a few way to do this. I'll list each one:
Resolve the type params using ethers and get function. (if there is a function which has your type in it)
const functionFragment = swapResolverInterface.getFunction("resolveImplementation");
encodedResolverOptions = defaultAbiCoder.encode(
[functionFragment.inputs[1]],
[resolverOptions]
);
Resolve it from an object and a method signature with parameter names:
encodedResolverOptions = defaultAbiCoder.encode(
["(bytes path,uint256 deadline,uint256 amountIn,uint256 amountOutMinimum,address inputTokenAddress,address destinationAddress,address targetAddress)"],
[resolverOptions]
);
Resolve it as an array from the method signature without names Note: this assumes the object was declared in the same order as the parameters, alternatively you can manually construct the array:
encodedResolverOptions = defaultAbiCoder.encode(
["(bytes,uint256,uint256,uint256,address,address,address)"],
[Object.values(resolverOptions)]
);

Are there any differences between "any" and "*"?

Looking at https://github.com/gajus/eslint-plugin-jsdoc, it seems like {any} and {*} are interchangeable.
However, https://github.com/google/closure-compiler/wiki/Types-in-the-Closure-Type-System makes no mention of {any}, and differentiates between "any" and "all".
Is there a difference between any and *?
Checking the sources of the Typescript compiler (The one that parses the JSDoc for typings) it shows that any, * (JSDoc ALL Type) and ? (JSDoc Unknown/ANY Type) are treated the same:
TypeScript/src/compiler/checker.ts
function getTypeFromTypeNodeWorker(node: TypeNode): Type {
switch (node.kind) {
case SyntaxKind.AnyKeyword:
case SyntaxKind.JSDocAllType:
case SyntaxKind.JSDocUnknownType:
return anyType;
// ...
Also, the logic for the Javascript to Typescript file transformer does the same:
TypeScript/src/services/codefixes/annotateWithTypeFromJSDoc.ts
function transformJSDocType(node: TypeNode): TypeNode {
switch (node.kind) {
case SyntaxKind.JSDocAllType:
case SyntaxKind.JSDocUnknownType:
return factory.createTypeReferenceNode("any", emptyArray);
// ...

Can we use JSDoc #this when passing a function literal as an argument

With JSDoc, I know you can use #this when declaring a function with
/** #this {{foo: string}} */
const myFunc = function() {
console.log(this.bar) // this will NOT type-check
return this.foo // this will type-check
};
I'd like to be able to do the same when passing a function literal as an argument. This would look something like:
functionDefinedSomewhereElse(/** #this {{foo: string}} */ function() {
return this.foo // this will NOT type-check
});
The above code does not work though…
Is this even possible ?

VSCode IntelliSense does not autocomplete JavaScript DOM events and methods

I am using Visual Studio Code version 1.17.1.
In *.js file when I type document.querySelector("#elementId").style. I have no IntelliSense hints for styles (like margin, display, etc.).
Even no onclick event hint after document.querySelector("#elementId").
I don't use any npm packages. It is just simple html\css\js project.
How to turn on correct IntelliSense hints? Thanks.
Because result of the querySelector is either:
Element - the most general base class or null
If you already know id you can use document.getElementById() - which returns instance of more specific class - HTMLElement - autocomplete will work as expected.
document.getElementById('elementId').
If you don't know id, but want autocomplete you can use JSDoc type annotations:
/** #type {HTMLElement} */
var el = document.querySelector(".myclass");
el.
// or without extra variable:
/** #type {HTMLElement} */
(document.querySelector(".myclass")).
I haven't really tested it but you can try something like that:
/**
* #type {function(string): HTMLElement}
*/
var querySelector = document.querySelector.bind(document);
querySelector('.myclass').
Another choice would be alter typescript types:
Create file dom.d.ts
Append to it:
interface NodeSelector {
querySelector<K extends keyof ElementTagNameMap>(selectors: K): ElementTagNameMap[K] | null;
querySelector<E extends HTMLElement = HTMLElement>(selectors: string): E | null;
querySelectorAll<K extends keyof ElementListTagNameMap>(selectors: K): ElementListTagNameMap[K];
querySelectorAll<E extends HTMLElement = HTMLElement>(selectors: string): NodeListOf<E>;
}
Now querySelector returns HTMLElement.
The other answer points to the correct answer – type casting with jsdoc – but I've found that this only works consistently when you do it exactly as typescript wants when dealing with union types: you need to wrap the casted expression in parentheses and place the type cast doc on the same line. The snippet from a permalink to the wiki:
// We can "cast" types to other types using a JSDoc type assertion
// by adding an `#type` tag around any parenthesized expression.
/**
* #type {number | string}
*/
var numberOrString = Math.random() < 0.5 ? "hello" : 100;
var typeAssertedNumber = /** #type {number} */ (numberOrString)

Difference between param[out] and return in doxygen?

What is the difference between \param[out] and \return in Doxygen? They both seem to document the output / return of a function. Is the difference due to void functions which don't have a return value and only param[out] would be valid?
Out parameters are different from return values. Take this example in C:
/**
* \param[in] val Value calculations are based off.
* \param[out] variable Function output is written to this variable.
*
* \return Nothing
*/
void modify_value(int val, int *variable)
{
val *= 5;
int working = val % 44;
*variable = working;
}
The function returns nothing, but the value to which variable points is changed, hence we call it an output parameter. It represents an 'output' of the function in that we expect it to be modified somehow by the function. val, on the other hand, is an 'input' parameter because it is not modified (and, indeed, cannot be modified from the perspective of the function's caller, since it is passed as a value).
Here's a slightly more useful and realistic example:
typedef struct data {
int i;
int j;
...
} data;
/**
* \param[in] val Initialising parameter for data.
* \param[out] dat Data pointer where the new object should be stored.
*
* \return True if the object was created, false if not
* (i.e., we're out of memory)
*/
bool create_data(int val, data **dat)
{
data *newdata;
newdata = (data*)malloc(sizeof(data));
if(newdata == NULL)
{
*dat = NULL;
return false;
}
newdata->i = val;
*dat = newdata;
return true;
}
In this case, we construct some complex object inside the function. We return a simple status flag that lets the user know the object creation was successful. But we pass out the newly-created object using an out parameter.
(Although, of course, this function could easily just return a pointer. Some functions are more complex!)
As a simpler answer, [out] parameters are only for results returned via parameters not the return value. It is quite reasonable to have a function which has a return value and also has optional return data, eg: one I'm just writing has the signature:
/**
Determine UTF type of a file.
Unless a UTF8 file has a BOM, it is regarded as unknown.
#param [in] path Path to file suitable for ifstream
#param [out] bomWasFound optional return flag to indicate a BOM was found, really only useful for UTF8
#return an enum indicating type, default utf_unknown
*/
UtfType CheckFileType(const std::string& path, bool* bomWasFound=0);