typescript - Nemožem pristupovať k vlastnosti premennej s viacerými typmi


Vytvoril som typ, ktorý môže byť nejakého iného typu alebo nejakého rozhrania, aby som ho mohol použiť vo funkcii.

type Value = string | number
interface IUser { name: string, id: string }
export type IGlobalUser = Value | IUser;

Teraz, keď chcem, aby funkcia dostala parameter typu IGlobalUser, očakával by som, že budem môcť pristupovať k vlastnostiam rozhrania IUser. Takto:

foo(user: IrGlobalUser) { alert(user.name) } 

Avšak, TypeScript hovorí:

Property 'name' does not exist on type 'string | number | IUser'.   
Property 'name' does not exist on type 'string'.

Chcem, aby funkcia vedela akceptovať aj Value aj IUser a vedela ich použiť, máte nejaké nápady, ako to dosiahnuť?

Odpoveď č. 1

Môžete to urobiť pomocou používateľom definovaných strážnych typov

type Value = string | number
interface IUser { name: string, id: string }
export type IGlobalUser = Value | IUser;

function isUser(checkObj: IGlobalUser): checkObj is IUser {
  const optionalUser = checkObj as IUser;
  // need to be sufficient to identify your case
  return isObject(optionalUser) &&
    optionalUser.id !== undefined &&
    optionalUser.name !== undefined;
}

function foo(user: IGlobalUser) {

  if (isUser(user)) {
    alert(user.name);
  }
} 

function isObject(obj: any) {
  return obj !== null && typeof obj === 'object';
}

Funkcia isUser získa typ IGlobalUser a určí, či ide o IUser. Toto vám umožní za behu skontrolovať, o aký typ ide.

Toto sa preloží do bežného JavaScriptu, ale TypeScript vie, že táto funkcia určuje typ. Keď použijete užívateľom definovanú strážnu funkciu, TypeScript bude vedieť, o ktorý typ ide

Vo VS Code:

  • prvým typom je IGlobalUser, ako sa očakávalo

  • druhý typ je IUser, ako sa očakávalo

Keď sa skompiluje do JavaScriptu, funkcia isUser a if podmienka tam budú samozrejme prítomné. Ale pravdepodobne budete chcieť niekde vo vašom kóde takúto kontrolu aj tak. Napísanie pomocou Type Guard vykoná potrebnú kontrolu počas behu programu, ale zároveň TypeScriptu umožní rozpoznať dva rôzne scenáre a poskytnúť vám spätnú väzbu zodpovedajúcim spôsobom.

Odpoveď č. 2

Funkcia prijíma ako Value, tak aj IUser. TypeScript vás upozorňuje, že nemôžete vedieť, či typ user je string, number alebo IUser, a v prvých dvoch prípadoch user nemá vlastnosť name.

Použite stráž typu typeof, aby ste odlíšili jednotlivé prípady, a kompilátor už nebude strážiť chyby:

type Value = string | number
interface IUser { name: string, id: string }
type IGlobalUser = Value | IUser;

function foo(user: IGlobalUser) { 
    if (typeof user === 'object') {
        console.log(`IUser: ${user.name}`);
    } else {
        console.log(`string or number: ${user}`);
    }
} 

foo({ name: 'John Doe', id: '42'});
foo('Jane Doe');
foo(43);

Skontrolujte to online.