Website-Suche

typescript - Kann nicht auf eine Eigenschaft einer Variable mit mehreren Typen zugreifen


Ich habe einen Typ erstellt, der ein anderer Typ oder ein Interface sein kann, sodass ich ihn in einer Funktion verwenden kann.

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

Nun, wenn ich möchte, dass eine Funktion einen Parameter vom Typ IGlobalUser erhält, würde ich erwarten, dass ich auf die Eigenschaften des Interfaces IUser zugreifen kann. So:

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

TypeScript sagt jedoch:

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

Ich möchte, dass die Funktion sowohl Value als auch IUser akzeptieren kann und sie verwenden kann. Irgendwelche Ideen, wie man das erreichen kann?

Antwort #1

Sie können das mit benutzerdefinierten Typwächtern machen

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';
}

Die Funktion isUser erhält einen Typ von IGlobalUser und bestimmt, ob es sich um ein IUser handelt. Dies ermöglicht Ihnen, zur Laufzeit zu prüfen, um welche Art von Typ es sich handelt.

Dies wird in reguläres JavaScript übersetzt, aber TypeScript weiß, dass diese Funktion den Typ bestimmt. Wenn Sie die benutzerdefinierte Guard-Funktion verwenden, wird TypeScript wissen, um welchen Typ es sich handelt

In VS Code:

  • Der erste Typ ist IGlobalUser, wie erwartet

  • Der zweite Typ ist IUser, wie erwartet

Wenn sie zu JavaScript kompiliert wird, werden die isUser-Funktion und die if-Anweisung natürlich vorhanden sein. Aber Sie möchten wahrscheinlich sowieso eine solche Prüfung irgendwo in Ihrem Code haben. Wenn Sie sie mit einem Type Guard schreiben, wird die erforderliche Prüfung zur Laufzeit durchgeführt, aber TypeScript wird auch auf die beiden verschiedenen Szenarien aufmerksam gemacht und gibt Ihnen entsprechend Feedback.

Antwort #2

Die Funktion akzeptiert sowohl Value als auch IUser. TypeScript warnt Sie, dass Sie nicht wissen können, ob der Typ von user string, number oder IUser ist, und in den ersten beiden Fällen hat user nicht die Eigenschaft name.

Verwenden Sie einen typeof-Typwächter, um die Fälle zu unterscheiden, und der Compiler wird sich nicht mehr beschweren:

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);

Überprüfe es online.