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

Partial support for TypeScript 3.8 (private fields, import/export type modifier) #7631

Merged
merged 6 commits into from Mar 11, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
9 changes: 9 additions & 0 deletions changelog_unreleased/typescript/pr-7631.md
@@ -0,0 +1,9 @@
#### TypeScript 3.8 ([#7631](https://github.com/prettier/prettier/pull/7631) by [@thorn0](https://github.com/thorn0))

Prettier doesn't yet fully support the new syntax added in TypeScript 3.8:

| Syntax | `typescript` parser | `babel-ts` parser |
| ------------------------------------------------------------------------------------------------------------------------------- | ------------------- | ----------------- |
| [Type-Only Imports and Exports](https://devblogs.microsoft.com/typescript/announcing-typescript-3-8/#type-only-imports-exports) | ✔️ | ❌ |
| [ECMAScript Private Fields](https://devblogs.microsoft.com/typescript/announcing-typescript-3-8/#ecmascript-private-fields) | ✔️ | ✔️ |
| [`export * as ns`](https://devblogs.microsoft.com/typescript/announcing-typescript-3-8/#export-star-as-namespace-syntax) | ❌ | ❌ |
Copy link
Member

Choose a reason for hiding this comment

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

export * as ns seems to be supported with babel-ts.
Playground

parser=babel-ts

Input:

export * as foo from './foo';

Output

export * as foo from "./foo";

Copy link
Member Author

Choose a reason for hiding this comment

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

You're right. Overlooked this somehow. I'll fix the changelog.

19 changes: 18 additions & 1 deletion src/language-js/postprocess.js
@@ -1,6 +1,9 @@
"use strict";

const { getLast } = require("../common/util");
const {
getLast,
getNextNonSpaceNonCommentCharacter
} = require("../common/util");
const { composeLoc, locEnd } = require("./loc");

function postprocess(ast, options) {
Expand Down Expand Up @@ -48,6 +51,20 @@ function postprocess(ast, options) {
node.end = getLast(node.expressions).end;
}
break;
case "ClassProperty":
// TODO: Temporary auto-generated node type. To remove when typescript-estree has proper support for private fields.
if (
node.key &&
node.key.type === "TSPrivateIdentifier" &&
getNextNonSpaceNonCommentCharacter(
options.originalText,
node.key,
locEnd
) === "?"
) {
node.optional = true;
}
break;
}
});

Expand Down
4 changes: 4 additions & 0 deletions src/language-js/printer-estree.js
Expand Up @@ -3521,6 +3521,10 @@ function printPathNoParens(path, options, print, args) {
case "PrivateName":
return concat(["#", path.call(print, "id")]);

// TODO: Temporary auto-generated node type. To remove when typescript-estree has proper support for private fields.
case "TSPrivateIdentifier":
return n.escapedText;

case "TSConditionalType":
return printTernaryOperator(path, options, print, {
beforeParts: () => [
Expand Down
54 changes: 54 additions & 0 deletions tests/typescript_class/__snapshots__/jsfmt.spec.js.snap
Expand Up @@ -253,3 +253,57 @@ class User {

================================================================================
`;

exports[`standard_private_fields.ts 1`] = `
====================================options=====================================
parsers: ["typescript"]
printWidth: 80
| printWidth
=====================================input======================================
class Square {
#sideLength: number;
readonly #area: number;
#unit?: string;

constructor(sideLength: number, unit?: string) {
this.#sideLength = sideLength;
this.#area = this.#sideLength ** 2;
if (unit) {
this.#unit = unit;
}
}

equals(other: any) {
return this.#sideLength === other.#sideLength;
}

getArea() {
return this.#area + (this.#unit ?? 'px') + '²';
}
}

=====================================output=====================================
class Square {
#sideLength: number;
readonly #area: number;
#unit?: string;

constructor(sideLength: number, unit?: string) {
this.#sideLength = sideLength;
this.#area = this.#sideLength ** 2;
if (unit) {
this.#unit = unit;
}
}

equals(other: any) {
return this.#sideLength === other.#sideLength;
}

getArea() {
return this.#area + (this.#unit ?? "px") + "²";
}
}

================================================================================
`;
21 changes: 21 additions & 0 deletions tests/typescript_class/standard_private_fields.ts
@@ -0,0 +1,21 @@
class Square {
#sideLength: number;
thorn0 marked this conversation as resolved.
Show resolved Hide resolved
readonly #area: number;
#unit?: string;

constructor(sideLength: number, unit?: string) {
this.#sideLength = sideLength;
this.#area = this.#sideLength ** 2;
if (unit) {
this.#unit = unit;
}
}

equals(other: any) {
return this.#sideLength === other.#sideLength;
}

getArea() {
return this.#area + (this.#unit ?? 'px') + '²';
}
}
16 changes: 16 additions & 0 deletions tests/typescript_export/__snapshots__/jsfmt.spec.js.snap
Expand Up @@ -60,6 +60,22 @@ declare module "hello" {
================================================================================
`;

exports[`export-as-ns.ts 1`] = `
====================================options=====================================
parsers: ["typescript"]
printWidth: 80
| printWidth
=====================================input======================================
// TODO: uncomment when typescript-estree gets support for this syntax
// export * as utilities from "./utilities.js";

=====================================output=====================================
// TODO: uncomment when typescript-estree gets support for this syntax
// export * as utilities from "./utilities.js";

================================================================================
`;

exports[`export-class.js 1`] = `
====================================options=====================================
parsers: ["typescript"]
Expand Down
2 changes: 2 additions & 0 deletions tests/typescript_export/export-as-ns.ts
@@ -0,0 +1,2 @@
// TODO: uncomment when typescript-estree gets support for this syntax
// export * as utilities from "./utilities.js";
j-f1 marked this conversation as resolved.
Show resolved Hide resolved
45 changes: 45 additions & 0 deletions tests/typescript_import_export/__snapshots__/jsfmt.spec.js.snap
@@ -0,0 +1,45 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`type-modifier.ts 1`] = `
====================================options=====================================
parsers: ["typescript"]
printWidth: 80
| printWidth
=====================================input======================================
export type { SomeThing };
export type { A as B };
export type { B as C } from './a';
export type { foo } from 'bar';
export type * from 'bar';
export type { foo };

// this should be treated as a normal import statement
import type from './foo';

import type { SomeThing } from "./some-module.js";
import type { foo, bar } from 'baz';
import type { foo as bar } from 'baz';
import type * as foo from './bar';
import type foo from 'bar';
import type foo, { bar } from 'bar';

=====================================output=====================================
export type { SomeThing };
export type { A as B };
export type { B as C } from "./a";
export type { foo } from "bar";
export type * from "bar";
Copy link
Member

Choose a reason for hiding this comment

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

@thorn0 Is this test needed? TS Playground says "Only named exports may use 'export type'.".
https://www.typescriptlang.org/play/?ssl=1&ssc=1&pln=2&pc=1#code/KYDwDg9gTgLgBDAnmYcBUcBmUIFs4BEARgIZQEDcAUEA

Copy link
Member Author

Choose a reason for hiding this comment

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

Let's remove this test. Babel 7.9.0 can't parse it.

export type { foo };

// this should be treated as a normal import statement
import type from "./foo";

import type { SomeThing } from "./some-module.js";
import type { foo, bar } from "baz";
import type { foo as bar } from "baz";
import type * as foo from "./bar";
import type foo from "bar";
import type foo, { bar } from "bar";

================================================================================
`;
2 changes: 2 additions & 0 deletions tests/typescript_import_export/jsfmt.spec.js
@@ -0,0 +1,2 @@
// TODO: remove disableBabelTS when Babel's TS plugin gets support for import/export `type` modifier
run_spec(__dirname, ["typescript"], { disableBabelTS: true });
16 changes: 16 additions & 0 deletions tests/typescript_import_export/type-modifier.ts
@@ -0,0 +1,16 @@
export type { SomeThing };
export type { A as B };
export type { B as C } from './a';
export type { foo } from 'bar';
export type * from 'bar';
export type { foo };

// this should be treated as a normal import statement
import type from './foo';

import type { SomeThing } from "./some-module.js";
import type { foo, bar } from 'baz';
import type { foo as bar } from 'baz';
import type * as foo from './bar';
import type foo from 'bar';
import type foo, { bar } from 'bar';