Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

fix(eslint-plugin): [no-unsafe-type-assertion] fix for unsafe assertion to a constrained type parameter#10461

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Conversation

controversial
Copy link
Contributor

@controversialcontroversial commentedDec 5, 2024
edited
Loading

PR Checklist

Overview

Attempts to fix the issue described in#10453:

typeObj={foo:string};functionfunc<TextendsObj>(){consto:Obj={foo:'hi'};// this type assertion is unsafe because T could be instantiated with a more specific subtype of Obj// no-unsafe-type-assertion should (but didn’t) report thisconstmyObj=oasT;}

After experimenting with the logic inno-unsafe-type-assertion, I found that obtaining the “types to check” usingservices.getTypeAtLocation in place ofgetConstrainedTypeAtLocation (i.e. omitting a call togetBaseConstraintOfType) allows the subsequentisTypeAssignableTo check to correctly catch this case.

Additionally, I added a new error message for this case: if the “expression type” isnot assignable to the “asserted type”, but the asserted type has a constraint to which the expression type is assignable, the rule will report the following:

Unsafe type assertion: the original type is assignable to the constraint of type '{{type}}', but '{{type}}' could be instantiated with a different subtype of its constraint.


This is my first contribution to this project and I’m broadly unfamiliar with both ESLint plugin development and TypeScript internals, so it’s very possible that I’m missing a hidden implication of this change—i.e. I’m not sure if there was an important reason to usegetConstrainedTypeAtLocation in the original implementation. However, the existing tests for this rule are still passing.

kirkwaiblinger reacted with heart emoji
@typescript-eslint
Copy link
Contributor

Thanks for the PR,@controversial!

typescript-eslint is a 100% community driven project, and we are incredibly grateful that you are contributing to that community.

The core maintainers work on this in their personal time, so please understand that it may not be possible for them to review your work immediately.

Thanks again!


🙏Please, if you or your company is finding typescript-eslint valuable, help us sustain the project by sponsoring it transparently onhttps://opencollective.com/typescript-eslint.

@netlifyNetlify
Copy link

netlifybot commentedDec 5, 2024
edited
Loading

Deploy Preview fortypescript-eslint ready!

NameLink
🔨 Latest commit239f3df
🔍 Latest deploy loghttps://app.netlify.com/sites/typescript-eslint/deploys/6761bd5ffc147e0008e6d79d
😎 Deploy Previewhttps://deploy-preview-10461--typescript-eslint.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
Lighthouse
Lighthouse
1 paths audited
Performance: 92 (🟢 up 14 from production)
Accessibility: 100 (no change from production)
Best Practices: 92 (no change from production)
SEO: 98 (no change from production)
PWA: 80 (no change from production)
View the detailed breakdown and full score reports

To edit notification comments on pull requests, go to yourNetlify site configuration.

@nx-cloudNx Cloud
Copy link

nx-cloudbot commentedDec 5, 2024
edited
Loading

☁️ Nx Cloud Report

CI is running/has finished running commands for commit239f3df. As they complete they will appear below. Click to see the status, the terminal output, and the build insights.

📂 See all runs for this CI Pipeline Execution


✅ Successfully ran 32 targets

Sent with 💌 fromNxCloud.

@controversialcontroversial changed the titlefix(eslint-plugin): [no-unsafe-type-assertion] Fix for type parameters with generic constraintsfix(eslint-plugin): [no-unsafe-type-assertion] fix for type parameters with generic constraintsDec 5, 2024
@codecovCodecov
Copy link

codecovbot commentedDec 5, 2024
edited
Loading

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 86.79%. Comparing base(b2ce158) to head(239f3df).
Report is 10 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@##             main   #10461   +/-   ##=======================================  Coverage   86.78%   86.79%           =======================================  Files         445      445             Lines       15366    15376   +10       Branches     4475     4478    +3     =======================================+ Hits        13336    13346   +10  Misses       1675     1675             Partials      355      355
FlagCoverage Δ
unittest86.79% <100.00%> (+<0.01%)⬆️

Flags with carried forward coverage won't be shown.Click here to find out more.

Files with missing linesCoverage Δ
...slint-plugin/src/rules/no-unsafe-type-assertion.ts100.00% <100.00%> (ø)

... and1 file with indirect coverage changes

@controversial
Copy link
ContributorAuthor

controversial commentedDec 5, 2024
edited
Loading

With respect to a custom error message,@kirkwaiblingersuggested:

As a first pass, I think we could just model it after the TS error message?

Unsafe type assertion: 'Object' is assignable to the constraint of type 'CustomObjectT', but 'CustomObjectT' could be instantiated with a different subtype of constraint 'Object'.

In the original PR of this rule,#10051, a discussion about the appropriate verbosity of the error messageresolved to omit any types other than theexplicitly written type from the error message in order to prevent excessively verbose errors.

With that in mind, I’m starting out with the following error message:

Unsafe type assertion:the original type is assignable to the constraint of type 'CustomObjectT', but 'CustomObjectT' could be instantiated with a different subtype ofits constraint.

I’m happy to amend this message to be more verbose if we decide to go that way, though!

kirkwaiblinger reacted with thumbs up emoji

@controversialcontroversial changed the titlefix(eslint-plugin): [no-unsafe-type-assertion] fix for type parameters with generic constraintsfix(eslint-plugin): [no-unsafe-type-assertion] fix for unsafe assertion to a constrained type parameterDec 5, 2024
Copy link
Member

@kirkwaiblingerkirkwaiblinger left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

What a great first PR to typescript-eslint! This is very much on the right track, and in a tricky area of the codebase, too.

Left a few comments and questions.

checker.getBaseConstraintOfType(assertedType);
const isAssignableToConstraint =
!!assertedTypeConstraint &&
checker.isTypeAssignableTo(

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

(no specific changes requested in the following)

While I was thinking deeply, it occurred to make that I don't think that asserting from any concrete type to any type parameter is ever safe, so I was wondering whether we could gain some performance by checking for this early and avoiding anychecker.isTypeAssignableTo() checks..

This would sacrifice the ability to have distinct error messages for whether it's not assignable because of ordinary unassignability (string | number as T where T extends string) or due to the generic subtype instantiation (string as T where T extends string | number), it could potentially be mitigated by a separate error message just saying A concrete type can never be safely assigned to a type parameter (or similar).

However, I think we still need the current infrastructure in order to deal with the case of assignment from one type parameter to another type parameter (since T -> V where V extends T is ok), so I'm leaning against going that route, i.e. leaning towards your current strategy. If you want to give this a thought, though, I'm curious for your opinion as well!

@kirkwaiblingerkirkwaiblinger added the awaiting responseIssues waiting for a reply from the OP or another party labelDec 6, 2024
@controversial
Copy link
ContributorAuthor

controversial commentedDec 6, 2024
edited
Loading

Thanks so much for the thoughtful review@kirkwaiblinger !!

I added the test cases from your playground and addressed the missing cases. For the missing case ofunconstrained type parameters, I added another message to match the one Typescript uses:

Unsafe type assertion: '{{type}}' could be instantiated with an arbitrary type which could be unrelated to the original type.

Here’s an updatedplayground link!

The only test case that tripped me up a bit was the one you had calledparameterExtendsOtherParameter:
functionparameterExtendsOtherParameter<T,VextendsT>(x:T,y:V){x=y;yasT;// allowedy=x;xasV;// banned; generic arbitrary subtype <-- currently has wrong error message.}

My first impression was that this case should raise the “x is assignable to the constraint of V” message. However, my current implementation instead says “V could be instantiated with an arbitrary type.”Notably, though (and somewhat to my surprise) this behavior is consistent with the message that Typescript gives for this case, so I think it’s probably ok as-is?

Iadded a newparameterExtendsOtherParameter test where T isnot unconstrained; here, both TypeScript (for assignment) and my implementation raise “is assignable to the constraint of V” like I expected. I renamed the original test toparameterExtendsUnconstrainedParameter.

I’m curious to hear your thoughts about whether we should try to produce “assignable to the constraint” for this edge case?

kirkwaiblinger reacted with heart emoji

@github-actionsgithub-actionsbot removed the awaiting responseIssues waiting for a reply from the OP or another party labelDec 6, 2024
@controversial
Copy link
ContributorAuthor

Merged the latestmain to resolve merge conflicts from#10472

When you get a chance, let me know if there’s anything else you need from me@kirkwaiblinger :)

kirkwaiblinger reacted with thumbs up emoji

@kirkwaiblinger
Copy link
Member

My first impression was that this case should raise the “x is assignable to the constraint of V” message. However, my current implementation instead says “V could be instantiated with an arbitrary type.”Notably, though (and somewhat to my surprise) this behavior is consistent with the message that Typescript gives for this case, so I think it’s probably ok as-is?

I feel strongly that TS is wrong here, sinceV plainly cannot beunrelated toT. It's guaranteed to be a subtype ofT, since...V extends T 🤷 . However, I agree that it makes sense to match their behavior here, and we can follow up by filing an issue to TS if we like. (Feel free to do this if you're interested! Otherwise I probably will at some point 🙂)

Iadded a newparameterExtendsOtherParameter test where T isnot unconstrained; here, both TypeScript (for assignment) and my implementation raise “is assignable to the constraint of V” like I expected. I renamed the original test toparameterExtends**Unconstrained**Parameter.

🎉

controversial reacted with heart emoji

Copy link
Member

@kirkwaiblingerkirkwaiblinger left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Really outstanding work! Great attention to detail on noticing the additional error message, nicely done on pushing back where it made sense to do so!

Trivial cleanup requested but this is otherwise an enthusiastic approval from me! 🙂 We'll probably leave this open for a little bit as well for another team member to take a look if they like, since it's nuanced stuff.

Thanks!

cuzco

@kirkwaiblingerkirkwaiblinger requested a review froma teamDecember 17, 2024 03:01
@kirkwaiblingerkirkwaiblinger added the 1 approval>=1 team member has approved this PR; we're now leaving it open for more reviews before we merge labelDec 17, 2024
unit tests should only test one thing
@controversial
Copy link
ContributorAuthor

cleanup completed! thanks again for your thoughtful reviews, excited to have this merged at some point :)

kirkwaiblinger and JoshuaKGoldberg reacted with heart emoji

@kirkwaiblingerkirkwaiblinger requested a review froma teamDecember 17, 2024 18:06
@github-actionsgithub-actionsbot removed the 1 approval>=1 team member has approved this PR; we're now leaving it open for more reviews before we merge labelDec 17, 2024
@JoshuaKGoldbergJoshuaKGoldberg merged commit4c91ed5 intotypescript-eslint:mainDec 21, 2024
62 of 63 checks passed
renovatebot added a commit to andrei-picus-tink/auto-renovate that referenced this pull requestDec 23, 2024
| datasource | package                          | from   | to     || ---------- | -------------------------------- | ------ | ------ || npm        | @typescript-eslint/eslint-plugin | 8.18.1 | 8.18.2 || npm        | @typescript-eslint/parser        | 8.18.1 | 8.18.2 |## [v8.18.2](https://github.com/typescript-eslint/typescript-eslint/blob/HEAD/packages/eslint-plugin/CHANGELOG.md#8182-2024-12-23)##### 🩹 Fixes-   **eslint-plugin:** \[no-unnecessary-condition] handle noUncheckedIndexedAccess true ([#10514](typescript-eslint/typescript-eslint#10514))-   **eslint-plugin:** \[consistent-type-assertions] allow default assertionStyle option ([#10512](typescript-eslint/typescript-eslint#10512))-   **eslint-plugin:** \[no-unnecessary-type-arguments] handle type/value context ([#10503](typescript-eslint/typescript-eslint#10503))-   **eslint-plugin:** \[no-unsafe-type-assertion] fix for unsafe assertion to a constrained type parameter ([#10461](typescript-eslint/typescript-eslint#10461))-   **eslint-plugin:** \[consistent-indexed-object-style] use a suggestion over an auto-fix if can't reliably determine that produced index signature is valid ([#10490](typescript-eslint/typescript-eslint#10490))-   **eslint-plugin:** \[no-unnecessary-condition] don't flag values of an unconstrained or valid type parameter ([#10473](typescript-eslint/typescript-eslint#10473))-   **eslint-plugin:** \[prefer-reduce-type-parameter] don't report cases in which the fix results in a type error ([#10494](typescript-eslint/typescript-eslint#10494))-   **eslint-plugin:** \[no-deprecated] not reporting usages of deprecated declared constants as object value ([#10498](typescript-eslint/typescript-eslint#10498))##### ❤️ Thank You-   Luke Deen Taylor [@controversial](https://github.com/controversial)-   Ronen Amiel-   Scott O'Hara-   YeonJuan [@yeonjuan](https://github.com/yeonjuan)-   Yukihiro Hasegawa [@y-hsgw](https://github.com/y-hsgw)You can read about our [versioning strategy](https://main--typescript-eslint.netlify.app/users/versioning) and [releases](https://main--typescript-eslint.netlify.app/users/releases) on our website.
renovatebot added a commit to mmkal/eslint-plugin-mmkal that referenced this pull requestDec 23, 2024
##### [v8.18.2](https://github.com/typescript-eslint/typescript-eslint/blob/HEAD/packages/eslint-plugin/CHANGELOG.md#8182-2024-12-23)##### 🩹 Fixes-   **eslint-plugin:** \[no-unnecessary-condition] handle noUncheckedIndexedAccess true ([#10514](typescript-eslint/typescript-eslint#10514))-   **eslint-plugin:** \[consistent-type-assertions] allow default assertionStyle option ([#10512](typescript-eslint/typescript-eslint#10512))-   **eslint-plugin:** \[no-unnecessary-type-arguments] handle type/value context ([#10503](typescript-eslint/typescript-eslint#10503))-   **eslint-plugin:** \[no-unsafe-type-assertion] fix for unsafe assertion to a constrained type parameter ([#10461](typescript-eslint/typescript-eslint#10461))-   **eslint-plugin:** \[consistent-indexed-object-style] use a suggestion over an auto-fix if can't reliably determine that produced index signature is valid ([#10490](typescript-eslint/typescript-eslint#10490))-   **eslint-plugin:** \[no-unnecessary-condition] don't flag values of an unconstrained or valid type parameter ([#10473](typescript-eslint/typescript-eslint#10473))-   **eslint-plugin:** \[prefer-reduce-type-parameter] don't report cases in which the fix results in a type error ([#10494](typescript-eslint/typescript-eslint#10494))-   **eslint-plugin:** \[no-deprecated] not reporting usages of deprecated declared constants as object value ([#10498](typescript-eslint/typescript-eslint#10498))##### ❤️ Thank You-   Luke Deen Taylor [@controversial](https://github.com/controversial)-   Ronen Amiel-   Scott O'Hara-   YeonJuan [@yeonjuan](https://github.com/yeonjuan)-   Yukihiro Hasegawa [@y-hsgw](https://github.com/y-hsgw)You can read about our [versioning strategy](https://main--typescript-eslint.netlify.app/users/versioning) and [releases](https://main--typescript-eslint.netlify.app/users/releases) on our website.
@github-actionsgithub-actionsbot locked asresolvedand limited conversation to collaboratorsDec 30, 2024
Sign up for freeto subscribe to this conversation on GitHub. Already have an account?Sign in.
Reviewers

@kirkwaiblingerkirkwaiblingerkirkwaiblinger approved these changes

Assignees
No one assigned
Labels
None yet
Projects
None yet
Milestone
No milestone
Development

Successfully merging this pull request may close these issues.

Bug: [no-unsafe-type-assertion] Fails to report unsafe assertions involving constrained type parameters
3 participants
@controversial@kirkwaiblinger@JoshuaKGoldberg

[8]ページ先頭

©2009-2025 Movatter.jp