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
Fix deep properties of PackageJson
and TsConfigJson
#269
Conversation
Also, maybe it's time to drop |
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 somewhat related to #79 and the fact that both PackageJson
and TsConfigJson
types should both really be valid JsonValue
types, as else they are kind of lying about being Json
types.
And as can be seen in the JsonValue
definition, undefined
is not a valid value there:
Lines 15 to 45 in 6b6d81c
/** | |
Matches a JSON object. | |
This type can be useful to enforce some input to be JSON-compatible or as a super-type to be extended from. Don't use this as a direct return type as the user would have to double-cast it: `jsonObject as unknown as CustomResponse`. Instead, you could extend your CustomResponse type from it to ensure your type only uses JSON-compatible types: `interface CustomResponse extends JsonObject { … }`. | |
@category Basic | |
*/ | |
export type JsonObject = {[Key in string]?: JsonValue}; | |
/** | |
Matches a JSON array. | |
@category Basic | |
*/ | |
export type JsonArray = JsonValue[]; | |
/** | |
Matches any valid JSON primitive value. | |
@category Basic | |
*/ | |
export type JsonPrimitive = string | number | boolean | null; | |
/** | |
Matches any valid JSON value. | |
@see `Jsonify` if you need to transform a type to one that is assignable to `JsonValue`. | |
@category Basic | |
*/ | |
export type JsonValue = JsonPrimitive | JsonObject | JsonArray; |
I guess it can be exemplified by this:
const value = {
xyz: undefined
};
if (value.xyz === undefined) {
console.log('value.xyz is undefined!');
}
if (Object.prototype.hasOwnProperty.call(value, 'xyz') === false) {
console.log('value.xyz property does not exist');
}
if (value.abc === undefined) {
console.log('value.abc is undefined!');
}
if (Object.prototype.hasOwnProperty.call(value, 'abc') === false) {
console.log('value.abc property does not exist');
}
Which prints:
value.xyz is undefined!
value.abc is undefined!
value.abc property does not exist
And thus show cases that there's a difference between a property being evaluated as undefined
and the object actually having that property.
And the output of JSON.parse
can never be like value.xyz
in that a property exists, but its value is undefined
.
I'm not sure what @sindresorhus thinks here? I'm leaning more towards moving in the direction of #79
I agree, but on the other hand this is the limitation for Just because by TypeScript design there is no difference between property that exist with const obj: {a?: string} = {a: undefined} And it makes sense, since So, I'm using this trick to remove values that come from other sources e.g. I use Of course, I can use
is that bad? I didn't explicitly add |
Sorry, const a: JsonObject = {
bugs: undefined
} or const a: PackageJson = {
bugs: {
email: undefined
}
} |
This was true up until TypeScript 4.4 was recently released. TypeScript 4.4 introduced Due to #65 it doesn't apply correctly to You can see it in more proper action on TS Playground here. Edit: Fixed the playground link |
I think that as long as I guess there might also be a case where we need to ensure that its tested in the |
@voxpelli Are we good to merge this? |
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.
@sindresorhus Sorry, I've dropped things completely here I see:
My trail of thought was:
PackageJson
should be possible to use wherever aJsonObject
is requested. That's currently not possible according toPackageJson
is not a validJsonObject
#79- As Make
JsonObject
work as expected with TS 4.4--exactOptionalPropertyTypes
#272 points out,{ bugs: undefined }
is not a possible value of aJsonObject
(though it is a valid object when usingJSON.stringify()
, but will be treated the same as if it was left out completely) - Considering Make
JsonObject
work as expected with TS 4.4--exactOptionalPropertyTypes
#272, this PR would bring us further fromPackageJson
is not a validJsonObject
#79 than we are today.
Though I now elaborated in #272 (comment) that its like more complex than that, so lets merge this and deal with the #79 and #272 problems in those respective issues.
(As I mentioned in #272, it kind of depends on whether one see the JsonObject
/ PackageJson
value to represent something that is valid to go into a JSON.stringify()
or whether its more strictly something that one could expect back from JSON.parse()
, but lets leave that to those issues)
29f3df0
to
08de69b
Compare
@@ -713,7 +713,7 @@ declare namespace TsConfigJson { | |||
/** | |||
Specify path mapping to be computed relative to baseUrl option. | |||
*/ | |||
paths?: Record<string, string[]>; | |||
paths?: Partial<Record<string, 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.
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.
Revert PR: #404
All top-level properties are marked as optional. This makes sense and with TS defaults it is possible to assign
undefined
:But not when it comes to
Record<string, string>
I've just replaced
Record
types withPartial<Record>
, because there is no short way of doing thatMaybe we should introduce
OptionalRecord
type or rewrite everything as{[k: string]?: type}
?The worst thing happens in
scripts
property. Despite of having?
in properties, we can't specifyundefined
e.g.Even VSCode displays that it's possible to assign undefined here, weird.
Also, I can't see strict errors in ide for test files.
Why
test-d
was excluded fromtsconfig
?P.S. I understand that as a workaround I could use
PartialDeep<PackageJson>
, but it wouldn't fix individual types such asDependency
.