Fix handling of new keyword and call signatures and improve type parameter formatting (#1491)
* fix(typescript): fix handling of new keyword * fix(typescript): fix handling of call signatures * feat(typescript): share type parameter formatting with flowmaster
parent
59b348f550
commit
aeeaffca35
|
@ -1,3 +1,4 @@
|
|||
node_modules
|
||||
npm-debug.log
|
||||
/test.js
|
||||
/.vscode
|
145
src/printer.js
145
src/printer.js
|
@ -756,6 +756,7 @@ function genericPrintNoParens(path, options, print, args) {
|
|||
// typescript accepts ";" and newlines
|
||||
var separator = isTypeAnnotation ? "," : ",";
|
||||
var fields = [];
|
||||
var prefix = [];
|
||||
var leftBrace = n.exact ? "{|" : "{";
|
||||
var rightBrace = n.exact ? "|}" : "}";
|
||||
var parent = path.getParentNode(0);
|
||||
|
@ -763,35 +764,25 @@ function genericPrintNoParens(path, options, print, args) {
|
|||
var propertiesField = isTypeScriptType
|
||||
? "members"
|
||||
: "properties";
|
||||
var prefix = []
|
||||
|
||||
if (isTypeAnnotation) {
|
||||
fields.push("indexers", "callProperties");
|
||||
}
|
||||
|
||||
if (isTypeScriptInterfaceDeclaration) {
|
||||
prefix.push(
|
||||
printTypeScriptModifiers(path, options, print),
|
||||
"interface ",
|
||||
path.call(print, "name"),
|
||||
printTypeParameters(path, options, print, "typeParameters"),
|
||||
" "
|
||||
);
|
||||
}
|
||||
if (n.heritageClauses) {
|
||||
prefix.push(
|
||||
"extends ",
|
||||
join(", ", path.map(print, "heritageClauses")),
|
||||
" "
|
||||
);
|
||||
|
||||
if (n.typeParameters) {
|
||||
prefix.push(
|
||||
"<",
|
||||
join(", ", path.map(print, "typeParameters")),
|
||||
">"
|
||||
);
|
||||
}
|
||||
|
||||
if (n.heritageClauses) {
|
||||
prefix.push(
|
||||
"extends ",
|
||||
join(", ", path.map(print, "heritageClauses")),
|
||||
" "
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fields.push(propertiesField);
|
||||
|
@ -1810,10 +1801,8 @@ function genericPrintNoParens(path, options, print, args) {
|
|||
// with flow they are one `TypeParameterDeclaration` node.
|
||||
if (n.type === 'TSFunctionType' && n.typeParameters) {
|
||||
parts.push(
|
||||
"<",
|
||||
join(", ", path.map(print, "typeParameters")),
|
||||
">"
|
||||
)
|
||||
printTypeParameters(path, options, print, "typeParameters")
|
||||
);
|
||||
} else {
|
||||
parts.push(path.call(print, "typeParameters"));
|
||||
}
|
||||
|
@ -2026,31 +2015,8 @@ function genericPrintNoParens(path, options, print, args) {
|
|||
")"
|
||||
]);
|
||||
case "TypeParameterDeclaration":
|
||||
case "TypeParameterInstantiation": {
|
||||
const shouldInline =
|
||||
n.params.length === 1 &&
|
||||
(n.params[0].type === "ObjectTypeAnnotation" ||
|
||||
n.params[0].type === "NullableTypeAnnotation");
|
||||
|
||||
if (shouldInline) {
|
||||
return concat(["<", join(", ", path.map(print, "params")), ">"]);
|
||||
}
|
||||
|
||||
return group(
|
||||
concat([
|
||||
"<",
|
||||
indent(
|
||||
concat([
|
||||
softline,
|
||||
join(concat([",", line]), path.map(print, "params"))
|
||||
])
|
||||
),
|
||||
ifBreak(shouldPrintComma(options, "all") ? "," : ""),
|
||||
softline,
|
||||
">"
|
||||
])
|
||||
);
|
||||
}
|
||||
case "TypeParameterInstantiation":
|
||||
return printTypeParameters(path, options, print, "params");
|
||||
case "TypeParameter":
|
||||
var variance = getFlowVariance(n, options);
|
||||
|
||||
|
@ -2140,30 +2106,9 @@ function genericPrintNoParens(path, options, print, args) {
|
|||
|
||||
return concat(parts);
|
||||
case "TSTypeReference":
|
||||
parts.push(path.call(print, "typeName"))
|
||||
|
||||
if (n.typeArguments) {
|
||||
parts.push(
|
||||
"<",
|
||||
join(", ", path.map(print, "typeArguments")),
|
||||
">"
|
||||
)
|
||||
}
|
||||
|
||||
return concat(parts);
|
||||
case "TSCallSignature":
|
||||
return concat([
|
||||
"(",
|
||||
join(", ", path.map(print, "parameters")),
|
||||
"): ",
|
||||
path.call(print, "typeAnnotation")
|
||||
]);
|
||||
case "TSConstructSignature":
|
||||
return concat([
|
||||
"new (",
|
||||
join(", ", path.map(print, "parameters")),
|
||||
"): ",
|
||||
path.call(print, "typeAnnotation")
|
||||
path.call(print, "typeName"),
|
||||
printTypeParameters(path, options, print, "typeArguments")
|
||||
]);
|
||||
case "TSTypeQuery":
|
||||
return concat(["typeof ", path.call(print, "exprName")]);
|
||||
|
@ -2199,13 +2144,26 @@ function genericPrintNoParens(path, options, print, args) {
|
|||
path.call(print, "indexType"),
|
||||
"]"
|
||||
])
|
||||
case "TSConstructSignature":
|
||||
case "TSConstructorType":
|
||||
return concat([
|
||||
"new(",
|
||||
case "TSCallSignature":
|
||||
if (n.type !== "TSCallSignature") {
|
||||
parts.push("new ");
|
||||
}
|
||||
var isType = n.type === "TSConstructorType";
|
||||
parts.push(
|
||||
printTypeParameters(path, options, print, "typeParameters"),
|
||||
"(",
|
||||
join(", ", path.map(print, "parameters")),
|
||||
") => ",
|
||||
path.call(print, "typeAnnotation"),
|
||||
])
|
||||
")"
|
||||
);
|
||||
if (n.typeAnnotation) {
|
||||
parts.push(
|
||||
isType ? " => " : ": ",
|
||||
path.call(print, "typeAnnotation")
|
||||
);
|
||||
}
|
||||
return concat(parts);
|
||||
case "TSTypeOperator":
|
||||
return concat([
|
||||
"keyof ",
|
||||
|
@ -2223,13 +2181,13 @@ function genericPrintNoParens(path, options, print, args) {
|
|||
"}"
|
||||
])
|
||||
case "TSTypeParameter":
|
||||
parts.push(path.call(print, "name"))
|
||||
parts.push(path.call(print, "name"));
|
||||
|
||||
if (n.constraint) {
|
||||
parts.push(
|
||||
" in ",
|
||||
path.call(print, "constraint")
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return concat(parts)
|
||||
|
@ -3014,6 +2972,39 @@ function printTypeScriptModifiers(path, options, print) {
|
|||
]);
|
||||
}
|
||||
|
||||
function printTypeParameters(path, options, print, paramsKey) {
|
||||
const n = path.getValue();
|
||||
|
||||
// In flow, Foo<> is acceptable. In TypeScript, it's a syntax error.
|
||||
if (!n[paramsKey] || (n.type.startsWith("TS") && !n[paramsKey].length)) {
|
||||
return "";
|
||||
}
|
||||
|
||||
const shouldInline =
|
||||
n[paramsKey].length === 1 &&
|
||||
(n[paramsKey][0].type === "ObjectTypeAnnotation" ||
|
||||
n[paramsKey][0].type === "NullableTypeAnnotation");
|
||||
|
||||
if (shouldInline) {
|
||||
return concat(["<", join(", ", path.map(print, paramsKey)), ">"]);
|
||||
}
|
||||
|
||||
return group(
|
||||
concat([
|
||||
"<",
|
||||
indent(
|
||||
concat([
|
||||
softline,
|
||||
join(concat([",", line]), path.map(print, paramsKey))
|
||||
])
|
||||
),
|
||||
ifBreak(shouldPrintComma(options, "all") ? "," : ""),
|
||||
softline,
|
||||
">"
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
function printClass(path, options, print) {
|
||||
const n = path.getValue();
|
||||
const parts = [];
|
||||
|
|
|
@ -134,7 +134,7 @@ class C6 extends Mix(Public, Public2) {
|
|||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// @declaration: true
|
||||
|
||||
type Constructable = new(...args: any[]) => object;
|
||||
type Constructable = new (...args: any[]) => object;
|
||||
|
||||
class Private {
|
||||
constructor(...args: any[]) {}
|
||||
|
@ -307,7 +307,7 @@ class Thing3 extends Thing2 {
|
|||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// @declaration: true
|
||||
|
||||
type Constructor<T> = new(...args: any[]) => T;
|
||||
type Constructor<T> = new (...args: any[]) => T;
|
||||
|
||||
class Base {
|
||||
constructor(public x: number, public y: number) {}
|
||||
|
@ -437,7 +437,7 @@ const Timestamped = <CT extends Constructor<object>>(Base: CT) => {
|
|||
};
|
||||
}
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
type Constructor<T> = new(...args: any[]) => T;
|
||||
type Constructor<T> = new (...args: any[]) => T;
|
||||
|
||||
class Base {
|
||||
constructor(public x: number, public y: number) {}
|
||||
|
|
|
@ -45,7 +45,7 @@ AAA = A;
|
|||
AAA = "asdf";~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
abstract class A {}
|
||||
|
||||
var AAA: new() => A;
|
||||
var AAA: new () => A;
|
||||
|
||||
AAA = A;
|
||||
AAA = "asdf";
|
||||
|
|
|
@ -3,6 +3,6 @@
|
|||
exports[`cunstructorType.ts 1`] = `
|
||||
var d: new(x: number) => void;
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
var d: new(x: number) => void;
|
||||
var d: new (x: number) => void;
|
||||
|
||||
`;
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`callSignature.ts 1`] = `
|
||||
interface I {
|
||||
();
|
||||
(): void;
|
||||
<T, U>(arg: T);
|
||||
<T, U>(arg: T): U;
|
||||
}
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
interface I {
|
||||
(),
|
||||
(): void,
|
||||
<T, U>(arg: T),
|
||||
<T, U>(arg: T): U
|
||||
}
|
||||
|
||||
`;
|
|
@ -0,0 +1,6 @@
|
|||
interface I {
|
||||
();
|
||||
(): void;
|
||||
<T, U>(arg: T);
|
||||
<T, U>(arg: T): U;
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
run_spec(__dirname, { parser: "typescript" });
|
|
@ -0,0 +1,20 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`newKeyword.ts 1`] = `
|
||||
var x: { y: new <T, U> () => [T, U] };
|
||||
|
||||
interface I {
|
||||
new <T>(x: string);
|
||||
new (x: string);
|
||||
new (x: number): number;
|
||||
}
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
var x: { y: new <T, U>() => [T, U] };
|
||||
|
||||
interface I {
|
||||
new <T>(x: string),
|
||||
new (x: string),
|
||||
new (x: number): number
|
||||
}
|
||||
|
||||
`;
|
|
@ -0,0 +1 @@
|
|||
run_spec(__dirname, { parser: "typescript" });
|
|
@ -0,0 +1,7 @@
|
|||
var x: { y: new <T, U> () => [T, U] };
|
||||
|
||||
interface I {
|
||||
new <T>(x: string);
|
||||
new (x: string);
|
||||
new (x: number): number;
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`callAndConstructSignatureLong.ts 1`] = `
|
||||
interface Interface {
|
||||
<
|
||||
Voila,
|
||||
InViewHumbleVaudevillianVeteran,
|
||||
CastVicariouslyAsBothVictimAndVillainByTheVicissitudesOfFate
|
||||
>(): V;
|
||||
new <
|
||||
ThisVisage,
|
||||
NoMereVeneerOfVanity,
|
||||
IsAVestigeOfTheVoxPopuliNowVacant,
|
||||
Vanished
|
||||
>(): V;
|
||||
}
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
interface Interface {
|
||||
<
|
||||
Voila,
|
||||
InViewHumbleVaudevillianVeteran,
|
||||
CastVicariouslyAsBothVictimAndVillainByTheVicissitudesOfFate
|
||||
>(): V,
|
||||
new <
|
||||
ThisVisage,
|
||||
NoMereVeneerOfVanity,
|
||||
IsAVestigeOfTheVoxPopuliNowVacant,
|
||||
Vanished
|
||||
>(): V
|
||||
}
|
||||
|
||||
`;
|
||||
|
||||
exports[`functionTypeLong.ts 1`] = `
|
||||
type AwkwardlyLongFunctionTypeDefinition = <
|
||||
GenericTypeNumberOne,
|
||||
GenericTypeNumberTwo,
|
||||
GenericTypeNumberThree
|
||||
>(
|
||||
arg1: GenericTypeNumberOne,
|
||||
arg2: GenericTypeNumberTwo,
|
||||
arg3: GenericTypeNumberThree
|
||||
) => (GenericTypeNumberOne | GenericTypeNumberTwo | GenericTypeNumberThree);
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
type AwkwardlyLongFunctionTypeDefinition = <
|
||||
GenericTypeNumberOne,
|
||||
GenericTypeNumberTwo,
|
||||
GenericTypeNumberThree
|
||||
>(
|
||||
arg1: GenericTypeNumberOne,
|
||||
arg2: GenericTypeNumberTwo,
|
||||
arg3: GenericTypeNumberThree
|
||||
) => (GenericTypeNumberOne | GenericTypeNumberTwo | GenericTypeNumberThree);
|
||||
|
||||
`;
|
||||
|
||||
exports[`interfaceParamsLong.ts 1`] = `
|
||||
interface ReallyReallyLongName<
|
||||
TypeArgumentNumberOne,
|
||||
TypeArgumentNumberTwo,
|
||||
TypeArgumentNumberThree
|
||||
> {}
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
interface ReallyReallyLongName<
|
||||
TypeArgumentNumberOne,
|
||||
TypeArgumentNumberTwo,
|
||||
TypeArgumentNumberThree
|
||||
> {}
|
||||
|
||||
`;
|
||||
|
||||
exports[`typeParametersLong.ts 1`] = `
|
||||
type ReallyReallyReallyLongName<
|
||||
ReallyReallyReallyLongName1, ReallyReallyReallyLongName2
|
||||
> = any;
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
type ReallyReallyReallyLongName<
|
||||
ReallyReallyReallyLongName1,
|
||||
ReallyReallyReallyLongName2
|
||||
> = any;
|
||||
|
||||
`;
|
|
@ -0,0 +1,13 @@
|
|||
interface Interface {
|
||||
<
|
||||
Voila,
|
||||
InViewHumbleVaudevillianVeteran,
|
||||
CastVicariouslyAsBothVictimAndVillainByTheVicissitudesOfFate
|
||||
>(): V;
|
||||
new <
|
||||
ThisVisage,
|
||||
NoMereVeneerOfVanity,
|
||||
IsAVestigeOfTheVoxPopuliNowVacant,
|
||||
Vanished
|
||||
>(): V;
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
type AwkwardlyLongFunctionTypeDefinition = <
|
||||
GenericTypeNumberOne,
|
||||
GenericTypeNumberTwo,
|
||||
GenericTypeNumberThree
|
||||
>(
|
||||
arg1: GenericTypeNumberOne,
|
||||
arg2: GenericTypeNumberTwo,
|
||||
arg3: GenericTypeNumberThree
|
||||
) => (GenericTypeNumberOne | GenericTypeNumberTwo | GenericTypeNumberThree);
|
|
@ -0,0 +1,5 @@
|
|||
interface ReallyReallyLongName<
|
||||
TypeArgumentNumberOne,
|
||||
TypeArgumentNumberTwo,
|
||||
TypeArgumentNumberThree
|
||||
> {}
|
|
@ -0,0 +1 @@
|
|||
run_spec(__dirname, { parser: "typescript" });
|
|
@ -0,0 +1,3 @@
|
|||
type ReallyReallyReallyLongName<
|
||||
ReallyReallyReallyLongName1, ReallyReallyReallyLongName2
|
||||
> = any;
|
Loading…
Reference in New Issue