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í
voidzpů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>;
