Nicola Piccoli
Nicola Piccoli

Reputation: 135

Typescript: property based on another property

I have a situation of nested types and what I would like to achieve is to have a specified property based on another property's value.

In the HTML I cycle the response of an API and, based on the type value received, I would like to have a different option value.

For example: if I receive a response where type is 'articles' I would like to have OptionArticles as ChatOptions.

Is there a solution for this?

This is the code:

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;
}

Thanks.

Upvotes: 3

Views: 3209

Answers (2)

vroomfondel
vroomfondel

Reputation: 3106

You can use conditional types to enforce that the type in chatPayload is the same as the type in chatPayload.options.

ChatPayload can take as a type parameter the "type" from the API:

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

And you can switch the type depending on the value of the field in the API response:

// 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")
}

The casting is a little ugly, but you will have to use a cast in order to get an untyped API response into one of your own types.

For further safety, you can use a JSON validator to make sure that the response you're getting from the API conforms to what you expect.

Typescript playground

Upvotes: 2

Tanmay_vijay
Tanmay_vijay

Reputation: 619

Maybe you can use a setter for a field in your class. This method will be called everytime a value is set for this field.

In the setter you can change the value of other field as well.

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

Note: You may have to class instead of interface for the ChatPayload

Upvotes: 0

Related Questions