typescript - Kan inte komma åt en egenskap hos en variabel med flera typer
Jag har skapat en typ som kan vara av någon annan typ eller någon interface, så att jag kan använda den i en funktion.
type Value = string | number
interface IUser { name: string, id: string }
export type IGlobalUser = Value | IUser;
Nu, när jag vill att en funktion ska få en parameter av typen IGlobalUser, skulle jag förvänta mig att kunna få tillgång till egenskaperna hos gränssnittet IUser. Så här:
foo(user: IrGlobalUser) { alert(user.name) }
Men TypeScript säger:
Property 'name' does not exist on type 'string | number | IUser'.
Property 'name' does not exist on type 'string'.
Jag vill att funktionen ska kunna acceptera både Value och IUser och kunna använda det, har du några idéer om hur man kan uppnå det?
Svar #1
Du kan göra det med hjälp av användardefinierade typvakter
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';
}
Funktionen isUser kommer att få en typ av IGlobalUser och avgör om det är en IUser. Detta gör att du kan kontrollera vid körning vilken typ det är.
Detta översätts till vanlig JavaScript, men TypeScript vet att denna funktion bestämmer typen. När du använder den användardefinierade skyddsfunktionen kommer TypeScript att veta vilken typ det är
I VS Code:
När det kompileras till JavaScript kommer isUser-funktionen och if-satsen uppenbarligen att finnas där. Men du vill förmodligen ha en kontroll som den någonstans i din kod ändå. Att skriva den med en Type Guard kommer att göra den nödvändiga kontrollen vid körning, men kommer också att göra TypeScript medveten om de två olika scenarierna och ge dig återkoppling därefter.
Svar #2
Funktionen accepterar både Value och IUser. TypeScript varnar dig för att du inte kan veta om typen av user är string eller number eller IUser och i de två första fallen har inte user egenskapen name.
Använd en typeof-typvakt för att skilja fallen åt och kompilatorn kommer inte att klaga längre:
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);
Kolla det online.

