Reputation: 3190
I feel like I'm missing something extremely simple here - or that it's completely impossible. But given
interface ITest {
prop1: number
prop2: string
}
const obj: ITest = { prop1: 10, prop2: 'asd' };
const func = (newValue: {???}) => {
obj = {...obj, ...newValue};
}
How can I make it so newValue must be an object who's key name must exist in ITest, and who's value must the the type as defined in ITest[key]. Something like:{ [key in keyof IEditorStore ]: any }
but the only accepted value type is really only { prop1: number } or { prop2: string }.
Upvotes: 1
Views: 875
Reputation: 32236
One straightforward way to do this would be to use the Partial
helper and have your argument be of the type Partial<ITest>
. This will restrict it to be an object with only known keys but doesn't enforce that there is only a single key (or any at all). Eg,
const func = (newValue: Partial<ITest>) => {
obj = {...obj, ...newValue};
}
func({}); // No keys is fine.
func({prop1: 1, prop2: "a"}); // Also including both is fine.
If you want to ensure that you don't pass an empty object as an argument, you can change this to require that at least one key always be present:
type KeyValueOf<T extends {}> = {[K in keyof T]: Pick<T, K>}[keyof T];
const func = (newValue: KeyValueOf<ITest>) => {
obj = {...obj, ...newValue};
}
func({}); // This is no longer allowed, produces an error.
func({prop1: 1, prop2: "a"}); // Both keys still allowed
I don't think there is a way to prevent both keys being allowed here.
Upvotes: 1
Reputation: 215117
If the parameter object contains only one key, how about separating it into two parameters, so you can type them correspondingly:
const func = <K extends keyof ITest>(key: K, val: ITest[K]) => {
obj[key] = val;
}
Upvotes: 2