Reputation: 387
Here is my code, i know that is a bit long but not hard to understand. It showing error in the last line and also losing intellisense there. "Property 'test' does not exist on type 'Test | Test2'." As you can see clearly the 'test' property is obviously within the 'Test' class. So what's wrong?
class Test{
test: string = 'test';
}
class Test2{
test2: string = 'test2';
}
function isTest(obj: Test|Test2): obj is Test{
if(obj instanceof Test)
return true;
else
return false;
}
function test(obj: Test|Test2): Test|Test2{
if(isTest(obj))
return obj as Test;
else
return obj as Test2;
}
let varTest: Test = new Test();
console.log(test(varTest).test); //this line is broken
Upvotes: 2
Views: 81
Reputation: 5456
The return type of test()
is static in the sense that it's return value will always be Test | Test2
, regardless of how it's called. This means that varTest
can be Test
OR Test2
(which does not contain a test
property), so the error is correctly letting you know that the property you are trying to access may not exist.
If we need a dynamic return type, we need to turn to generics, overloads, or conditional types, depending on the problem. In your case, we can use function overloads.
Function overloads allow you to specify return types that are conditional on the input types. To make your test()
function work as expected, we overload it with two conditions: one for Test
and another for Test2
:
function test(obj: Test): Test; // given Test, return Test
function test(obj: Test2): Test2; // given Test2, return Test2
function test(obj: Test | Test2): Test | Test2{
if(isTest(obj))
return obj as Test;
else
return obj as Test2;
}
let varTest: Test = new Test();
console.log(test(varTest).test); // OK
let varTest2: Test2 = new Test2();
console.log(test(varTest2).test); // Error! 'test' does not exist in Test2
See playground link.
Upvotes: 1
Reputation: 3800
@Dakito, this typescript Union type is quite tricky.
But if you take a look here: Typescript Union Types you can see you will have to add a check to make sure you are safely accessing a field or method from an object without assuming it will not fail.
// this line is broken
let varTest: Test = new Test();
let testResult: Test | Test2 = test(varTest);
// Adding these checks here will help you safely access the correct values.
// You can also improve this code by using User-Defined Type Guards
if(<Test>testResult.test) {
console.log((<Test>testResult).test);
} else if(<Test2>testResult.test2) {
console.log((<Test2>testResult).test2);
}
Upvotes: 0