Support TypeScript 4.2 abstract constructor signatures (#12628)

Co-authored-by: Huáng Jùnliàng <jlhwung@gmail.com>
Co-authored-by: Nicolò Ribaudo <nicolo.ribaudo@gmail.com>
This commit is contained in:
Sosuke Suzuki 2021-02-22 04:07:55 +09:00 committed by GitHub
parent 74dc70aabb
commit e4588bed22
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 210 additions and 5 deletions

View File

@ -194,6 +194,10 @@ export function TSFunctionType(this: Printer, node: t.TSFunctionType) {
} }
export function TSConstructorType(this: Printer, node: t.TSConstructorType) { export function TSConstructorType(this: Printer, node: t.TSConstructorType) {
if (node.abstract) {
this.word("abstract");
this.space();
}
this.word("new"); this.word("new");
this.space(); this.space();
this.tsPrintFunctionOrConstructorType(node); this.tsPrintFunctionOrConstructorType(node);

View File

@ -0,0 +1 @@
const x: abstract new () => void;

View File

@ -0,0 +1 @@
const x: abstract new () => void;

View File

@ -0,0 +1 @@
const x: new () => void;

View File

@ -0,0 +1 @@
const x: new () => void;

View File

@ -790,10 +790,14 @@ export default (superClass: Class<Parser>): Class<Parser> =>
tsParseFunctionOrConstructorType( tsParseFunctionOrConstructorType(
type: "TSFunctionType" | "TSConstructorType", type: "TSFunctionType" | "TSConstructorType",
abstract?: boolean,
): N.TsFunctionOrConstructorType { ): N.TsFunctionOrConstructorType {
const node: N.TsFunctionOrConstructorType = this.startNode(); const node: N.TsFunctionOrConstructorType = this.startNode();
if (type === "TSConstructorType") { if (type === "TSConstructorType") {
this.expect(tt._new); // $FlowIgnore
node.abstract = !!abstract;
if (abstract) this.next();
this.next(); // eat `new`
} }
this.tsFillSignature(tt.arrow, node); this.tsFillSignature(tt.arrow, node);
return this.finishNode(node, type); return this.finishNode(node, type);
@ -1219,6 +1223,10 @@ export default (superClass: Class<Parser>): Class<Parser> =>
return this.finishNode(node, "TSConditionalType"); return this.finishNode(node, "TSConditionalType");
} }
isAbstractConstructorSignature(): boolean {
return this.isContextual("abstract") && this.lookahead().type === tt._new;
}
tsParseNonConditionalType(): N.TsType { tsParseNonConditionalType(): N.TsType {
if (this.tsIsStartOfFunctionType()) { if (this.tsIsStartOfFunctionType()) {
return this.tsParseFunctionOrConstructorType("TSFunctionType"); return this.tsParseFunctionOrConstructorType("TSFunctionType");
@ -1226,6 +1234,12 @@ export default (superClass: Class<Parser>): Class<Parser> =>
if (this.match(tt._new)) { if (this.match(tt._new)) {
// As in `new () => Date` // As in `new () => Date`
return this.tsParseFunctionOrConstructorType("TSConstructorType"); return this.tsParseFunctionOrConstructorType("TSConstructorType");
} else if (this.isAbstractConstructorSignature()) {
// As in `abstract new () => Date`
return this.tsParseFunctionOrConstructorType(
"TSConstructorType",
/* abstract */ true,
);
} }
return this.tsParseUnionTypeOrHigher(); return this.tsParseUnionTypeOrHigher();
} }

View File

@ -1250,6 +1250,7 @@ export type TsConstructorType = TsTypeBase &
TsSignatureDeclarationBase & { TsSignatureDeclarationBase & {
type: "TSConstructorType", type: "TSConstructorType",
typeAnnotation: TsTypeAnnotation, typeAnnotation: TsTypeAnnotation,
abstract: boolean,
}; };
export type TsTypeReference = TsTypeBase & { export type TsTypeReference = TsTypeBase & {

View File

@ -0,0 +1 @@
let x: abstract new () => void = X;

View File

@ -0,0 +1,52 @@
{
"type": "File",
"start":0,"end":35,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":35}},
"program": {
"type": "Program",
"start":0,"end":35,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":35}},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "VariableDeclaration",
"start":0,"end":35,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":35}},
"declarations": [
{
"type": "VariableDeclarator",
"start":4,"end":34,"loc":{"start":{"line":1,"column":4},"end":{"line":1,"column":34}},
"id": {
"type": "Identifier",
"start":4,"end":30,"loc":{"start":{"line":1,"column":4},"end":{"line":1,"column":30},"identifierName":"x"},
"name": "x",
"typeAnnotation": {
"type": "TSTypeAnnotation",
"start":5,"end":30,"loc":{"start":{"line":1,"column":5},"end":{"line":1,"column":30}},
"typeAnnotation": {
"type": "TSConstructorType",
"start":7,"end":30,"loc":{"start":{"line":1,"column":7},"end":{"line":1,"column":30}},
"abstract": true,
"parameters": [],
"typeAnnotation": {
"type": "TSTypeAnnotation",
"start":23,"end":30,"loc":{"start":{"line":1,"column":23},"end":{"line":1,"column":30}},
"typeAnnotation": {
"type": "TSVoidKeyword",
"start":26,"end":30,"loc":{"start":{"line":1,"column":26},"end":{"line":1,"column":30}}
}
}
}
}
},
"init": {
"type": "Identifier",
"start":33,"end":34,"loc":{"start":{"line":1,"column":33},"end":{"line":1,"column":34},"identifierName":"X"},
"name": "X"
}
}
],
"kind": "let"
}
],
"directives": []
}
}

View File

@ -0,0 +1 @@
let x: new () => void = X;

View File

@ -0,0 +1,52 @@
{
"type": "File",
"start":0,"end":26,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":26}},
"program": {
"type": "Program",
"start":0,"end":26,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":26}},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "VariableDeclaration",
"start":0,"end":26,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":26}},
"declarations": [
{
"type": "VariableDeclarator",
"start":4,"end":25,"loc":{"start":{"line":1,"column":4},"end":{"line":1,"column":25}},
"id": {
"type": "Identifier",
"start":4,"end":21,"loc":{"start":{"line":1,"column":4},"end":{"line":1,"column":21},"identifierName":"x"},
"name": "x",
"typeAnnotation": {
"type": "TSTypeAnnotation",
"start":5,"end":21,"loc":{"start":{"line":1,"column":5},"end":{"line":1,"column":21}},
"typeAnnotation": {
"type": "TSConstructorType",
"start":7,"end":21,"loc":{"start":{"line":1,"column":7},"end":{"line":1,"column":21}},
"abstract": false,
"parameters": [],
"typeAnnotation": {
"type": "TSTypeAnnotation",
"start":14,"end":21,"loc":{"start":{"line":1,"column":14},"end":{"line":1,"column":21}},
"typeAnnotation": {
"type": "TSVoidKeyword",
"start":17,"end":21,"loc":{"start":{"line":1,"column":17},"end":{"line":1,"column":21}}
}
}
}
}
},
"init": {
"type": "Identifier",
"start":24,"end":25,"loc":{"start":{"line":1,"column":24},"end":{"line":1,"column":25},"identifierName":"X"},
"name": "X"
}
}
],
"kind": "let"
}
],
"directives": []
}
}

View File

@ -0,0 +1,2 @@
type abstract = "abstract";
let x: abstract;

View File

@ -0,0 +1,65 @@
{
"type": "File",
"start":0,"end":44,"loc":{"start":{"line":1,"column":0},"end":{"line":2,"column":16}},
"program": {
"type": "Program",
"start":0,"end":44,"loc":{"start":{"line":1,"column":0},"end":{"line":2,"column":16}},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "TSTypeAliasDeclaration",
"start":0,"end":27,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":27}},
"id": {
"type": "Identifier",
"start":5,"end":13,"loc":{"start":{"line":1,"column":5},"end":{"line":1,"column":13},"identifierName":"abstract"},
"name": "abstract"
},
"typeAnnotation": {
"type": "TSLiteralType",
"start":16,"end":26,"loc":{"start":{"line":1,"column":16},"end":{"line":1,"column":26}},
"literal": {
"type": "StringLiteral",
"start":16,"end":26,"loc":{"start":{"line":1,"column":16},"end":{"line":1,"column":26}},
"extra": {
"rawValue": "abstract",
"raw": "\"abstract\""
},
"value": "abstract"
}
}
},
{
"type": "VariableDeclaration",
"start":28,"end":44,"loc":{"start":{"line":2,"column":0},"end":{"line":2,"column":16}},
"declarations": [
{
"type": "VariableDeclarator",
"start":32,"end":43,"loc":{"start":{"line":2,"column":4},"end":{"line":2,"column":15}},
"id": {
"type": "Identifier",
"start":32,"end":43,"loc":{"start":{"line":2,"column":4},"end":{"line":2,"column":15},"identifierName":"x"},
"name": "x",
"typeAnnotation": {
"type": "TSTypeAnnotation",
"start":33,"end":43,"loc":{"start":{"line":2,"column":5},"end":{"line":2,"column":15}},
"typeAnnotation": {
"type": "TSTypeReference",
"start":35,"end":43,"loc":{"start":{"line":2,"column":7},"end":{"line":2,"column":15}},
"typeName": {
"type": "Identifier",
"start":35,"end":43,"loc":{"start":{"line":2,"column":7},"end":{"line":2,"column":15},"identifierName":"abstract"},
"name": "abstract"
}
}
}
},
"init": null
}
],
"kind": "let"
}
],
"directives": []
}
}

View File

@ -1772,6 +1772,7 @@ export interface TSConstructorType extends BaseNode {
typeParameters?: TSTypeParameterDeclaration | null; typeParameters?: TSTypeParameterDeclaration | null;
parameters: Array<Identifier | RestElement>; parameters: Array<Identifier | RestElement>;
typeAnnotation?: TSTypeAnnotation | null; typeAnnotation?: TSTypeAnnotation | null;
abstract?: boolean | null;
} }
export interface TSTypeReference extends BaseNode { export interface TSTypeReference extends BaseNode {

View File

@ -157,14 +157,22 @@ defineType("TSThisType", {
fields: {}, fields: {},
}); });
const fnOrCtr = { const fnOrCtrBase = {
aliases: ["TSType"], aliases: ["TSType"],
visitor: ["typeParameters", "parameters", "typeAnnotation"], visitor: ["typeParameters", "parameters", "typeAnnotation"],
fields: signatureDeclarationCommon,
}; };
defineType("TSFunctionType", fnOrCtr); defineType("TSFunctionType", {
defineType("TSConstructorType", fnOrCtr); ...fnOrCtrBase,
fields: signatureDeclarationCommon,
});
defineType("TSConstructorType", {
...fnOrCtrBase,
fields: {
...signatureDeclarationCommon,
abstract: validateOptional(bool),
},
});
defineType("TSTypeReference", { defineType("TSTypeReference", {
aliases: ["TSType"], aliases: ["TSType"],