Define Async function schema Using #hapi/joi package - javascript

I need to validate a property value which has type of "function" and assynchronous
below is the example code i'm using to define schema of the property: evaluate
`const Joi = require('#hapi/joi');
evaluate: Joi.func().default(evaluateFunc),`
but this returns promise instead of function when trying to run validate function, please let me know how to define this

Related

Best way to create empty json for typescript, or should I init with null?

Pretty simple question that I already have a solution for but it looks ugly to me.
I am trying to access local storage but I need to useEffect and if I want to extract the value from inside useEffect I need to instantiate before the codeblock in the higher scope.
Typescript does not accept var temp:JSON = {} So I have to do the cumbersome var temp:JSON = JSON.parse(JSON.stringify({})) which works. But it seems somewhat stupid to me that Javascript will randomly coerce my string into truthy values with == but can't coerce an empty Object into JSON.
JSON type is probably not what you need to be using for this. This type reflects an interface for converting data to/from JSON, aka the JSON global object in JavaScript.
Instead, you should create an interface that reflects the type of data stored in localstorage, then use that interface as the type for the parsed string from localstorage:
interface StoredObject {
name?: string;
kind?: string;
...
}
...
const [storedObject, setStoredObject] = useState<StoredObject>();
useEffect(() => {
const jsonString = localStorage.getItem(key);
setStoredObject(JSON.parse(jsonString));
}, []);
You can make it work like this:
const temp:JSON = {} as JSON;
However, you should consider why TypeScript returns an error:
error TS2739: Type '{}' is missing the following properties from type 'JSON': parse, stringify, [Symbol.toStringTag]
The type JSON is meant for the built-in JSON object and not for its output. In your case, temp is just a regular Object.
you can do like this:
let foo:JSON = {} as JSON;
I hope it help you.

Typescript complaining after passing ...args as argument to a function

I'm using fetch-mock library to build my own utils.
When defining a new function and passing args to fetchMock.mock function, I get this error:
A spread argument must either have a tuple type or be passed to a rest
parameter
export function mockRequest(...args: any) {
return fetchMock.mock(...args);
}
I could strictly define the amount of arguments, but would want to avoid it. Any suggestions how to keep ...args and make TypeScript happy?
I've tried various solutions such as using .apply and doing some casts as well but to no avail.
Problem
fetchMock.mock is typed to accept 0-3 arguments:
mock(matcher: MockMatcher | MockOptions, response: MockResponse | MockResponseFunction, options?: MockOptions): this;
mock(options: MockOptions): this;
mock(): this;
– wheresrhys/fetch-mock/types/index.d.ts:L270-L294
An attempt is made to spread an array of any into it. any will not stop TypeScript from checking the potential length of the spread – it will only not check the type of the items in the tuple are acceptable for the function parameters. An example:
function fn(a: number, b: number) {}
const foo: any[] = [];
const bar: [any, any] = ["one", "two"];
fn(...foo); // Not OK ❌
// ~~~~~~
// A spread argument must either have a tuple type or be passed to a rest parameter.
fn(...bar); // OK, even though we're passing in strings ✅
TypeScript Playground
Solution
The error message tells you the solution (emphasis mine):
A spread argument must either have a tuple type or be passed to a rest parameter.
Let's explore both of them.
Passing to a rest parameter
If the function is typed to accept a rest parameter it works because rest parameters are essentially an infinite list of optional parameters. However, in your case, you don't have control of the interface of the library. Consequently, you'll have to use the other option.
Type the argument as a tuple
Tuples are a list that have two notable properties. They are:
Finite. This guarantees the length will match the length of the arguments to the function you're attempting to use.
Ordered. This guarantees the type of a value at each index will match with the function's argument at the same index.
Using Parameters?
tl;dr this doesn't work, see the linked GitHub issues
TypeScript provides a utility function named Parameters which constructs a tuple type from the types used in the parameters of the function passed to it, so in theory you could do this:
function mockRequest(...args: Parameters<typeof fetchMock.mock>) {
return fetchMock.mock(...args);
}
TypeScript Playground
However at the time of writing, Parameters only returns the parameters from the last overload (see TypeScript issue 14107 and TypeScript issue 32164). In the above example, mockRequest would be typed to accept no parameters because the last overload of fetchMock.mock has no parameters.
Manual types
As lovely as it would've been to use Parameters. It looks like we'll have to manually add types. Here's a working example:
type Overload1 = [matcherOrOptions: MockMatcher | MockOptions, response: MockResponse | MockResponseFunction, options?: MockOptions];
type Overload2 = [matcherOrOptions: MockOptions];
type Overload3 = [];
type Args = Overload1 | Overload2 | Overload3;
function mockRequest(...args: Args) {
return args.length === 1 ?
fetchMock.mock(...args) :
args.length >= 2 ?
fetchMock.mock(...args as Overload1) :
fetchMock.mock();
}
TypeScript Playground
For an underdetermined reason, TypeScript isn't able to narrow the type of args to Overload1 with the condition args.length >= 2 so a cast is necessary.
Try making args an array type.
export function mockRequest(...args: any[]) {
return fetchMock.mock(...args);
}

Is it possible to let the interpreter know my method checks for undefined/null in TypeScript

For example I have a method isEmpty that checks if anything is empty, null, or undefined and returns true if so.
However in TypeScript it doesn't let the interpreter know that this is the case and I get a red underline in my IDE (WebStorm)
Example code
let str: string | undefined = undefined
if (!isEmpty(str)) {
doSomeWorkFunction(str) // this line is shows the error 'string | undefined is not assignable to type string
}
However if the code is
let str: string | undefined = undefined
if (str) {
doSomeWorkFunction(str) // no error because the interpreter knows I checked the value
}
The fix I would like to avoid is
let str: string | undefined = undefined
if (!isEmpty(str)){
// #ts-ignore
doSomeWorkFunction(str) // no error since ts is now ignoring this error
}
How might I go about still keeping the TypeScript strict null checks in place without having to ignore issues like this.
TypeScript has a feature called "type guards" that helps in this situation: https://www.typescriptlang.org/docs/handbook/advanced-types.html. Specifically, it lets you tell the compiler that the return type is not just a boolean, but a boolean that means something specific about the types of the inputs. For example, you can convert a function like this
function isDefinedString(input: string | undefined): boolean
into a function like this:
function isDefinedString(input: string | undefined): input is string
The return type is still a boolean, but now the compiler will assume that the input is specifically a string and not any other type allowed by the argument declaration (in this case undefined).
Try using this signature on your existing isEmpty function declaration. Although not required to make it work, because you are adding this additional context to the function signature I'd recommend changing the name of isEmpty to reflect its dual purpose of checking emptiness and whether the variable is defined.
Edit:
One caveat to returning type information is that returning false will make the compiler assume that the object is not that type. In the above example, if isDefinedString returns false then the compiler will assume that it is not a string. This runs into problems with any or generic parameters, because returning false effectively tells the compiler that there is no type (or in the compiler's words, there is "never" a type) that satisfies your criteria. While this doesn't result in an error directly, the fact that the compiler has no type that works with your object means you can't do anything meaningful with the object in the if/else branch triggered by your type guard returning false. As such, if you are using a broad type such as any or a generic, you will want to limit what your type guard says to something like input is (null | undefined) or input is MySpecificInterface if you plan to do something meaningful in both true and false cases. This trickiness may also be a sign that you want to separate your validation into two checks:
if(typeGuard(myObject)) {
if(isValid(myObject)) {
// do something with valid object
} else {
// do something with invalid object
}
}
// do nothing without an object to act upon

TS2532: Object is possibly 'undefined'. on array.map()

I understand that this TS error is essentially just a warning but I have been unable to find a solution when it occurs on .map
const files = require.context("./", true, /\.vue$/i);
files.keys().map(key =>
Vue.component(
key
.split("/")
.pop()
.split(".")[0],
files(key).default
)
);
I have tried checking if the value of key exists before doing anything else but it still produces the same error.
TS2532: Object is possibly 'undefined'.
You are trying to split a string. Using someString.split("/"), which does return an array. Using the method pop() does either return the last element of the array or undefined (according to MDN)
Therefore your typing at that point is: string | undefined executing .split(..) on an undefined value will cause problems. That's what TypeScript is trying to tell you here.
To avoid this warning/error and to be type safe you could use the latest optional chaining feature TypeScript 3.7.0 provides you if applicable:
key.split("/").pop()?.split(".")[0] ?? someDefaultString
An alternative solution would be to extract this kind of logic into another function like so:
function extractValue(key: string): string { // you want to name that function better though
return key.split("/").pop()?.split(".")[0] ?? "defaultValue";
}
And use it like:
Vue.component(extractValue(key), files(key).default)

TypeScript function to return nullable Promise

I'm trying to create a function that returns a Promise with values that can be resolved to null.
Basically something like this:
static getUserById(ids: String): Promise<?User> {
// do something
}
but it is returning an error
Generic type 'Promise' requires 1 type argument(s)
How to create a function in TypeScript that can return a Promise with nullable resolved values?
? means optionnal parameter not nullable type.
You should use this:
Promise<User|null>

Categories

Resources