I have the 2 following interfaces
interface IComment extends IData {
comment: string;
}
interface IHistory extends IData{
differences: any[];
timeStamp: number;
}
both of them extend
interface IData {
user: string;
date: Moment | string;
isHistory: boolean;
}
now to the problem
I have an Array with elements of IComment and IHistory.
const data: Array<IHistory | IComment> = [...someHistoryArray, ...someCommentArray]
now when I want to map over the array and I want to access the timeStamp
data.map((entry: IHistory | IComment) => {
if(entry.isHistory) {
entry.timeStamp
// TS2339: Property 'timeStamp' does not exist on type 'IHistory | IComment'. Property 'differences' does not exist on type 'IComment'.
} else {
entry.comment
// TS2339: Property 'comment' does not exist on type 'IHistory | IComment'. Property 'comment' does not exist on type 'IHistory'.
}
})
well I found 2 solutions that aren´t satisfing enough for me...
I could write at every position
(entry as IHistory).timeStamp
I could define for example
const historyEntry: IHistory = entry as IHistory;
Are there any other possible solutions?
You can use isHistory
as a discriminant for the union if you add specific definitions in each interface:
interface IComment extends IData {
comment: string;
isHistory: false;
}
interface IHistory extends IData {
differences: any[];
timeStamp: number;
isHistory: true;
}
interface IData {
user: string;
date: string;
isHistory: boolean;
}
let data: Array<IComment | IHistory>=[]
data.map((entry: IHistory | IComment) => {
if(entry.isHistory === true) {
entry.timeStamp //ok
} else {
entry.comment //ok
}
})
Another possibility would be to use a User-Defined Type Guard, ie a function that helps the compiler to derive whether a parameter has a certain type. The following code should solve your specific issue - i added comments to the changed bits.
interface IComment extends IData {
comment: string;
}
interface IHistory extends IData {
differences: any[];
timeStamp: number;
}
interface IData {
user: string;
date: Moment | string;
isHistory: boolean;
}
const data: Array<IHistory | IComment> = [];
data.map((entry: IHistory | IComment) => {
// Explicitely narrows down the type to IHistory within the block
if (isHistory(entry)) {
// entry.timeStamp
} else {
// entry.comment
}
});
// User-Defined Type Guard
function isHistory(data: IData): data is IHistory {
return data.isHistory;
}
See Advanced Types at User-Defined Type Guards for more info.
You can use "in" for this case.
if('timeStamp' in entry) {
entry.timeStamp
} else {
entry.comment
}
Documentation: https://www.typescriptlang.org/docs/handbook/advanced-types.html#type-guards-and-differentiating-types
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.