function isUndefined (payload: any): payload is undefined | void {
return payload === undefined
}
In TypeScript, I have a function that can return either something or undefined
or void
.
Something like an event handler that can return a modified payload or the dev can choose to return nothing or undefined in case they won't modify the payload:
function eventHandler <T extends {[key: string]: any}> (payload: T): Modified<T> | undefined | void {
// ... implementation
}
Then I have a type checker that needs to check if it's returning something other than void or undefined:
const result = eventHandler(payload)
if (result !== undefined) {
// we have a modified payload!
}
However, is the above snippet I get an error because it says that even though result !== undefined
it can still be void
?
In my opinion, I think it's peculiar because void
should be the same as undefined
.
So I made this type checker that solves it:
function isUndefined (payload: any): payload is undefined | void {
return payload === undefined
}
This solves my issue, but my question is:
Is this OK? Or is it bad practice?
void
is not undefined
. void
means the absence of a return value. undefined
is the type of the value undefined at runtime.
it is true that a function that returns no value at run time returns undefined
, but in the TS type system we chose to make the absence of a return value special.
For example assigning (a) => void to (a) => number | undefined
(a) => void to (a) => number | undefined
is likely an error, though it is safe at run-time.
In general do not use void except in the return type of functions. for everything else, use undefined
.
So, yes we will need to use different check for undefined
and void
.
I think you're making this more complicated that it needs to be. A function that returns void
can:
return;
statement with no value specified.return undefined;
statement. In pure javascript, all of the above would have a return value of undefined
. If you say a function returns undefined
, then you can only do #2 and #3 from the above list.
So you can just have a function type that unions void
with whatever something you want.
function foo(): string | void {
return Math.random() > 0.5 ? 'abc' : 123
}
const val = foo()
if (val === undefined) {
console.log('is undefined', val)
} else {
console.log('is some value', val)
}
This means that you could create a generic function type that modifies payloads like so:
type PayloadModifier<T extends {[key: string]: any}> = (payload: T) => T | void
const setMaxAsTen: PayloadModifier<{a: number}> = (payload) => {
if (payload.a > 10) {
return { a: 10 }
}
return undefined // required unless noImplicitReturns is false
}
const val = setMaxAsTen({a: 5})
if (val === undefined) {
console.log('is undefined', val)
} else {
console.log('is some value', val)
}
Last thing to note is that there is a compiler option that is good to leave on called noImplicitReturns
. if a function declares a return value in any execution branch, then a return value must be declared in every execution branch. So because the above sometimes returns a value, you must explicitly return undefined
if you don't to return a payload. You can toggle off that option, allowing you to omit that line, but it's not recommended as it does help you catch some bugs.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.