Issue
Is there a way to assert that a function returns a value that has type of the value given as an argument to the function, yet keep the wider argument type restrictions than of the original value?
Example:
I want to trim a string value, but if the value is null
or undefined
, I want it to return the original null
or undefined
.
function trimOrOriginal(value?: string | null) {
return value ? value.trim() : value;
};
Let's say I have non-optional field of type string | null
. If I want to trim this field and assign the trimmed value to the original variable, I get a compiler error because the trimOrOriginal
can return undefined
even though I know it can never be undefined
as the value I gave for the parameter is never undefined
.
I could use generics:
const trimOrOriginal = <T>(value: T) => {
if (typeof value === "string") {
return value.trim();
}
return value;
};
But this doesn't look nice. I would like to specify that the argument type has to be "string".
Solution
You want to infer the return type based on the argument type.
const example1 = trimOrOriginal(null) // inferred type null
const example2 = trimOrOriginal("bla") // inferred type string
let input: string | undefined = "blub"
const example3 = trimOrOriginal(input) // inferred type string | undefined
For this you need to use generic types and type constraints. There is no way to do this without generics. That said, an implementation could look like this:
const trimOrOriginal = <T extends string | null | undefined >(s: T) =>
(typeof s === 'string' ? s.trim() : s) as T extends string ? string : T
The conditional return type is necessary to widen string literals to strings:
type SL = "a " | "b " // constructed example
const a: SL = "a "
const example4 = trimOrOriginal(a) // inferred type is now string, not SL!
const sl: SL = trimOrOriginal(a) // type error, string is not assignable to SL
In real life, just use s?.trim()
:-)
Answered By - Christian Rodemeyer
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.