I have a function that is used to change the type of an API input (simple dummy example given):
interface BaseInput {
version: '3' | '4';
}
interface InputA extends BaseInput{
version: '4';
foo: string;
}
interface InputB extends BaseInput{
version: '3';
bar: string;
}
const convert3to4 = (apiBodyInput: InputB) => {
return { version: '4', foo: apiBodyInput.bar } as InputA;
};
const convert4to3 = (apiBodyInput: InputA) => {
return { version: '3', bar: apiBodyInput.foo } as InputA;
};
// adapted from https://dev.to/maikelev/discriminated-unions-in-typescript-5fia#exhaustiveness-checking
function assertNever(version: never): never {
throw new Error(`Unrecognised api version: ${version}`);
}
export const changeApiVersion(apiBodyInput: InputA | InputB, targetVersion: '3' | '4') => {
if(apiBodyInput.version !== '3' && apiBodyInput.version !== '4'){
return assertNever(apiBodyInput.version)
}
switch(targetVersion) {
case '4':
return apiBodyInput.version === '3' ? convert3to4(apiBodyInput) : apiBodyInput;
case '3':
return apiBodyInput.version === '4' ? convert4to3(apiBodyInput) : apiBodyInput;
default:
return assertNever(targetVersion);
}
}
Hovering over each branch of the switch statement, TS knows each return can only be of one type. But when I use it (e.g. changeApiVersion({version: 3, bar: 'sad clown noise'}, 4) or similar) I get back the output is InputA | InputB
If I flip the logic to check apiBodyInput.version in the switch case, and the target version in the if/else I get the same issue (albeit now each case has a varied output), e.g.:
export const changeApiVersion(apiBodyInput: InputA | InputB, targetVersion: '3' | '4') => {
if(targetVersion !== '3' && targetVersion !== '4'){
return assertNever(targetVersion)
}
switch(apiBodyInput.version) {
case '3':
return targetVersion === '4' ? convert3to4(apiBodyInput) : apiBodyInput;
case '4':
return targetVersion === '3' ? convert4to3(apiBodyInput) : apiBodyInput;
default:
return assertNever(apiBodyInput.version);
}
}
Either case it doesn't seem to be narrowing down my types.
Where am I going wrong?