打字稿:属性 基于另一个 属性

Typescript: property based on another property

我遇到了嵌套类型的情况,我想实现的是根据另一个 属性 的值指定一个 属性。

在 HTML 中,我循环 API 的响应,并且根据收到的类型值,我想要一个不同的选项值。

例如:如果我收到类型为 'articles' 的响应,我希望将 OptionArticles 作为 ChatOptions。

有解决办法吗?

这是代码:

export interface ChatMessage {
    status: string;
    query: string;
    step: string;
    richResponse: boolean;
    payload: ChatPayload;
    sessionId?: number;
}

interface ChatPayload {
    type: ChatTypes;
    options: ChatOptions;
    confidence?: number;
    gotAllParams?: boolean;
}

type ChatTypes = 'text' | 'date' | 'articles' | 'params';

type ChatOptions = OptionText | OptionArticles | OptionParams;

interface OptionText {
    type: 'text' | 'date';
    text: string[];
}

interface OptionArticles {
    type: 'articles';
    prefilled: Values[];
    possible: Values[];
}

interface OptionParams {
    type: 'params';
    params: FineParams;
}

谢谢。

或许您可以在 class 中使用 setter 作为字段。每次为此字段设置值时都会调用此方法。

在 setter 中您也可以更改其他字段的值。

https://www.geeksforgeeks.org/typescript-accessor/

注意:您可能需要 class 而不是 ChatPayload 的接口

您可以使用 conditional types 强制 chatPayload 中的类型与 chatPayload.options 中的类型相同。

ChatPayload 可以将 "type" 来自 API:

作为类型参数
interface ChatPayload<Type extends ChatTypes> {
    type: Type;
    options: Type extends "articles" ? OptionArticles : Type extends "params" ? OptionParams : OptionText ;
    confidence?: number;
    gotAllParams?: boolean;
}

并且您可以根据 API 响应中字段的值切换类型:

// the response you get from the API; you don't know the type yet
const apiResponse: any = {}

if (apiResponse.type === "text" || apiResponse.type === "date") {
    doSomething(apiResponse as ChatPayload<"text" | "date">)
} else if (apiResponse.type === "articles") {
    doSomething(apiResponse as ChatPayload<"articles">)
} else if (apiResponse.type === "params") {
    doSomething(apiResponse as ChatPayload<"params">)
} else {
    throw new Error("unexpected type")
}

转换有点难看,但您必须使用转换才能将未类型化的 API 响应转换为您自己的类型之一。

为了进一步安全,您可以使用 JSON 验证器来确保您从 API 获得的响应符合您的预期。

Typescript playground