generics - Typescript jakékoliv číslo kromě X
Shrnutí:
Je tento typ nějak možný v TS? Exclude<number, 200 | 400> ("jakékoliv číslo kromě 200 nebo 400")
Mám následující případ použití. Mám typ odpovědi, který je generický:
type HttpResponse<Body = any, StatusCode = number> = {
body: Body
statusCode: StatusCode
}
A rád bych použil stavový kód jako rozlišovací znak:
// Succes
type SuccessResponse = HttpResponse<SomeType, 200>
// Known error
type ClientErrorResponse = HttpResponse<ClientError, 400>
// Anything else, generic error, issue is with the status code here.
type OtherErrorResponse = HttpResponse<GenericError, Exclude<number, 200 | 400>>
// The response type is a union of the above
type MyResponse = SuccessResponse | ClientErrorResponse | OtherErrorResponse
Když používám typ MyResponse, rád bych použil stavový kód jako rozlišovač, např.:
const response: MyResponse = ...
if(response.statusCode === 200) {
// response is inferred as SuccessResponse => body is inferred as SomeType
} else if(response.statusCode === 400) {
// response is inferred as ClientErrorResponse => body is inferred as ClientError
} else {
// response is inferred as OtherErrorResponse => body is inferred as GenericError
}
Nicméně to takto nefunguje, protože Exclude<number, 200 | 400> je totéž jako prosté number. Jak to vyřešit? Je typ "jakékoliv číslo kromě 200 nebo 400" vůbec možný v TypeScriptu? Existují nějaké jiné kreativní řešení?
Odpověď č. 1
V tuto chvíli to není možné.
Viz: https://github.com/microsoft/TypeScript/issues/15480
Exclude<number, 200 | 400> nefunguje, protože TypeScript sleduje pouze to, čím něco je, a nikdy nesleduje to, čím není. Aby vyloučení některých hodnot z nekonečné řady fungovalo, musel by TypeScript vygenerovat unii se všemi možnými hodnotami kromě těch, které chcete vyloučit. To by byla unie nekonečné délky (protože nekonečno minus 2 se rovná nekonečnu)
To se řeklo, seznam HTTP stavových kódů je vlastně konečný. Takže nejlepší způsob je pravděpodobně vytvořit sjednocení všech možných hodnot a použít ho:
type HTTPStatusCode = 100 | 101 | 102 | 103 | 200 | 201 | 202 | ...
Teď by to mělo fungovat dobře:
Exclude<HTTPStatusCode, 200 | 400>
