-
Notifications
You must be signed in to change notification settings - Fork 12.9k
Rewrite getPropFromRaw slightly to surface T in the parameters #53301
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -29,7 +29,6 @@ import { | |
emptyArray, | ||
endsWith, | ||
ensureTrailingDirectorySeparator, | ||
every, | ||
Expression, | ||
extend, | ||
Extension, | ||
|
@@ -2974,7 +2973,7 @@ function parseJsonConfigFileContentWorker( | |
}; | ||
|
||
function getConfigFileSpecs(): ConfigFileSpecs { | ||
const referencesOfRaw = getPropFromRaw<ProjectReference>("references", element => typeof element === "object", "object"); | ||
const referencesOfRaw = getPropFromRaw("references", (element): element is ProjectReference => !!element && typeof element === "object", "object"); | ||
const filesSpecs = toPropValue(getSpecsFromRaw("files")); | ||
if (filesSpecs) { | ||
const hasZeroOrNoReferences = referencesOfRaw === "no-prop" || isArray(referencesOfRaw) && referencesOfRaw.length === 0; | ||
|
@@ -3049,7 +3048,7 @@ function parseJsonConfigFileContentWorker( | |
|
||
function getProjectReferences(basePath: string): readonly ProjectReference[] | undefined { | ||
let projectReferences: ProjectReference[] | undefined; | ||
const referencesOfRaw = getPropFromRaw<ProjectReference>("references", element => typeof element === "object", "object"); | ||
const referencesOfRaw = getPropFromRaw("references", (element): element is ProjectReference => !!element && typeof element === "object", "object"); | ||
if (isArray(referencesOfRaw)) { | ||
for (const ref of referencesOfRaw) { | ||
if (typeof ref.path !== "string") { | ||
|
@@ -3077,11 +3076,12 @@ function parseJsonConfigFileContentWorker( | |
return getPropFromRaw(prop, isString, "string"); | ||
} | ||
|
||
function getPropFromRaw<T>(prop: "files" | "include" | "exclude" | "references", validateElement: (value: unknown) => boolean, elementTypeName: string): PropOfRaw<T> { | ||
function getPropFromRaw<T>(prop: "files" | "include" | "exclude" | "references", validateElement: (value: unknown) => value is T, elementTypeName: string): PropOfRaw<T> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This doesn't make the code any safer than it currently is but I feel like it surfaces the "unsafe" part (the predicate function) to the reader and that code ends up being less surprising (previously it relied on the explicit type parameter and the contextual type provided through the return annotation: TS playground) |
||
if (hasProperty(raw, prop) && !isNullOrUndefined(raw[prop])) { | ||
if (isArray(raw[prop])) { | ||
const result = raw[prop] as T[]; | ||
if (!sourceFile && !every(result, validateElement)) { | ||
const value = raw[prop]; | ||
if (isArray(value)) { | ||
const result = filter(value, validateElement); | ||
if (!sourceFile && result.length !== value.length) { | ||
errors.push(createCompilerDiagnostic(Diagnostics.Compiler_option_0_requires_a_value_of_type_1, prop, elementTypeName)); | ||
} | ||
return result; | ||
|
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.
The problem is that below, we still return the result if not every array element matches the type guard. So, I don't really know if this is a good idea as it seems to imply safety that isn't real either.
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.
That is true and I pondered about it - this could be potentially rewritten further (although I'm not up to it as I don't really care about this ;p). I just feel that this proposed structure is less surprising to the reader - not necessarily when it comes to its behavior but to the code structure itself. And since the type predicate has to be written at the call site (or referenced), it at least gives a vague notion of this function being on the edge of safety.
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.
Thinking about it some more, I think we could safely change this function to be the following:
So, we'll always get back a list of
T
; I think this is okay because it's extremely likely that the "bad" things would cause some sort of crash.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.
Applied the suggested change and added
!!element &&
to predicates testing forProjectReference
(they were just checkingtypeof element === 'object'
). The consuming code validates furthertypeof ref.path === 'string'
(although probably a little bit late since at this point in time the type already should/could be "trusted", not a big deal for this though) butoriginalPath
,prepend
,circular
are passed through as-is to the caller so I wouldn't be surprised if that could cause some issues. Perhaps those should get normalized to default values if they have invalid values (extra validation messages would also be nice)?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 don't know if that's strictly required; the function below calls
!isNullOrUndefined(raw[prop])
, right?Yeah, though that'd require some tests I think.
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.
If you refer to the check within
getPropFromRaw
then this only happens forraw[prop]
butvalidateElement
operates ontypeof raw[prop][number]
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.
It turns out that the added
filter
here was at fault for the broken tests on main. Everything passes with this patch:Do you want me to create a new PR with this change? I honestly don't care about it that much... but since I already have written this code it doesn't cost me much. The original motivation behind this PR was mostly "stylistic" since the old structure was a little bit confusing - it doesn't allow for a simple refactor like:
All in all, it doesn't really matter in the grand scheme of things - so it's up to you, just let me know what I should do.
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.
The filter was the only reason this code became typesafe, so, I'm not sure about removing it if we can figure out why that broke the tests; was it even a break, or just a differing error?