Reputation: 9183
I've used typescript's conditional types with great success, but often I find that while I can express the type signatures, in the implementation of the functions I must use any
even though I know the implementation is correct.
Example, this definition:
type ExportType<InputType extends string|undefined> =
string extends InputType ? undefined : ()=>void;
function convert<InputType extends string|undefined>(input: InputType): ExportType<InputType>;
(I know I could use overloads, but my real issue is more complex and overloads wouldn't be realistic for the real issue)
In effect the signature is saying "if the parameter is string
, I'll return ()=>void
, if it's undefined
, I'll return undefined
.
And this works great. Playing with convert("x")
and convert(undefined)
shows that typescript agrees with this definition.
However when actually trying to implement this function:
type ExportType<InputType extends string|undefined> =
string extends InputType ? undefined : ()=>void;
function convert<InputType extends string|undefined>(input: InputType): ExportType<InputType> {
if (input) {
return ()=>{console.log("OK");};
} else {
return undefined;
}
}
This does not compile. Typescript says:
error TS2322: Type '() => void' is not assignable to type 'ExportType<InputType>'.
return ()=>{console.log("OK");};
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
But that line is in if (input)
, therefore at this point we know that the input is not undefined
, so it must be string
, and therefore we must return () => void
... But it seems the compiler is just not smart enough to see that.
Changing that line to:
return <any>(()=>{console.log("OK");});
Makes it work, but it's disappointing...
So is there a way to write a fully type-safe and checked implementation of this signature that typescript lets us express?
Upvotes: 0
Views: 296
Reputation: 250396
Typescript will not allow you to assign a value to an unresolved conditional type (ie one that still contains free type parameters). You can use a cast as you discovered or you can use a separate implementation signature:
type ExportType<InputType extends string|undefined> =
string extends InputType ? undefined : ()=>void;
function convert<InputType extends string|undefined>(input: InputType): ExportType<InputType>
function convert(input: string|undefined): undefined | (()=>void) {
if (input) {
return ()=>{console.log("OK");};
} else {
return undefined;
}
}
Upvotes: 2