首页 > 解决方案 > 有没有办法强制一个类包含一个特定的枚举值(最好是内联的)?

问题描述

我目前正在使用 TypeScript 中的编译器,并且我有一个 Enum 来表示令牌类型和一个用于实际令牌的类:

enum TokenType {
    String,
    Integer,
    Float,
    Identifier,
    // ... elided
}

class Token {
    type: TokenType
    lexeme: string
    lineNo: number
    columnNo: number

    constructor(
        type: TokenType,
        lexeme: string,
        lineNo: number,
        columnNo: number
    ) {
        this.type = type
        this.lexeme = lexeme
        this.lineNo = lineNo
        this.columnNo = columnNo
    }

    toString(): string {
        return (
            'Token{' +
            [this.type, this.lexeme, this.lineNo, this.columnNo].join(',') +
            '}'
        )
    }
}

在我的 AST 节点类型中,我想指定 Token 持有特定类型,例如在FunctionDeclaration类型中:

type FunctionDeclaration = {
    ident: Token with type = TokenType.identifier
    //           ^ Imaginary syntax, but this is what I'm trying to do
}

我试过使用extend像:

interface IdentifierToken extends Token {
    type: TokenType.Identifier
}

但是,即使令牌的类型new Token(TokenType.Identifier, ...)是.IdentifierTokenTokenType.Identifier

此外,我宁愿不必为所有不同的 TokenTypes 声明新的单独类型(因为有 ~25 个)。那么,强制类属性值的内联方式是否可行?

标签: typescriptcompiler-construction

解决方案


您可能需要考虑使用与您正在使用的特定子类型相对应的类型参数创建Token一个泛型类:TokenType

class Token<T extends TokenType = TokenType> {
    type: T
    lexeme: string
    lineNo: number
    columnNo: number

    constructor(
        type: T,
        lexeme: string,
        lineNo: number,
        columnNo: number
    ) {
        this.type = type
        this.lexeme = lexeme
        this.lineNo = lineNo
        this.columnNo = columnNo
    }
}

然后你可以很容易地引用“ Tokenatype等于XXXas Token<XXX>

type FunctionDeclaration = {
    ident: Token<TokenType.Identifier>
}

此外,当您使用Token构造函数时,编译器将T根据构造参数进行推断:

const identifierToken = new Token(TokenType.Identifier, "", 1, 2);
// const identifierToken: Token<TokenType.Identifier>

const f: FunctionDeclaration = { ident: identifierToken }; // okay

const floatToken = new Token(TokenType.Float, "", 3, 4);
// const floatToken: Token<TokenType.Float>

const g: FunctionDeclaration = { ident: floatToken }; // error!
// Type 'Token<TokenType.Float>' is not assignable to type 'Token<TokenType.Identifier>'.

Playground 代码链接


推荐阅读