2

I'm having a bit of trouble getting they type assertions I'd like to have.

I have a function

const setSetting: SetSettingFn = (key, value) => {
    if (typeof settings[key] != null) {
        settings = {
            ...settings,
            [key]: value
        }
    }
}

with the SetSettingFn type of:

type SetSettingFn = (key: keyof AppSettings, value: AppSettings[keyof AppSettings]) => void

I'd like the value prop to know, based on the key that was entered the proper type to assert from that key. The above just kind of mashes all the types in AppSettings into one flat type with everything.

For example if settings.foo is boolean, then this should throw a type error: setSetting('foo', 1)

4
  • Couldn't you just do settings[key] = value instead of settings = {...settings, [key]: value}? Commented Jan 11, 2022 at 1:15
  • perhaps typeof AppSettings[keyof AppSettings]? Commented Jan 11, 2022 at 1:17
  • I could, right now typescript complains about that though - because of the improper typing for value. I went around that problem by desctructuring. The typing part is the actual issue, and I'm not sure how to tell typescript to narrow the type of value Commented Jan 11, 2022 at 1:21
  • AppSettings is a type, so it doesn't like typeof AppSettings, because its a type not a value Commented Jan 11, 2022 at 1:22

1 Answer 1

1

When you say, AppSettings[keyof AppSettings] you are allowing any key to be selected from AppSettings. You need to tell TypeScript that you mean the specific key that is the first parameter to be used to ascertain the value type. Something like this:

let settings: Record<string, any> = {};
const setSetting: SetSettingFn = (key, value) => {
    if (typeof settings[key] != null) {
        settings = {
            ...settings,
            [key]: value
        }
    }
}

type AppSettings = {
  foo: string;
  bar: number;
}

type SetSettingFn = < K extends keyof AppSettings = keyof AppSettings>(key: K, value: AppSettings[K]) => void

setSetting('foo', 1);
// Error: Argument of type 'number' is not assignable to parameter of type 'string'.(2345)

setSetting('foo', 'string');
// OK

Link to TS Playground: https://tsplay.dev/NDzv4W

Sign up to request clarification or add additional context in comments.

3 Comments

This works, could you explain what its actually doing? K extends keyof AppSettings = keyof AppSettings at first blush seems like its just renaming what I already had
I am restricting exact key here. I am saying, use the same key as parameter named key when determining type of value. If your case you are saying, parameter names could be any key AppSettings (which is fine), and the parameter named value can be of any value type mentioned in AppSettings. Mine is indicating that I want to use the same key's value type as the second param, yours is allowing any value type as long as it is in AppSettings.
That makes sense! Thank you so much!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.