typescript 使用泛型类的属性来告知类的泛型类型

mpbci0fu  于 2023-05-01  发布在  TypeScript
关注(0)|答案(3)|浏览(80)

我的TypeScript代码看起来像这样:

type TokenType =
    | "A"
    | "B"
    | "C";

class Token<TType extends TokenType> {
    constructor(public readonly type: TType) {}
}

function testing(token: Token<TokenType>) {
    switch (token.type) {
        case "A":
            token;
            // ^? (parameter) token: Token<TokenType>
            handleTypeA(token); // errors
            break;
    }
}

function handleTypeA(token: Token<"A">) {
  // do stuff with the token here...
}

我想使用这个switch语句来缩小token的类型,因为我知道它实际上是Token<"A">。有什么方法可以做到吗?特别是,不使用as或某种 predicate 函数?在我的实际用例中,我有一个非常长的TokenType,有很多选项,所以我宁愿使用switch语句,而不是一大堆if ... else if ... else语句。

m4pnthwp

m4pnthwp1#

当您为所有可能的令牌类型创建一个令牌类型的并集类型时:

type TokenType =
    | "A"
    | "B"
    | "C";

class Token<TType extends TokenType> {
    constructor(public readonly type: TType) {}
}

type TokenX = Token<"A"> | Token<"B"> | Token<"C">; // <-- HERE

那么你的测试函数将如你所期望的那样工作:

function testing(token: TokenX) {
    switch (token.type) {
        case "A":
            token;
            // ^? (parameter) token: Token<"A">
            handleTypeA(token); // NO ERROR NOW
            break;
    }
}
hlswsv35

hlswsv352#

您可以使用自索引mapped typeTokenType联合分发到Token联合(以下示例中为SomeToken):

type TokenType =
    | "A"
    | "B"
    | "C";

class Token<TType extends TokenType> {
    constructor(public readonly type: TType) {}
}

type SomeToken = {
    [TType in TokenType]: Token<TType>
}[TokenType];

function handleTypeA(token: Token<"A">) {}

function testing(token: SomeToken) {
    switch (token.type) {
        case "A":
            token;
            handleTypeA(token); // OK
            break;
    }
}
mutmk8jj

mutmk8jj3#

是的,您可以使用switch语句来缩小令牌的类型,但是您需要使用类型保护。类型保护是返回布尔值的函数,该值指示值是否为特定类型。它们允许您基于运行时检查来细化值的类型。
在您的示例中,您可以为您想要处理的每个令牌类型定义一个类型保护函数,如下所示:

function isTypeA(token: Token<TokenType>): token is Token<"A"> {
    return token.type === "A";
}

function isTypeB(token: Token<TokenType>): token is Token<"B"> {
    return token.type === "B";
}

function isTypeC(token: Token<TokenType>): token is Token<"C"> {
    return token.type === "C";
}

然后,你可以像这样在switch语句中使用这些类型保护:

function testing(token: Token<TokenType>) {
    switch (token.type) {
        case "A":
            if (isTypeA(token)) {
                handleTypeA(token);
            }
            break;
        case "B":
            if (isTypeB(token)) {
                handleTypeB(token);
            }
            break;
        case "C":
            if (isTypeC(token)) {
                handleTypeC(token);
            }
            break;
    }
}

function handleTypeA(token: Token<"A">) {
    // do stuff with the token here...
}

function handleTypeB(token: Token<"B">) {
    // do stuff with the token here...
}

function handleTypeC(token: Token<"C">) {
    // do stuff with the token here...
}

请注意,isTypeX函数是在调用相应的handleTypeX函数之前调用的。这是必要的,因为TypeScript无法自动推断类型细化,并且您需要在调用期望它的函数之前手动检查令牌是否为预期类型。
这样,您就可以避免使用as或 predicate 函数,仍然使用switch语句来处理令牌类型。
Happy coding:)

相关问题