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 flow
master
Lucas Azzola 2017-05-04 01:01:45 +10:00 committed by Christopher Chedeau
parent 59b348f550
commit aeeaffca35
17 changed files with 240 additions and 82 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
node_modules
npm-debug.log
/test.js
/.vscode

View File

@ -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 = [];

View File

@ -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) {}

View File

@ -45,7 +45,7 @@ AAA = A;
AAA = "asdf";~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
abstract class A {}
var AAA: new() => A;
var AAA: new () => A;
AAA = A;
AAA = "asdf";

View File

@ -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;
`;

View File

@ -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
}
`;

View File

@ -0,0 +1,6 @@
interface I {
();
(): void;
<T, U>(arg: T);
<T, U>(arg: T): U;
}

View File

@ -0,0 +1 @@
run_spec(__dirname, { parser: "typescript" });

View File

@ -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
}
`;

View File

@ -0,0 +1 @@
run_spec(__dirname, { parser: "typescript" });

View File

@ -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;
}

View File

@ -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;
`;

View File

@ -0,0 +1,13 @@
interface Interface {
<
Voila,
InViewHumbleVaudevillianVeteran,
CastVicariouslyAsBothVictimAndVillainByTheVicissitudesOfFate
>(): V;
new <
ThisVisage,
NoMereVeneerOfVanity,
IsAVestigeOfTheVoxPopuliNowVacant,
Vanished
>(): V;
}

View File

@ -0,0 +1,9 @@
type AwkwardlyLongFunctionTypeDefinition = <
GenericTypeNumberOne,
GenericTypeNumberTwo,
GenericTypeNumberThree
>(
arg1: GenericTypeNumberOne,
arg2: GenericTypeNumberTwo,
arg3: GenericTypeNumberThree
) => (GenericTypeNumberOne | GenericTypeNumberTwo | GenericTypeNumberThree);

View File

@ -0,0 +1,5 @@
interface ReallyReallyLongName<
TypeArgumentNumberOne,
TypeArgumentNumberTwo,
TypeArgumentNumberThree
> {}

View File

@ -0,0 +1 @@
run_spec(__dirname, { parser: "typescript" });

View File

@ -0,0 +1,3 @@
type ReallyReallyReallyLongName<
ReallyReallyReallyLongName1, ReallyReallyReallyLongName2
> = any;