#Cannot inference ternary condition
12 messages · Page 1 of 1 (latest)
Yeah so typeof concatToString is going to be effectively the same as just writing boolean. In other words you'll always get a union. To prove this to yourself write:
declare const getStringValuesFunction: GetStringValuesFunction;
const result = getStringValuesFunction({ concatToString: false, includeFunction: true, includeCommas: true });
result; // This will be typed as `string | Array<[string | number, boolean]>` despite the explicit `concatToString: false`.
To solve it from the type perspective you need to make it generic:
type GetStringValuesFunction = <const ConcatToString extends boolean>(options: { includeFunction: boolean; includeCommas: boolean; concatToString: ConcatToString }) => ConcatToString extends true ? string : Array<[string | number, boolean]>;
To solve it exactly the way you've asked from the runtime perspective you probably have to explicitly cast the return type, TypeScript doesn't seem to infer conditional types as a return value:
type ConcatReturn<ConcatToString extends boolean> = ConcatToString extends true ? string : Array<[string | number, boolean]>;
function test<ConcatToString extends boolean>({ concatToString }: { includeFunction: boolean; includeCommas: boolean; concatToString: ConcatToString; }): ConcatReturn<ConcatToString> {
if (concatToString) {
return "foo" as ConcatReturn<ConcatToString>;
} else {
return [["hello", true]] as ConcatReturn<ConcatToString>;
}
}
To solve it the way I'd recommend would be overloads:
type GetValuesFunctionOptions = {
includeFunction: boolean;
includeCommas: boolean;
concatToString: boolean;
}
function test(options: GetValuesFunctionOptions & { concatToString: true }): string
function test(options: GetValuesFunctionOptions & { concatToString: false }): Array<[string | number, boolean]>
// Implementation
function test(options: GetValuesFunctionOptions): string | Array<[string | number, boolean]> {
if (options.concatToString) {
return "hello"
} else {
return [["hello", true]];
}
}
please note, this isn't any more sound. You could just have easily have written if (options.concatToString) { return [["hello", true]] } and gotten no warning.
It basically does the casts more implicitly but the signature is at least more honest as well.
In truth I'd recommend two functions; getValues and getValuesConcat or concatValues(getValues(...)) or something
Thanks for the response! I appreciate all of the various examples you've given. Took me a while to digest it but I learned a lot from it. I can see that when I have add function overloads or type casts it's probably a good sign that I should split the function up rather than try have it be responsible for everything.