Reputation: 439
I treat type assertion
as something like Hi Compiler, I know the type of this variable better than you. Just follow me!
.
But it seems that the compiler still has its own logic to infer the type. For example, suppose,
interface PM_MGEInfo {
category: string;
bid: string;
cid?: string;
labs?: { [key: string]: any };
}
Then, 1&2 are no problem, but 3 throws a TS2352 error.
function makeMgeInfo(bid: string): PM_MGEInfo {
return <PM_MGEInfo>{
bid
};
}
function makeMgeInfo(bid: string): PM_MGEInfo {
return <PM_MGEInfo>{
bid,
labs: {}
};
}
function makeMgeInfo(bid: string): PM_MGEInfo {
return <PM_MGEInfo>{
bid,
// error TS2352: Type '{ labs: { poi_id: string; }; bid: string; }' cannot be converted to type 'PM_MGEInfo'.
// Property 'category' is missing in type '{ labs: { poi_id: string; }; bid: string; }'.
labs: {a: 1}
};
}
Why does type assertion
begin to check other fields in 3? Does someone know its detail logic?
Updated: I created an issue in Github Microsoft/TypeScript#23698.
Upvotes: 5
Views: 183
Reputation: 439
Check the spec 4.16 Type Assertions, which is inspired by this answer:
In a type assertion expression of the form < T > e, e is contextually typed (section 4.23) by T and the resulting type of e is required to be assignable to T, or T is required to be assignable to the widened form of the resulting type of e, or otherwise a compile-time error occurs.
For case 1, T
is assignable to e
obviously.
For case 2, the widened form of e
is {bid: string, labs: Object}
, which T is assignable to. Notice that labs?
is assignable to Object
(In fact, I am not sure about it, but this is my only possible explanation).
For case 3, neither of above conditions is satisfied.
Upvotes: 1
Reputation: 3454
I think that the compiler doesn't recognize your value {a: 1}
as type { [key: string]: any }
because if you alter the line like this there is no compiler error:
function makeMgeInfo(bid: string): PM_MGEInfo {
return <PM_MGEInfo>{
bid,
labs: {a: 1} as {[key: string]: any}
};
}
also it is working if you define the variable like this:
mylabs: {[key: string]: any} = {a: 1};
and call it in your function:
makeMgeInfo(bid: string): PM_MGEInfo {
return <PM_MGEInfo>{
bid,
labs: this.mylabs
};
}
Therefore I would say, that the compiler does not recognize your defined type from the labs field. The error message in this case is very misleading.
Upvotes: 0
Reputation: 11202
I see two options. Either use Partial<T>
or any
. When using any, YOU are responsible for making sure things will work, so use as last option.
Examples of both:
function makeMgeInfoWithPartial(bid: string): Partial<PM_MGEInfo> {
// props are optional but only those defined by PM_MGEInfo are valid
return {
bid,
labs: {a: 1}
}
}
function makeMgeInfoWithAny(bid: string): PM_MGEInfo {
return {
bid,
labs: {a: 1},
whatever: 'also works'
} as any
}
Upvotes: 0