Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Writes to indexed access of an index signature are not sufficiently constrained #60703

Open
mkantor opened this issue Dec 6, 2024 · 5 comments
Labels
Experimentation Needed Someone needs to try this out to see what happens Suggestion An idea for TypeScript

Comments

@mkantor
Copy link
Contributor

mkantor commented Dec 6, 2024

🔎 Search Terms

"return type" "generic" "type parameter" "indexed access" "index signature" "assignable" "constraint"

🕗 Version & Regression Information

  • This is the behavior in every version I tried, and I reviewed the FAQ for entries about index signatures

⏯ Playground Link

https://www.typescriptlang.org/play/?ts=5.7.2#code/C4TwDgpgBAogHgQwLZgDbQLxQN4CgpQIBcUA5AqflANoDWEIJAzsAE4CWAdgOYC6zbLt1wBfXLgAmEAMaoEraNID2nFlAiIU6EvGRoIuZauBR6IAIwCOPKFnKUNe9HQbnetspyUmKUAPR+UF7qrKxKrOJSsvKKKmpmAEwk9lAAPmQARg6a+i4gCe52Xj6k-oEQoeEANIRM6nCQ0sAQEkA

💻 Code

type Example = {
  a: 'a'
  [key: string]: string
}

declare const example: Example
const key1: string = 'a'
example[key1] = 'not a' // no error

declare const key2: 'a' | 'b'
example[key2] = 'not a' // error, as expected
//^^^^^^^^^^^
// Type '"not a"' is not assignable to type '"a"'.

🙁 Actual behavior

The index signature allows any string value to be assigned, ignoring the narrower type of a.

🙂 Expected behavior

Both property assignments in the above code should raise errors, for the same reason.

Additional information about the issue

This is a more generalized version of #60700. @MartinJohns helped me realize that type parameters need not be involved.

Here's another pair of examples (1, 2) which I expected to be reasoned through similarly:

type WiderType = { a?: string, b?: string }
type Example = { a: 'a' } & WiderType
declare const example: Example
declare const key: keyof Example
example[key] = 'not a'
//^^^^^^^^^^
// Type '"not a"' is not assignable to type '"a"'.
type WiderType = { [key: string]: string }
type Example = { a: 'a' } & WiderType
declare const example: Example
declare const key: keyof Example
example[key] = 'not a' // no error

In both cases Example carries with it the information that the property a must have a value assignable to 'a' (as can be seen with example.a = 'not a'). But this is not enforced when assigning to dynamic property using a key whose type matches the index signature.

Here's another example which does produce the error I expect:

type WiderType = { [key: string | symbol]: string }
type Example = { [key: string]: 'a' } & WiderType

declare const example: Example
declare const key: string | symbol
example[key] = 'not a' // error, as expected
//^^^^^^^^^^
// Type '"not a"' is not assignable to type '"a"'.
@mkantor
Copy link
Contributor Author

mkantor commented Dec 6, 2024

Phrased as a feature request:

When checking assignability of x to Type[K], if Type has an index signature over K, today it seems that only the index signature's property type is considered. I propose that additionally TypeScript should check whether x is assignable to each other property of Type whose keys are subtypes of K, similar to what happens when there is no index signature over K.

@MartinJohns
Copy link
Contributor

It's still the same design limitation.

@mkantor mkantor changed the title Writes indexed access of an index signature are not sufficiently constrained Writes to indexed access of an index signature are not sufficiently constrained Dec 6, 2024
@jcalz
Copy link
Contributor

jcalz commented Dec 7, 2024

TS is often unsound in the face of writes. Reminds me of #9825 (comment). A cure might well be worse than the disease.

@mkantor
Copy link
Contributor Author

mkantor commented Dec 7, 2024

A cure might well be worse than the disease.

It wouldn't surprise me, however it's not immediately obvious to me that fixing this particular soundness issue would cause more harm than any other type system change (this behavior doesn't seem like something people would intentionally rely on). But what do I know?

@RyanCavanaugh RyanCavanaugh added Suggestion An idea for TypeScript Experimentation Needed Someone needs to try this out to see what happens labels Dec 11, 2024
@RyanCavanaugh
Copy link
Member

I'm not opposed to looking at a PR for this and assessing the fallout.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Experimentation Needed Someone needs to try this out to see what happens Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests

4 participants