AdaLollA
AdaLollA

Reputation: 371

Typescript: reference to interface in variable

While implementing the client side of a server communication I happen to meet the following problem: How can I store a reference to an interface in a variable.

I have an interface that hold all the information about a specific RESTfull backend call:

export interface IEndpoint {
  path: string,
  method: HTTP_METHOD,
  data: any,
  response: any
}

Create instance of this element (ISomeInterface and IAnotherInterface are the interfaces that I want to refer to later):

export const GET_TEST: IEndpoint = {
  path: 'api/test',
  method: HTTP_METHOD.GET,
  data: <ISomeInterface>{},
  response: <IAnotherInterface>{}
};

The goal is to use the data and response field as type references in a Promise (meta is an instance of IEndpoint):

new Promise<meta.response>((resolve) => {
  ...
});

The callback type of the Promise (meta.response) is where I am not able to extract the type/interface that I previously assigned.

Upvotes: 3

Views: 6191

Answers (3)

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 249586

Values and types exist in two different domains. Types are erased at compile time so we can't assign a type to an interface field as you try to do.

What we can do is work in the type domain and keep the data and response types in the IEndpoint type using generic parameters, and extract them when needed.

export interface IEndpoint<TData, TResponse> {
    path: string,
    method: HTTP_METHOD,
    // just here because typescript doesn't handle unused generics well
    _data?: TData,
    _response?: TResponse
}

function makeRequest<T extends IEndpoint<any, any>>(endPoint: T, data: T['_data']): Promise<T['_response']> {
    return null as any// actual call
}

interface ISomeInterface { data: string }
interface IAnotherInterface { result: string }
export const GET_TEST: IEndpoint<ISomeInterface, IAnotherInterface> = {
    path: 'api/test',
    method: "GET"
};
// Takes in ISomeInterface returns Promise<IAnotherInterface> 
makeRequest(GET_TEST, { data: ""}).then(r=> r.result);

As @jeroen-vervaeke points out makeRequest could also be typed in a simpler way with the same effect:

function makeRequest2<TData, TResponse>(endPoint: IEndpoint<TData, TResponse>, data: TData): Promise<TResponse>{
    return null as any;
}

Upvotes: 3

Tomas
Tomas

Reputation: 3436

You refer to meta part in:

new Promise<meta.response>((resolve) => {
  ...
});

As it would represent a type, while it represent's a value. You can workaround it by using typeof:

new Promise<typeof (meta.response)>((resolve) => {
  ...
});

Or via direct reference to response type:

new Promise<IAnotherInterface>(resolve => {
  ...
});

Beside that, TS team strongly suggest to use as as casting operator, not <>:

export const GET_TEST: IEndpoint = {
  path: 'api/test',
  method: HTTP_METHOD.GET,
  data: {} as,ISomeInterface
  response: {} as IAnotherInterface
};

Upvotes: -1

user4676340
user4676340

Reputation:

You could work around your issue with a generic class and bind the method to this class :

export class Endpoint<T, U> {
  constructor(
    private path: string,
    private method: HTTP_METHOD,
    private data: T,
    private response: U
  ) {}

  // your new promise method there
}

Upvotes: 0

Related Questions