interface SubProps1<T> {
foo: boolean
bar: string
baz: T
}
interface SubProps2<T> {
fooz: boolean
barr: string
bazd: Array<T>
}
interface Props<T> {
sub1: SubProps1<T>
sub2: SubProps2<T>
}
type CSSObjectWithLabel = Record<string, unknown>
type StylesConfig<T> = {
[K in keyof Props<T>]?: StylesConfigFunction<Props<T>[K]>;
}
type StylesConfigFunction<SubProps> =
(base: CSSObjectWithLabel, props: SubProps) => CSSObjectWithLabel;
function mergeStyles<T>(
nonColorStyles: StylesConfig<T>,
colorStyles: StylesConfig<T>,
): StylesConfig<T> {
type S = StylesConfig<T>
const result: S = {};
const uniqueKeys = new Set([
...Object.keys(nonColorStyles),
...Object.keys(colorStyles)
] as (keyof S)[])
function assigner<K extends keyof S>(key: K) {
result[key] = (base: CSSObjectWithLabel, props: Props<T>[K]): CSSObjectWithLabel => ({
...base,
...colorStyles[key]?.(base, props),
...nonColorStyles[key]?.(base, props)
})
}
return result;
}
We try to merge into result
object different functions with signature in accordance to the key value Type map defined by Props
interface.
We face an issue where Props<T>[K]
(inside assigner function, on the line we assign result[key]
is resolved as the following union SubProps1 | SubProps2
. Please refer to joined screenshot.
I understand it's not possible for TS to know the value of key in the assigner function, but its possible to say that the type of result[key]
for a given specific key correspond to the specific mapped StylesConfigFunction
, hence allowing only the correct SubProps
type and not the union of both types.
This looks like a TS limitation, but maybe this limitation is motivated by a reason I'm not aware of.
Is there any reason for this limitation? is it done on purposes? If not, is it possible to make TS smart enough for handling this case? Thanks a lot