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

📝 Docs: Note that & why Twoslash and $ExpectType have different behavior #74

Open
OliverJAsh opened this issue Mar 17, 2023 · 3 comments
Labels
area: documentation Improvements or additions to docs 📝 status: accepting prs Please, send a pull request to resolve this! 🙏

Comments

@OliverJAsh
Copy link

OliverJAsh commented Mar 17, 2023

🐛 Bug Report

  • eslint-plugin-expect-type version: 0.2.2
  • ESLint version: 8.36.0
  • Node version: 16.3.0

Actual Behavior

Full reduced test case here: https://github.com/OliverJAsh/eslint-plugin-expect-type-issue

Contents inlined below.

package.json:

{
  "dependencies": {
    "@typescript-eslint/parser": "^5.55.0",
    "eslint": "^8.36.0",
    "eslint-plugin-expect-type": "^0.2.2",
    "typescript": "^5.0.2"
  }
}

tsconfig.json:

{
  "compilerOptions": {
    "strict": true
  }
}

.eslintrc.js:

const path = require("path");

module.exports = {
  parser: "@typescript-eslint/parser",
  parserOptions: {
    project: path.join(__dirname, "./tsconfig.json"),
  },
  plugins: ["eslint-plugin-expect-type"],
  rules: {
    "expect-type/expect": "error",
  },
};

source.ts:

export type Compact<A> = A extends Function ? A : { [K in keyof A]: A[K] } & {};

test.ts:

import { Compact } from "./source";

declare const any: any;

const x: Compact<Record<"a" | "b", number> | Record<"a" | "c", number>> = any;

// ❌ Error:
//  Expected type to be: { a: number; b: number; } | { a: number; c: number; }, got: Compact<Record<"a" | "b", number> | Record<"a" | "c", number>>
// $ExpectType { a: number; b: number; } | { a: number; c: number; }
type Test1 = typeof x;

// ✅ No error
type Test2 = typeof x;
//   ^? type Test2 = {
//          a: number;
//          b: number;
//      } | {
//          a: number;
//          c: number;
//      }
  • $ExpectType expects: Compact<Record<"a" | "b", number> | Record<"a" | "c", number>>
  • Twoslash expects:
       type Test2 = {
        a: number;
        b: number;
    } | {
        a: number;
        c: number;
    }

I believe the reason for this difference is because Twoslash and $ExpectType use different mechanisms to generate the "actual" value:

This particular issue started after we upgraded to TypeScript 5. Prior to this, $ExpectType had the same behavior as Twoslash in this particular example. I'm not sure why this has changed.

Expected Behavior

Twoslash queries and $ExpectType should behave the same.

Reproduction

https://github.com/OliverJAsh/eslint-plugin-expect-type-issue

@danvk
Copy link
Collaborator

danvk commented Mar 17, 2023

Thanks for the report @OliverJAsh. Do you think its expected (by the TS team) that the behaviors of getQuickInfoAtPosition and typeToString have diverged? Should we file an upstream issue about it?

Assuming this is intentional… while it is curious, I'm not sure this is undesirable behavior? I would expect $ExpectType to behave the same way as dtslint. And I'd expect twoslash-style assertions to behave the same way they do in the TypeScript playground. Which I believe is the case right now, even though those two have diverged.

@OliverJAsh
Copy link
Author

Do you think its expected (by the TS team) that the behaviors of getQuickInfoAtPosition and typeToString have diverged?

Good question. I honestly have no idea. Up until now, my mental model for $ExpectType has always been it will use the same printed string as what you see when you hover over a type or use Twoslash, but maybe I was wrong to think that.

@JoshuaKGoldberg JoshuaKGoldberg added the status: needs investigation Further research required...? 🔎 label May 4, 2023
@JoshuaKGoldberg
Copy link
Owner

Coming back >1.5 years later: I think this is more of a documentation issue at this point. We have the two approaches with different root ideals:

  • $ExpectType: Goes directly to the TypeScript's stringification
  • ^?: Instead mirrors the visual display

@JoshuaKGoldberg JoshuaKGoldberg added type: docs area: documentation Improvements or additions to docs 📝 status: accepting prs Please, send a pull request to resolve this! 🙏 and removed status: needs investigation Further research required...? 🔎 type: docs labels Nov 29, 2024
@JoshuaKGoldberg JoshuaKGoldberg changed the title Twoslash and $ExpectType have different behavior 📝 Docs: Note that & why Twoslash and $ExpectType have different behavior Nov 29, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: documentation Improvements or additions to docs 📝 status: accepting prs Please, send a pull request to resolve this! 🙏
Projects
None yet
Development

No branches or pull requests

3 participants