So these are my types:
export type typeOne = {
A: string;
B: string;
};
export type typeTwo = {
A: string;
C: string;
};
export type Result = typeOne | typeTwo; //condition
And this is the use case:
for (const item: Result of list) {
const something = item.B ? 'B exsist' : item.C;
return something;
}
It keeps returning error:
TS2339: Property 'B' does not exist on type 'Result'. Property 'B' does not exist on type 'typeTwo'.
and also for the other one:
TS2339: Property 'C' does not exist on type 'Result'. Property 'C' does not exist on type 'typeOne'.
Do you have any idea how can I fix this?
Note: The following error is also happening for the loop:
TS2483: The left-hand side of a 'for...of' statement cannot use a type annotation.
So these are my types:
export type typeOne = {
A: string;
B: string;
};
export type typeTwo = {
A: string;
C: string;
};
export type Result = typeOne | typeTwo; //condition
And this is the use case:
for (const item: Result of list) {
const something = item.B ? 'B exsist' : item.C;
return something;
}
It keeps returning error:
TS2339: Property 'B' does not exist on type 'Result'. Property 'B' does not exist on type 'typeTwo'.
and also for the other one:
TS2339: Property 'C' does not exist on type 'Result'. Property 'C' does not exist on type 'typeOne'.
Do you have any idea how can I fix this?
Note: The following error is also happening for the loop:
Share Improve this question asked Oct 8, 2020 at 20:18 AfsanefdaAfsanefda 3,3398 gold badges42 silver badges80 bronze badgesTS2483: The left-hand side of a 'for...of' statement cannot use a type annotation.
3 Answers
Reset to default 5You can use an in
type guard to discriminate a union of object types with unequal keys:
for (const item: Result of list) {
const something = "B" in item ? 'B exsist' : item.C;
return something;
}
Playground link
One of the nuances of TypeScript is that if you have a union type of objects, you can only access the fields that are mon between them. It is mon to use this technique to add a mon field that can tell the two apart. For instance:
export type typeOne = {
type: 'one';
A: string;
B: string;
};
export type typeTwo = {
type: 'two'
A: string;
C: string;
};
export type Result = typeOne | typeTwo; //condition
for (const item: Result of list) {
const something = item.type === 'one' ? 'B exists' : item.C;
return something;
}
In this case, type
acts as a discriminator. Read more here: https://basarat.gitbook.io/typescript/type-system/discriminated-unions
Alternatively, you can create a custom type guard to differentiate between the two types. This involves a function that takes your union type and evaluates at runtime if the value is of a particular type. You can use a type assertion to access a non-shared field in the union:
function isTypeOne(result: Result): result is typeOne {
return (result as typeOne).B !== undefined;
}
for (const item: Result of list) {
const something = isTypeOne(item) ? 'B exists' : item.C;
return something;
}
Here, if isTypeOne
fails, typeOne
can be safely eliminated from Result
, thus the type is inferred as typeTwo
.
Regarding the last error you mentioned:
"TS2483: The left-hand side of a 'for...of' statement cannot use a type annotation."
The Result
type definition should be part of your declaration of list
. That way, there is no need to specify that the left-hand side of the statement is a Result
.
For example, assuming list
is an array:
const list: Array<Result> = [{A: 'foo', B: 'bar'}, {A: 'foo', C: 'baz'}]
for (const item of list) {
// Run code from other answers here
}