Reputation: 1685
I am quite new to TS and wrote a pick function but finding it difficult to pick from an intersection type:
type PaletteType = {
black: string,
white: string
}
type ColorType = {
primaryColor: string,
labelText: string,
}
type Props = {
...,
backgroundColor: keyof ColorType | keyof PaletteType // (or would keyof (ColorType & PaletteType) would be better?
}
// Some general pick funtion
function pick<T extends { [key: string]: any }, K extends keyof T>(object: T, key?: K) {
if (key) { return object[key] }
return undefined
}
pick(Colors, props.backgroundColor) // error -> black | white not assignable to Colors
I am quite sure my 'solution' is kinda wrong:
backgroundColor: pick(Palette as typeof Palette & typeof Color, props.bg) || pick(Color as typeof Palette & typeof Color, props.bg),
Upvotes: 1
Views: 869
Reputation: 328302
Adding these declarations to make the code compile:
declare const Colors: ColorType;
declare const Palette: PaletteType;
declare const props: Props;
In order to make your call to pick()
type safe you can either merge Colors
and Palette
via something like object spread:
pick({ ...Colors, ...Palette }, props.backgroundColor); // okay
That works because {...Colors, ...Palette}
is seen to be of type ColorType & PaletteType
, whose keys are keyof ColorType | keyof PaletteType
.
Or, you can make a user-defined type guard to narrow props.backgroundColor
to either keyof ColorType
or keyof PaletteType
before calling pick()
:
const hasKey = <T extends object>(obj: T, key: keyof any): key is keyof T => key in obj;
hasKey(Colors, props.backgroundColor) ?
pick(Colors, props.backgroundColor) :
pick(Palette, props.backgroundColor); // okay
The former is probably neater.
By the way, I'm not sure what pick(o,k)
buys you over just o[k]
, but that's up to you I guess.
Hope that helps; good luck!
Upvotes: 2