Improve formatting of TS casts with generics and unions (#4219)

* Add tests showing existing behavior of various TS casts.

* Improve formatting of TS casts with generics and unions.

By adding a soft break between the cast and the expression. Also
includes wrapping parentheses for clarity as suggested in #4171.

Avoids changing behavior at all though if casting an array or object
literal because those already have good behavior where the array or
object literal breaks before the cast does so including them would just
result in a pointless extra layer of parentheses that would add no
clarity.

* Update tests in prepation for updating long cast format.

* Update so nested breaks inside type cast are indented.

* Add tests where expression being cast is too long itself.

* Update cast formatting to only sometimes break after cast.

Specifically it will break after the cast if that makes the cast itself
fit on a single line. If the cast itself won't fit on a single line then
the expression being cast will be placed directly after the `>` at the
end of the cast.
master
Kevin Donnelly 2018-05-07 23:26:01 -05:00 committed by Suchipi
parent ed18f9f7d7
commit c6e7c1966e
3 changed files with 333 additions and 6 deletions

View File

@ -487,13 +487,37 @@ function printPathNoParens(path, options, print, args) {
" = ",
path.call(print, "right")
]);
case "TSTypeAssertionExpression":
return concat([
"<",
path.call(print, "typeAnnotation"),
">",
path.call(print, "expression")
case "TSTypeAssertionExpression": {
const shouldBreakAfterCast = !(
n.expression.type === "ArrayExpression" ||
n.expression.type === "ObjectExpression"
);
const castGroup = group(
concat([
"<",
indent(concat([softline, path.call(print, "typeAnnotation")])),
softline,
">"
])
);
const exprContents = concat([
ifBreak("("),
indent(concat([softline, path.call(print, "expression")])),
softline,
ifBreak(")")
]);
if (shouldBreakAfterCast) {
return conditionalGroup([
concat([castGroup, path.call(print, "expression")]),
concat([castGroup, group(exprContents, { shouldBreak: true })]),
concat([castGroup, path.call(print, "expression")])
]);
}
return group(concat([castGroup, path.call(print, "expression")]));
}
case "MemberExpression": {
const parent = path.getParentNode();
let firstNonMemberParent;
@ -2506,6 +2530,7 @@ function printPathNoParens(path, options, print, args) {
// | C
const parent = path.getParentNode();
const parentParent = path.getParentNode(1);
// If there's a leading comment, the parent is doing the indentation
const shouldIndent =
@ -2514,6 +2539,8 @@ function printPathNoParens(path, options, print, args) {
parent.type !== "GenericTypeAnnotation" &&
parent.type !== "TSTypeReference" &&
!(parent.type === "FunctionTypeParam" && !parent.name) &&
parentParent.type !== "TSTypeAssertionExpression" &&
!(
(parent.type === "TypeAlias" ||
parent.type === "VariableDeclarator") &&

View File

@ -1,5 +1,251 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`generic-cast.ts 1`] = `
// https://github.com/prettier/prettier/issues/4171
function y() {
const fits = <Immutable.Map<string, any>>fits();
const fitsObjLiteral = <Immutable.Map<string, any>>{ a: "test" };
const fitsArrayLiteral = <Immutable.Map<string, any>>["test", "test2"]
const breakAfterCast = <Immutable.Map<string, any>>someExistingConfigMap.mergeDeep(fallbackOpts);
const stillTooLong = <Immutable.Map<string, boolean, number, object, null, undefined, any, void, never>>someExistingConfigMap.mergeDeep(fallbackOptions);
const stillTooLong2 = <Immutable.Map<string, boolean, number, object, null, undefined, any, void, never> | undefined>someExistingConfigMap.mergeDeep(fallbackOptions);
const stillTooLong3 = <Immutable.Map<string>>someExistingConfigMap.mergeDeep(fallbackOptions.someMethodWithLongName(param1, param2));
const stillTooLong4 = <Immutable.Map<string, boolean, number, object, null, undefined, any, void, never> | undefined>someExistingConfigMap.mergeDeep(fallbackOptions.someMethodWithLongName(param1, param2));
const testObjLiteral = <Immutable.Map<string, any>>{ property1: "myPropertyVal" };
const testObjLiteral2 = <Immutable.Map<string, any, number, boolean, object, null, undefined, never, "extra long">>{ property1: "myPropertyVal" };
const testArrayLiteral = <Immutable.Map<string, any>>["first", "second", "third"];
const testArrayLiteral2 = <Immutable.Map<string, any, number, boolean, object, null, undefined, never, "extra long">>["first", "second", "third"];
const insideFuncCall = myFunc(param1, <Immutable.Map<string, any>>param2, param3)
}
// https://github.com/prettier/prettier/issues/4168
function x() {
const fits = <PermissionsChecker<any> | undefined>(<any>permissions)[type];
const fitsObjLiteral = <PermissionsChecker<any> | undefined>{ a: "test" };
const fitsArrayLiteral = <PermissionsChecker<any> | undefined>["t1", "t2"];
const breakAfterCast = <PermissionsChecker<any> | undefined>(<any>permissions)[receiverType];
const stillTooLong = <PermissionsChecker<object> | undefined | number | string | boolean>(<any>permissions)[receiverType];
const stillTooLong2 = <PermissionsChecker<object> | undefined | number | string | boolean | null | never>(<any>permissions)[receiverType];
const stillTooLong3 = <PermissionsChecker<object> | undefined>(<any>permissions.someMethodWithLongName(parameter1, parameter2))[receiverTypeLongName];
const stillTooLong4 = <PermissionsChecker<object> | undefined | number | string | boolean | null | never>(<any>permissions.someMethodWithLongName(parameter1, parameter2))[receiverTypeLongName];
const testObjLiteral = <PermissionsChecker<any> | undefined>{ prop1: "myPropVal" };
const testObjLiteral2 = <PermissionsChecker<object> | undefined | number | string | boolean | null | never | object>{ prop1: "myPropVal" };
const testArrayLiteral = <PermissionsChecker<any> | undefined>["first", "second", "third"];
const testArrayLiteral2 = <PermissionsChecker<object> | undefined | number | string | boolean | null | never | object>["first", "second", "third"];
const insideFuncCall = myFunc(param1, <PermissionsChecker<any> | undefined>param2, param3)
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// https://github.com/prettier/prettier/issues/4171
function y() {
const fits = <Immutable.Map<string, any>>fits();
const fitsObjLiteral = <Immutable.Map<string, any>>{ a: "test" };
const fitsArrayLiteral = <Immutable.Map<string, any>>["test", "test2"];
const breakAfterCast = <Immutable.Map<string, any>>(
someExistingConfigMap.mergeDeep(fallbackOpts)
);
const stillTooLong = <
Immutable.Map<
string,
boolean,
number,
object,
null,
undefined,
any,
void,
never
>
>someExistingConfigMap.mergeDeep(fallbackOptions);
const stillTooLong2 = <
| Immutable.Map<
string,
boolean,
number,
object,
null,
undefined,
any,
void,
never
>
| undefined
>someExistingConfigMap.mergeDeep(fallbackOptions);
const stillTooLong3 = <Immutable.Map<string>>(
someExistingConfigMap.mergeDeep(
fallbackOptions.someMethodWithLongName(param1, param2)
)
);
const stillTooLong4 = <
| Immutable.Map<
string,
boolean,
number,
object,
null,
undefined,
any,
void,
never
>
| undefined
>someExistingConfigMap.mergeDeep(
fallbackOptions.someMethodWithLongName(param1, param2)
);
const testObjLiteral = <Immutable.Map<string, any>>{
property1: "myPropertyVal"
};
const testObjLiteral2 = <
Immutable.Map<
string,
any,
number,
boolean,
object,
null,
undefined,
never,
"extra long"
>
>{ property1: "myPropertyVal" };
const testArrayLiteral = <Immutable.Map<string, any>>[
"first",
"second",
"third"
];
const testArrayLiteral2 = <
Immutable.Map<
string,
any,
number,
boolean,
object,
null,
undefined,
never,
"extra long"
>
>["first", "second", "third"];
const insideFuncCall = myFunc(
param1,
<Immutable.Map<string, any>>param2,
param3
);
}
// https://github.com/prettier/prettier/issues/4168
function x() {
const fits = <PermissionsChecker<any> | undefined>(<any>permissions)[type];
const fitsObjLiteral = <PermissionsChecker<any> | undefined>{ a: "test" };
const fitsArrayLiteral = <PermissionsChecker<any> | undefined>["t1", "t2"];
const breakAfterCast = <PermissionsChecker<any> | undefined>(
(<any>permissions)[receiverType]
);
const stillTooLong = <
PermissionsChecker<object> | undefined | number | string | boolean
>(<any>permissions)[receiverType];
const stillTooLong2 = <
| PermissionsChecker<object>
| undefined
| number
| string
| boolean
| null
| never
>(<any>permissions)[receiverType];
const stillTooLong3 = <PermissionsChecker<object> | undefined>(
(<any>permissions.someMethodWithLongName(parameter1, parameter2))[
receiverTypeLongName
]
);
const stillTooLong4 = <
| PermissionsChecker<object>
| undefined
| number
| string
| boolean
| null
| never
>(<any>permissions.someMethodWithLongName(parameter1, parameter2))[
receiverTypeLongName
];
const testObjLiteral = <PermissionsChecker<any> | undefined>{
prop1: "myPropVal"
};
const testObjLiteral2 = <
| PermissionsChecker<object>
| undefined
| number
| string
| boolean
| null
| never
| object
>{ prop1: "myPropVal" };
const testArrayLiteral = <PermissionsChecker<any> | undefined>[
"first",
"second",
"third"
];
const testArrayLiteral2 = <
| PermissionsChecker<object>
| undefined
| number
| string
| boolean
| null
| never
| object
>["first", "second", "third"];
const insideFuncCall = myFunc(
param1,
<PermissionsChecker<any> | undefined>param2,
param3
);
}
`;
exports[`hug-args.ts 1`] = `
postMessage(
<IActionMessage>{

View File

@ -0,0 +1,54 @@
// https://github.com/prettier/prettier/issues/4171
function y() {
const fits = <Immutable.Map<string, any>>fits();
const fitsObjLiteral = <Immutable.Map<string, any>>{ a: "test" };
const fitsArrayLiteral = <Immutable.Map<string, any>>["test", "test2"]
const breakAfterCast = <Immutable.Map<string, any>>someExistingConfigMap.mergeDeep(fallbackOpts);
const stillTooLong = <Immutable.Map<string, boolean, number, object, null, undefined, any, void, never>>someExistingConfigMap.mergeDeep(fallbackOptions);
const stillTooLong2 = <Immutable.Map<string, boolean, number, object, null, undefined, any, void, never> | undefined>someExistingConfigMap.mergeDeep(fallbackOptions);
const stillTooLong3 = <Immutable.Map<string>>someExistingConfigMap.mergeDeep(fallbackOptions.someMethodWithLongName(param1, param2));
const stillTooLong4 = <Immutable.Map<string, boolean, number, object, null, undefined, any, void, never> | undefined>someExistingConfigMap.mergeDeep(fallbackOptions.someMethodWithLongName(param1, param2));
const testObjLiteral = <Immutable.Map<string, any>>{ property1: "myPropertyVal" };
const testObjLiteral2 = <Immutable.Map<string, any, number, boolean, object, null, undefined, never, "extra long">>{ property1: "myPropertyVal" };
const testArrayLiteral = <Immutable.Map<string, any>>["first", "second", "third"];
const testArrayLiteral2 = <Immutable.Map<string, any, number, boolean, object, null, undefined, never, "extra long">>["first", "second", "third"];
const insideFuncCall = myFunc(param1, <Immutable.Map<string, any>>param2, param3)
}
// https://github.com/prettier/prettier/issues/4168
function x() {
const fits = <PermissionsChecker<any> | undefined>(<any>permissions)[type];
const fitsObjLiteral = <PermissionsChecker<any> | undefined>{ a: "test" };
const fitsArrayLiteral = <PermissionsChecker<any> | undefined>["t1", "t2"];
const breakAfterCast = <PermissionsChecker<any> | undefined>(<any>permissions)[receiverType];
const stillTooLong = <PermissionsChecker<object> | undefined | number | string | boolean>(<any>permissions)[receiverType];
const stillTooLong2 = <PermissionsChecker<object> | undefined | number | string | boolean | null | never>(<any>permissions)[receiverType];
const stillTooLong3 = <PermissionsChecker<object> | undefined>(<any>permissions.someMethodWithLongName(parameter1, parameter2))[receiverTypeLongName];
const stillTooLong4 = <PermissionsChecker<object> | undefined | number | string | boolean | null | never>(<any>permissions.someMethodWithLongName(parameter1, parameter2))[receiverTypeLongName];
const testObjLiteral = <PermissionsChecker<any> | undefined>{ prop1: "myPropVal" };
const testObjLiteral2 = <PermissionsChecker<object> | undefined | number | string | boolean | null | never | object>{ prop1: "myPropVal" };
const testArrayLiteral = <PermissionsChecker<any> | undefined>["first", "second", "third"];
const testArrayLiteral2 = <PermissionsChecker<object> | undefined | number | string | boolean | null | never | object>["first", "second", "third"];
const insideFuncCall = myFunc(param1, <PermissionsChecker<any> | undefined>param2, param3)
}