6

Let's start with an apology for the overly generic question, but I am wrecking my head how to narrow it down due to lack of understanding of what's happening here, so will adjust based on comments / answers.

I have created a sample program on TypeScript Playground that should not compile but does (using latest version of TypeScript, v4.5.2 as of this writing.) I am trying to understand why this compiles in order to understand what other bad programs might sneak past the type checker and go undetected. Here is another version of the program that shows the problem at runtime. Are there any options I have overlooked or anything I can do to have this program not type check?

For convenience, I inline the program in question here as well:

type Settings = { 'a': boolean; 'b': string }

function setSetting<K extends keyof Settings>(p: K, v: Settings[K]): void {}

// setSetting('a', 100) // good; it fails
setSetting('a', true); // good; compiles

function breakSetSetting(k: keyof Settings, v: boolean): void {
  setSetting(k, v);
}

breakSetSetting('b', true); // bad; it compiles!

Update: As per comment by @crashmstr using generics for breakSettings makes the program not compile, however, it's still unclear to me why it was allowed to compile before.

3
  • 4
    If you use the same generics signature in the breakSetSetting, then you do get a compiler error there that you cannot just pass in a boolean v. As it is, the most the compiler knows is that the call into setSetting there is a string | bool for the second parameter and the v does "work" for that. Commented Dec 3, 2021 at 21:38
  • @crashmstr yup. You should probably write that as an answer. Commented Dec 3, 2021 at 21:42
  • Thanks, I have updated the question, however, I am still not sure why the previous program managed to compile at all Commented Dec 4, 2021 at 3:23

1 Answer 1

3

When you define K, you are defining it to be 'a' | 'b' (which is keyof K). This means that v would be Settings['a' | 'b'] which evaluates to boolean | string. Now when your breakSetSetting passes a boolean to setSetting, boolean is in the scope of boolean | string, making the compiler pass.

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

1 Comment

I think I am getting there, however, I do not understand why this is allowed to compile still. So to recap, my understanding of the problem is that when K is selected as a union, Settings[K] is a union as well and since unions are not ordered the actual values in those unions could mismatch. Edit: I can see how the first program compiles now. I wonder if the second version of the program I linked (that features the problem at runtime) is just implemented problematically using {...s, [p]: v}. Maybe there's a safer way to do that part?

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.