typescript - Ako môžem spraviť generický typ voliteľným?


Mám nasledujúcu metódu zaznamenávania:

private logData<T, S>(operation: string, responseData: T, requestData?: S) {
    this.logger.log(operation + ' ' + this.url);
    if (requestData) {
        this.logger.log('SENT');
        this.logger.log(requestData);
    }
    this.logger.log('RECEIVED');
    this.logger.log(responseData);
    return responseData;
}

requestData je voliteľné. Chcem byť schopný volať logData bez toho, aby som musel špecifikovať typ S, keď neposielam requestData do metódy: namiesto this.logData<T, any>('GET', data) chcem volať this.logData<T>('GET', data).

Existuje spôsob, ako to dosiahnuť?

Odpoveď č. 1

Od verzie TypeScript 2.3 môžete používať predvolené hodnoty generických parametrov.

private logData<T, S = {}>(operation: string, responseData: T, requestData?: S) {
  // your implementation here
}

Odpoveď č. 2

TS Update 2020: Zadaním void sa generický typ stane voliteľným.

type SomeType<T = void> = OtherType<T>;

Odpoveď vyššie, kde je ako objekt uvedená predvolená hodnota, ju robí voliteľnou, ale stále jej dáva hodnotu.


Príklad s predvolenou hodnotou typu je {}:

type BaseFunctionType<T1, T2> = (a:T1, b:T2) => void;

type FunctionType<T = {}> = BaseFunctionType<{name: string}, T>

const someFunction:FunctionType = (a) => {

}

someFunction({ name: "Siraj" });
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
// Expected 2 arguments, but got 1.(2554)

Odkaz na ihrisko


Príklad s predvolenou hodnotou generického typu je void

type BaseFunctionType<T1, T2> = (a:T1, b:T2) => void;

type FunctionType<T = void> = BaseFunctionType<{name: string}, T>

const someFunction:FunctionType = (a) => {

}

someFunction({ name: "Siraj" })

Toto je dobré čítanie o tom, ako spraviť generiká voliteľnými.

Voliteľný generický typ v Typescripte

Odkaz na ihrisko

Odpoveď č. 3

Podľa TypeScript 2.2 (môžete to vyskúšať v TS Playground) sa volanie this.logData("GET", data) (s data typu T) úspešne odvodí ako this.logData<T, {}>("GET", data).

Preťaženie navrhnuté Davidom Bohunekom sa môže použiť, ak odvodzovanie zlyhá s verziou TS, ktorú používate. Každopádne, uistite sa, že druhý podpis je najprv deklarovaný a potom definovaný, inak by sa nezapojil do dostupných preťažení.

// Declarations
private logData<T>(operation: string, responseData: T);
private logData<T, S>(operation: string, responseData: T, requestData?: S);
// Definition
private logData<T, S>(operation: string, responseData: T, requestData?: S) {
    // Body
}

Odpoveď č. 4

Ak hľadáte voliteľný generický typ v deklarácii typu/rozhrania, toto vám môže pomôcť.

(prišiel som hľadať toto, našiel som iba odpovede týkajúce sa všeobecných deklarácií funkcií. Sirajova odpoveď ma nasmerovala správnym smerom.)

type ResponseWithMessage = {
  message: string;
};

interface ResponseWithData<T> extends ResponseWithMessage {
  data: T;
}

export type ResponseObject<T = void> = T extends void
  ? ResponseWithMessage
  : ResponseWithData<T>;

Súvisiace články