Vyhledávání na webu

typescript - Jak mohu udělat generický typ volitelným?


Mám následující metodu protokolování:

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 volitelný. Chci být schopen volat logData, aniž bych musel specifikovat typ S, když requestData metodě neposílám: místo this.logData<T, any>('GET', data) chci volat this.logData<T>('GET', data).

Existuje způsob, jak toho dosáhnout?

Odpověď č. 1

Od TypeScriptu 2.3 můžete používat výchozí hodnoty generických parametrů.

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

Odpověď č. 2

Aktualizace TS 2020: Zadání void způsobí, že obecný typ bude volitelný.

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

Odpověď výše, kde je jako objekt zadána výchozí hodnota, ji činí volitelnou, ale stále jí přiřazuje hodnotu.


Příklad s výchozí 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 hřiště


Příklad s výchozí obecným typem hodnoty 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é čtení o tom, jak dělat generika nepovinnými.

Volitelný generický typ v Typescriptu

Odkaz na hřiště

Odpověď č. 3

Podle TypeScriptu 2.2 (můžete to vyzkoušet v TS Playground) je volání this.logData("GET", data) (s data typu T) úspěšně odvozeno jako this.logData<T, {}>("GET", data).

Přetížení navržené Davidem Bohunkem lze použít, pokud odvození selže s verzí TS, kterou používáte. Každopádně se ujistěte, že druhý podpis je nejprve deklarován a poté definován, jinak by se nezapojil do dostupných přetíž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
}

Odpověď č. 4

Pokud hledáte volitelný generický typ v rámci deklarace typu/rozhraní, může vám to pomoci.

(přišel jsem to hledat, našel jsem jen odpovědi týkající se obecných deklarací funkcí. Sirajova odpověď mě navedla správným směrem.)

type ResponseWithMessage = {
  message: string;
};

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

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

Související články