typescript - Prečo musí mať anotácia typu pre premennú v bloku Catch byť any?


Používam yup na overovanie formulára a narazil som na túto typovú chybu, keď som sa snažil, aby tento catch fungoval:

Typová anotácia premennej v bloku catch musí byť any alebo unknown, ak je špecifikovaná 1196

Môj kód:

const handleSubmit = async (): Promise<void> => {
    try {
      const isValid = await userSchema.validate(values, { abortEarly: false });
      console.log(isValid);
    } catch (err: ValidationError) {
      console.log(err);
      const errors = getValidationErrors(err);
    }

funkcia getValidationErrors:

export function getValidationErrors(err: yup.ValidationError): Errors {
  console.error(err);
  const validationErrors: Errors = {};
  err.inner.forEach((error) => {
    if (error.path) validationErrors[error.path] = error.message;
  });
  return validationErrors;
}

Pri hľadaní informácií o tom som zistil, že TypeScript neprijíma typy pre argumenty v klauzule catch... Prečo je to tak? Toto je predsa tak bežné v Jave alebo iných jazykoch... Myslím tým... moje riešenie tu je atribút err: any... Ale nie je typ any niečo, čo sa nesmie nikdy používať?

Odpoveď č. 1

Typescript vám to nedovolí, pretože neexistuje spôsob, ako by Typescript mohol pri kompilácii overiť, že jediná vec, ktorú kód môže vyhodiť, je ValidationError. V skutočnosti ani vy sami to neviete: čo ak dostanete RangeError, pretože bol prekročený maximálny zásobník volaní? Samozrejme, že je to nepravdepodobné (museli by ste si vytvoriť veľký zásobník volaní pred tým, než to zavoláte), ale nič na tomto kóde nemôže zaručiť, že sa to nestane.

Ak chcete, aby mala chyba určitý typ, budete musieť buď pridať kód na overenie, že to naozaj je ten typ:

catch (err: unknown) {
  if (err instanceof ValidationError) {
     // Inside this block, err is known to be a ValidationError
  }
}

Alebo budete musieť použiť typové tvrdenia, aby ste TypeScriptu povedali: „Viem, že je to tento typ, dôveruj mi“:

catch (err: unknown) {
  getValidationErrors(err as ValidationError);
}
// or:
catch (err: unknown) {
  const knownError = err as ValidationError;
  getValidationERrors(knownError);
}

To je tak bežné v Jave alebo iných jazykoch...

Rôzne jazyky majú odlišné obmedzenia vo svojom návrhu. Napríklad v jave môžete definovať, aké chyby bude vaša funkcia vyhadzovať ako súčasť definície funkcie, ako je

public static FileInputStream example(String fileName) throws FileNotFoundException {

Ani JavaScript, ani TypeScript nemajú spôsob, ako to špecifikovať v definícii funkcie.

A Java vám umožňuje mať niekoľko blokov catch, pričom rôzne typy chýb sú spracované rôznymi blokmi, ale keďže TypeScript existuje iba počas kompilácie, to nie je možnosť. Všetko musí byť spracované v jednom bloku catch a rozlíšenie, s akým typom chyby máte do činenia, musí byť vykonané explicitným kódom.

Odpoveď č. 2

Nemôžete napísať špecifickú anotáciu pre premennú v klauzule catch v TypeScripte, pretože v JavaScripte klauzula catch zachytí akúkoľvek výnimku, ktorá je vyvolaná, nielen výnimky určitého typu.

Java vám umožňuje (vlastne, vyžaduje od vás) napísať typ výnimky, pretože počas kompilácie je schopná skontrolovať (pre typy kontrolovaných výnimiek), či môže byť táto výnimka vyvolaná, ale čo je dôležitejšie, počas behu programu skontroluje, aký typ výnimky bol vyvolaný, a zachytí ho (vykoná blok catch) iba vtedy, ak typ výnimky zodpovedá klauzule catch.

V Typescript, ak chcete zachytiť iba konkrétny typ výnimky, musíte zachytiť čokoľvek, čo je vyhodené, skontrolovať, či je to typ výnimky, ktorý chcete spracovať, a ak nie, znova ho vyhodiť:

try {
    // code that could throw ValidationError
} catch(e: unknown) {
    if(!(e instanceof ValidationError)) { throw e; }
    // code to handle ValidationError
}

V tomto prípade, po príkaze if, bude typ e zúžený na ValidationError a môžete pristupovať k e.message.

Odpoveď č. 3

Ako už iní poznamenali, TS vám nedovolí používať v bloku catch iné typy než „any“ alebo „unknown“.

Môžete však premennú chyby pretypovať na konkrétny typ pomocou myVariable.

try {
  // where some ValidationError object could be thrown
} catch (err: unknown) {
   const errors = getValidationErrors(<ValidationError>err);
}

Súvisiace články