跳转到主要内容

TypeScript

所以你已经完成了JavaScript,现在想要挑战解析TypeScript了?坏消息是没有规范,但好消息是TypeScript解析器在一个单一文件中 🙃。

JSX vs TSX

对于以下代码,

let foo = <string> bar;

如果这是tsx,那么这是一个语法错误(未终止的JSX),但如果是VariableDeclarationTSTypeAssertion,那么这是正确的。

前向查找 (lookahead)

在某些地方,解析器需要向前查找并查看多个 token 以决定正确的语法。

TSIndexSignature

例如,为了解析TSIndexSignature,考虑以下两种情况:

type A = { readonly [a: number]: string }
^__________________________^ TSIndexSignature

type B = { [a]: string }
^_________^ TSPropertySignature

对于第一个type A中的{,我们需要向前查看5个 token (readonly[a:number)以确保它是TSIndexSignature而不是TSPropertySignature

为了实现这一点并提高效率,词法分析器需要一个缓冲区来存储多个 token 。

箭头表达式

cover grammar中讨论过,当在 SequenceExpression 后面找到=> token 时,我们需要将Expression转换为BindingPattern

但是对于TypeScript来说,这种方法不适用,因为()中的每个项目都可能有TypeScript语法,有太多情况需要考虑,例如:

<x>a, b as c, d!;
(a?: b = {} as c!) => {};

建议研究TypeScript源代码来处理这个问题。相关代码如下:

function tryParseParenthesizedArrowFunctionExpression(
allowReturnTypeInArrowFunction: boolean,
): Expression | undefined {
const triState = isParenthesizedArrowFunctionExpression();
if (triState === Tristate.False) {
// It's definitely not a parenthesized arrow function expression.
return undefined;
}

// If we definitely have an arrow function, then we can just parse one, not requiring a
// following => or { token. Otherwise, we *might* have an arrow function. Try to parse
// it out, but don't allow any ambiguity, and return 'undefined' if this could be an
// expression instead.
return triState === Tristate.True
? parseParenthesizedArrowFunctionExpression(
/*allowAmbiguity*/ true,
/*allowReturnTypeInArrowFunction*/ true,
)
: tryParse(() =>
parsePossibleParenthesizedArrowFunctionExpression(
allowReturnTypeInArrowFunction,
),
);
}

// True -> We definitely expect a parenthesized arrow function here.
// False -> There *cannot* be a parenthesized arrow function here.
// Unknown -> There *might* be a parenthesized arrow function here.
// Speculatively look ahead to be sure, and rollback if not.
function isParenthesizedArrowFunctionExpression(): Tristate {
if (
token() === SyntaxKind.OpenParenToken ||
token() === SyntaxKind.LessThanToken ||
token() === SyntaxKind.AsyncKeyword
) {
return lookAhead(isParenthesizedArrowFunctionExpressionWorker);
}

if (token() === SyntaxKind.EqualsGreaterThanToken) {
// ERROR RECOVERY TWEAK:
// If we see a standalone => try to parse it as an arrow function expression as that's
// likely what the user intended to write.
return Tristate.True;
}
// Definitely not a parenthesized arrow function.
return Tristate.False;
}

总之,TypeScript解析器结合了先行查找(快速路径)和回溯来解析箭头函数。