Is there a difference between typescript void and Promise< void > types?
Asking because I got confused why this is a valid typescript?
const asyncFunc: () => void = async () => {
await new Promise(resolve => resolve());
};
Shouldn't this be the only valid case?
const asyncFunc: () => Promise<void> = async () => {
await new Promise(resolve => resolve());
};
When a function definition has a void return type, it means the function must not return anything. If you need to resolve the Promise with a value of another type, pass the specific type to the generic. index.ts.
promise<void> may be used to create future<void> objects which have no value. In addition, a promise<void> can be constructed from a promise<T> where T is any type. This allows a promise<void> to be used by code which only needs to be able to renege on a promise and not fulfill it.
According to the TypeScript docs: void represents the return value of functions which don't return a value. Whenever you see a function returning void , you are explicitly told there is no return value. All functions with no return value have an inferred return type of void .
Use the Awaited utility type to get the return type of a promise in TypeScript, e.g. type A = Awaited<Promise<string>> . The Awaited utility type is used to recursively unwrap Promises and get their return type.
Yes there's a difference
void is a little like the opposite of any: the absence of having any type at all. You may commonly see this as the return type of functions that do not return a value
I guess Promise<void>
doesn't require explanation.
Now why the assignment in the question is allowed? Because target function (() => void
) can be called in all (*almost) the same situations as the source function. Have a look at simplified example:
declare let voidFunc: () => void;
declare let promiseFunc: () => Promise<void>;
voidFunc = promiseFunc; // OK
promiseFunc = voidFunc; // Error: Type 'void' is not assignable to type 'Promise<void>'
When you declare a variable with () => void
type, you are basically saying that it could be any function. So its value (function) could return anything. Take a look at this playground. I put there a few more function implementations to you to see that declaring a variable that receives a function is different than declaring a function itself.
Declaring the function itself has the behavior you expected.
const asyncFunc: () => void = async () => {
await new Promise(resolve => resolve());
};
const asyncFunc2: () => Promise<void> = async () => {
await new Promise(resolve => resolve());
};
const asyncFunc3 = async () => {
await new Promise(resolve => resolve());
};
// TS compiler complains about it
async function asyncFunc4(): void {
await new Promise(resolve => resolve());
}
async function asyncFunc4(): Promise<void> {
await new Promise(resolve => resolve());
}
Edit: Found this little explanation. It could help you understand it too. It says:
Do use the return type void for callbacks whose value will be ignored. Why: Using void is safer because it prevents you from accidentally using the return value of x in an unchecked way
This will work as well (notice that this is not even an async function):
const asyncFunc: () => void = () => {
return Math.random() > 0.5 ? 'hello' : 'world';
};
// OR this:
const asyncFunc2: () => void = () => {
return { nice: 'very '};
};
why?? Basically, you can have typescript interpret the types itself, or you can set a specific type to a constant.
Here, you defined a constant called asyncFunc
, which is of type () => void
. This means that typescript will disregard the return value of the function when defining the type. Think of it as if the user don't expect a value, so returning a value should still work fine and not break the code.
asyncFunc
??If you define the type of the constant yourself, the type will be () => void
, so the user won't expect any return value:
But if you let typescript interpret this itself, it should know the correct value.
So, for the function defined above (without the async), it will be () => string
:
specifically for the case of defining a function as () => void
, the function won't check the return value at all and you can return anything (even a promise).
Defining a function as async will just wrap the return value in a promise, which the () => void
type will just ignore.
If you want to define a different type of the return value than the interpreted type, you can define an async function to return a specific promise with a nested type.
Something like this for your example:
const asyncFunc: () => Promise<void> = async () => {
await new Promise(resolve => resolve());
};
The thing is, that this will happen automatically without the type definition:
So it's pretty redundant. you can just let typescript interpret the types unless you want to change the return type to something else.
So, in the example that might return hello
or world
we might want to let the user know that the return value can be any string instead of these two values.
Then, it makes sense to change the definition of the return value to something else:
You can combine any of these to achieve a workflow you like, but be aware that () => void
is kind of a special case with this type system (since any other return value besides void
will throw a type error.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With