Repository: prettier/prettier (JavaScript)
Date: 2020-10-31 15:33:57+00:00
Task type: Bug Fix

Issue:
prettier-ignore breaks mapped types
**Prettier 2.1.2**
[Playground link](https://prettier.io/playground/#N4Igxg9gdgLgprEAuEMCeAHOACAhgXm2AB0ptzsB6S7DAJzhhgEs46BaZgcyggdIrYA2gEFszMgCEAukmwBhcgB9yAEQHYAviAA0ICBhbQAzslC46dCAHcAChYSmUuADbXcaU3oBGdXGABrRgBlDH8JLmQYOgBXOD04AFtvOAATVLSAGVwoLhjcLjgAMT5E3CYI5BBcGJgIXRAACxhElwB1RuZ4YzCwOGDHLuYANy60KrBjLxAJYzYYWz8uMuQAM1c5vQArYwAPST9AkNxEuEyJODWN+JAd3eCIlzgARRiIeCuXTZAwujm6KroLDGMB0ZiGBr0CQwNrMVIwRrIAAcAAY9PQIHM2n4MFV6HB-sNLnoAI5veCLAxOarGdhQOBpNINBhk5gMRYFFZIdZfG5zRLMKKxPmPF7ky7c656GC4byw+GIpAAJmlfmYLgi8ggiS5IAJAFYGjE5gAVWVOHnfYZxACSUAysGCoPBMBE9uC6Cenzmmk0QA)
```sh
--parser typescript
```

**Input:**
```tsx
type a= {
    // prettier-ignore
    [A in B]: C  |  D
  }
```

**Output:**
```tsx
type a = {
  // prettier-ignore
  A in B: C | D;
};

```

**Second Output:**
```tsx
SyntaxError: Property or signature expected. (3:3)
  1 | type a = {
  2 |   // prettier-ignore
> 3 |   A in B: C | D;
    |   ^
  4 | };
  5 | 
```


Issue discussion:

Solution patch:
diff --git a/changelog_unreleased/typescript/pr-9551.md b/changelog_unreleased/typescript/pr-9551.md
new file mode 100644
index 000000000000..77ffc2676f6f
--- /dev/null
+++ b/changelog_unreleased/typescript/pr-9551.md
@@ -0,0 +1,22 @@
+#### Fix `prettier-ignore`d mapped types (#9551 by @fisker)
+
+<!-- prettier-ignore -->
+```ts
+// Input
+type a= {
+    // prettier-ignore
+    [A in B]: C  |  D
+  }
+
+// Prettier master
+type a = {
+  // prettier-ignore
+  A in B: C | D;
+};
+
+// Prettier stable
+type a = {
+    // prettier-ignore
+    [A in B]: C  |  D
+  };
+```
diff --git a/src/language-js/comments.js b/src/language-js/comments.js
index c33bff504871..f24362caf20c 100644
--- a/src/language-js/comments.js
+++ b/src/language-js/comments.js
@@ -18,6 +18,13 @@ const { locStart, locEnd } = require("./loc");
 function handleOwnLineComment(comment, text, options, ast, isLastComment) {
   const { precedingNode, enclosingNode, followingNode } = comment;
   return (
+    handleIgnoreComments(
+      text,
+      enclosingNode,
+      precedingNode,
+      followingNode,
+      comment
+    ) ||
     handleLastFunctionArgComments(
       text,
       precedingNode,
@@ -121,6 +128,13 @@ function handleRemainingComment(comment, text, options, ast, isLastComment) {
   const { precedingNode, enclosingNode, followingNode } = comment;
 
   if (
+    handleIgnoreComments(
+      text,
+      enclosingNode,
+      precedingNode,
+      followingNode,
+      comment
+    ) ||
     handleIfStatementComments(
       text,
       precedingNode,
@@ -848,6 +862,27 @@ function handleTSFunctionTrailingComments(
   return false;
 }
 
+function handleIgnoreComments(
+  text,
+  enclosingNode,
+  precedingNode,
+  followingNode,
+  comment
+) {
+  if (
+    isNodeIgnoreComment(comment) &&
+    enclosingNode &&
+    enclosingNode.type === "TSMappedType" &&
+    followingNode &&
+    followingNode.type === "TSTypeParameter" &&
+    followingNode.constraint
+  ) {
+    enclosingNode.prettierIgnore = true;
+    comment.unignore = true;
+    return true;
+  }
+}
+
 function handleTSMappedTypeComments(
   text,
   enclosingNode,


Test patch:
diff --git a/tests/typescript/prettier-ignore/__snapshots__/jsfmt.spec.js.snap b/tests/typescript/prettier-ignore/__snapshots__/jsfmt.spec.js.snap
new file mode 100644
index 000000000000..60bdf3b3f3d5
--- /dev/null
+++ b/tests/typescript/prettier-ignore/__snapshots__/jsfmt.spec.js.snap
@@ -0,0 +1,140 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`mapped-types.ts format 1`] = `
+====================================options=====================================
+parsers: ["typescript"]
+printWidth: 80
+                                                                                | printWidth
+=====================================input======================================
+type a= {
+    // prettier-ignore
+    [A in B]: C  |  D
+  }
+
+type a= {
+    [
+      // prettier-ignore
+      A in B
+    ]: C  |  D
+  }
+
+type a= {
+    [
+      A in
+      // prettier-ignore
+      B
+    ]: C  |  D
+  }
+
+type a= {
+    [A in B]:
+      // prettier-ignore
+      C  |  D
+  }
+
+type a= {
+    [
+      /* prettier-ignore */
+      A in B
+    ]: C  |  D
+  }
+
+type a= {
+    [
+      A in
+      /* prettier-ignore */
+      B
+    ]: C  |  D
+  }
+
+type a= {
+    [A in B]:
+      /* prettier-ignore */
+      C  |  D
+  }
+
+
+type a= {
+    /* prettier-ignore */ [A in B]: C  |  D
+  }
+
+type a= {
+    [/* prettier-ignore */ A in B ]: C  |  D
+  }
+
+type a= {
+    [A in /* prettier-ignore */ B]: C  |  D
+  }
+
+type a= {
+    [A in B]: /* prettier-ignore */ C  |  D
+  }
+
+type a= {
+    /* prettier-ignore */
+    [A in B]: C  |  D
+  }
+
+=====================================output=====================================
+type a = {
+    // prettier-ignore
+    [A in B]: C  |  D
+  };
+
+type a = {
+    [
+      // prettier-ignore
+      A in B
+    ]: C  |  D
+  };
+
+type a = {
+  [A in // prettier-ignore
+  B]: C | D;
+};
+
+type a = {
+  [A in B]: // prettier-ignore
+  C | D;
+};
+
+type a = {
+    [
+      /* prettier-ignore */
+      A in B
+    ]: C  |  D
+  };
+
+type a = {
+  [A in /* prettier-ignore */
+  B]: C | D;
+};
+
+type a = {
+  [A in B]: /* prettier-ignore */
+  C | D;
+};
+
+type a = {
+    /* prettier-ignore */ [A in B]: C  |  D
+  };
+
+type a = {
+    [/* prettier-ignore */ A in B ]: C  |  D
+  };
+
+type a = {
+  [A in /* prettier-ignore */ B]: C | D;
+};
+
+type a = {
+  [A in B /* prettier-ignore */]: C | D;
+};
+
+type a = {
+    /* prettier-ignore */
+    [A in B]: C  |  D
+  };
+
+================================================================================
+`;
diff --git a/tests/typescript/prettier-ignore/jsfmt.spec.js b/tests/typescript/prettier-ignore/jsfmt.spec.js
new file mode 100644
index 000000000000..2ea3bb6eb2e4
--- /dev/null
+++ b/tests/typescript/prettier-ignore/jsfmt.spec.js
@@ -0,0 +1,1 @@
+run_spec(__dirname, ["typescript"]);
diff --git a/tests/typescript/prettier-ignore/mapped-types.ts b/tests/typescript/prettier-ignore/mapped-types.ts
new file mode 100644
index 000000000000..5a37a573b5a4
--- /dev/null
+++ b/tests/typescript/prettier-ignore/mapped-types.ts
@@ -0,0 +1,68 @@
+type a= {
+    // prettier-ignore
+    [A in B]: C  |  D
+  }
+
+type a= {
+    [
+      // prettier-ignore
+      A in B
+    ]: C  |  D
+  }
+
+type a= {
+    [
+      A in
+      // prettier-ignore
+      B
+    ]: C  |  D
+  }
+
+type a= {
+    [A in B]:
+      // prettier-ignore
+      C  |  D
+  }
+
+type a= {
+    [
+      /* prettier-ignore */
+      A in B
+    ]: C  |  D
+  }
+
+type a= {
+    [
+      A in
+      /* prettier-ignore */
+      B
+    ]: C  |  D
+  }
+
+type a= {
+    [A in B]:
+      /* prettier-ignore */
+      C  |  D
+  }
+
+
+type a= {
+    /* prettier-ignore */ [A in B]: C  |  D
+  }
+
+type a= {
+    [/* prettier-ignore */ A in B ]: C  |  D
+  }
+
+type a= {
+    [A in /* prettier-ignore */ B]: C  |  D
+  }
+
+type a= {
+    [A in B]: /* prettier-ignore */ C  |  D
+  }
+
+type a= {
+    /* prettier-ignore */
+    [A in B]: C  |  D
+  }
diff --git a/tests_config/run_spec.js b/tests_config/run_spec.js
index 862ad62a93cf..27e25c9fc9a7 100644
--- a/tests_config/run_spec.js
+++ b/tests_config/run_spec.js
@@ -40,6 +40,7 @@ const unstableTests = new Map(
     ],
     ["js/no-semi/comments.js", (options) => options.semi === false],
     ["flow/no-semi/comments.js", (options) => options.semi === false],
+    "typescript/prettier-ignore/mapped-types.ts",
     "js/comments/html-like/comment.js",
   ].map((fixture) => {
     const [file, isUnstable = () => true] = Array.isArray(fixture)