I think you ran into a subtle typescript typing bug that was fixed by the introduction of the strictFunctionTypes compiler option. We didn't turn on this on while I was there as there was a lot of stuff to fix if we did.
I think the issue is that you are declaring your renderers to be of type Renderer, which allows any type matching FieldValue as an argument.
Specifically:
// `renderField1: Renderer` means that `renderField1` is considered to be
// of type `Renderer` when used elsewhere. The type declaration of `(value: string) => ...`
// only matters within the context of the function, as the declaration takes precidence.
const renderField1: Renderer = (value: string) =>
`<div>${value}</div>`This type of annotation is actually an error, but (I think) wasn't caught until Typescript added the strictFunctionTypes compiler option.
Try turning it on in the options to see the error. The issue is that you really shouldn't be able to assing a function
of type (value: string) => string to a variable of type (value: string | boolean) => string, as the former accepts
a more limited type of argument.
I see two solutions:
- make the signatures of all your
renderFieldfunctions the same (and identical to theRenderertype). For example:
// the type of `value` is inferred by the `Renderer` annotation.
const renderField1: Renderer = value =>
// now that renderField is a generic `Renderer`, we need to check to make sure we have the right value.
typeof value === 'string' ? `<div>${value}</div>` : '';
const renderField2: Renderer = value =>
typeof value === 'boolean' ? (value ? `<div>YES</div>` : `<div>NO</div>`) : '';
const renderField3: Renderer = value =>
typeof value === 'object' ? `<div>${value.whatever}${value.somethingElse}</div>` : '';- Remove the
Rendererannoations onrenderFieldand check for the correct type ofvalueingetValuebefore passing it torenderer.
const renderField1 = (value: string) =>
`<div>${value}</div>`
const renderField2 = (value: boolean) =>
value ? `<div>YES</div>` : `<div>NO</div>`
const renderField3 = (value: ArbitrarilyComplexType) =>
`<div>${value.whatever}${value.somethingElse}</div>`
function getValue(id: FieldId, value: FieldValue) {
switch (true) {
case id === FieldId.FIELD_1 && typeof value === 'string': return renderField1(value);
case id === FieldId.FIELD_2 && typeof value === 'boolean': return renderField2(value);
case id === FieldId.FIELD_3 && typeof value === 'object': return renderField3(value);
}
}
👍