Our types

enum TokenType { VariableDeclaration = 'VariableDeclaration', AssignmentOperator = 'AssignmentOperator', Literal = 'Literal', String = 'String', LineBreak = 'LineBreak', Log = 'Log' } interface TokenNode<T extends TokenType> { type: T } interface TokenValueNode<T extends TokenType> extends TokenNode<T> { value: string } type Token = TokenNode<TokenType.AssignmentOperator> | TokenNode<TokenType.VariableDeclaration> | TokenNode<TokenType.LineBreak> | TokenNode<TokenType.ConsoleLog> | TokenValueNode<TokenType.Literal> | TokenValueNode<TokenType.String>

Phew, some actual code.

Take a minute to read over this, and we'll step through it to explain what it's doing, and why we're doing it.