Issue
I have a TypeScript interfaces:
export interface iA {
name: string;
}
export interface iB {
size: number;
}
export interface iX {
id: number;
data: iA | iB;
}
Then in one of my Angular component class I’m using interface iX:
// example.component.ts
class ExampleComplnent {
public item: iX = {
id: 1,
data: { name: 'test' }
}
}
<!-- example.component.html -->
<div>{{ item.data.name }}</div>
This will throw an error: Propery 'name' not exist on type 'iB'
.
I know that in a TypeScript file I can use casting like this:
const name = (item.data as iA).name;
But how can I make casting on the HTML side?
I also want to mention that in my code I’m validating that item.data
is of type iA
, not of type iB
. So I’m sure it have the property ‘name’.
Solution
Unfortunately that’s not possible. It depends on your implementation what the best solution is. You can use generics:
export interface iA {
name: string;
}
export interface iB {
size: number;
}
export interface iX<T extends (iA | iB)> {
id: number;
data: T;
}
export class ExampleComponent {
item: iX<iA>;
}
You can use some method call from the template which asserts the type:
@Component({
selector: 'my-app',
template: '{{ getIaData(item)?.name }}',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
item: iX;
getIaData(ix: iX): iA | undefined {
return this.isIa(ix.data) ? ix.data : void 0;
}
isIa(data: iA | iB): data is iA {
return !!(data as iA).name;
}
}
and I’m sure there are more. But like I said, it depends on where you get the item
from and how and where it is defined
Answered By – Poul Kruijt
Answer Checked By – Clifford M. (BugsFixing Volunteer)