-
Notifications
You must be signed in to change notification settings - Fork 12.6k
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
Make optional properties assignable to string index signatures #41921
Make optional properties assignable to string index signatures #41921
Conversation
@typescript-bot user test this |
Heya @andrewbranch, I've started to run the parallelized Definitely Typed test suite on this PR at c88e7f8. You can monitor the build here. |
Heya @andrewbranch, I've started to run the parallelized community code test suite on this PR at c88e7f8. You can monitor the build here. |
The user suite test run you requested has finished and failed. I've opened a PR with the baseline diff from master. |
User tests look good |
declare let optionalUndefined: { k1?: undefined }; | ||
let dict: { [key: string]: string } = optionalUndefined; // error | ||
~~~~ | ||
!!! error TS2322: Type '{ k1?: undefined; }' is not assignable to type '{ [key: string]: string; }'. | ||
!!! error TS2322: Property 'k1' is incompatible with index signature. | ||
!!! error TS2322: Type 'undefined' is not assignable to type 'string'. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the only mildly interesting thing about this PR. We check if the property type is undefined
before filtering undefined
out of it in order to keep this error. (Otherwise we would end up checking if never
is assignable to string
.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I actually think the ?: string | undefined
-> [x: string]: string
one is actually weirder.
If the user and RWC tests look good, then awesome! |
@typescript-bot test this |
Heya @andrewbranch, I've started to run the extended test suite on this PR at c88e7f8. You can monitor the build here. |
@typescript-bot test this |
Heya @andrewbranch, I've started to run the extended test suite on this PR at c88e7f8. You can monitor the build here. |
Hi! I'm wondering - since this change allows unsound code more often than in the previous versions of TypeScript (playground) I'm wondering if there are maybe some other planned changes (new strict-like flags?) for the optionality of properties? I'm constantly tripped by the fact that an optional property allows |
@Andarist it looks like you want I don’t think I understand your |
First of all - thanks for answering!
Not quite, this was the demonstration of how this can lead to less sound code and - yes, this flag would help for this particular situation but the problem for me starts a step earlier. The problem is that
What I've meant that there is always a difference in my head between an existing property with undefined value and missing property, even though reading that yields type A = { a?: string }
type A = { a: string | undefined } This was most likely not true even before this PR but I've been always struggling to find a practical difference between those two in TS when testing short snippets of code. Might be worth describing this in the docs or something - I've seen people confused by this on multiple occasions. |
Note that |
Thank you for the thorough answer :) |
I just tested this with TypeScript 4.2 and I was hoping it would also fix this error, but it doesn't seem like it does: type Dict<T> = { [key: string]: T }
interface F extends Dict<string> {
// Property 'foo' of type 'string | undefined' is not assignable to string index type 'string'.
foo?: string;
} Does it make sense to extend this change so that it addresses this error as well? Also, if I understand correctly, this change is essentially a workaround for a larger issue, which is the fact that TypeScript does not distinguish between missing and |
Well, I think at best, it makes almost as much sense as any of the rest of this stuff, which is to say, I would be very unenthusiastic about widening this hole without a very good reason to do so. I think it probably makes more sense under |
Prerequisite of #41418, discussed in #41505 and #41907.
Attempted release-notes-quality description:
Optional properties are assignable to string index signatures
String index signatures are a way of typing dictionary-like objects, where you want to allow access with arbitrary keys:
Of course, for any movie title not yet in the dictionary,
movieWatchCount[title]
will beundefined
. (TypeScript 4.1 added the option--noUncheckedIndexedAccess
to includeundefined
when reading from an index signature like this.) Even though it’s clear that there must be some strings not present inmovieWatchCount
, previous versions of TypeScript treated optional object properties as unassignable to otherwise compatible index signatures, due to the presence ofundefined
:TypeScript 4.2 allows this assignment. However, it does not allow the assignment of non-optional properties with
undefined
in their types, nor does it allow writingundefined
to a specific key:The new rule also does not apply to number index signatures, since they are assumed to be array-like and dense: