Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Union with any produces unexpected result #16958

Closed
yeerkkiller1 opened this issue Jul 5, 2017 · 4 comments
Closed

Union with any produces unexpected result #16958

yeerkkiller1 opened this issue Jul 5, 2017 · 4 comments
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug

Comments

@yeerkkiller1
Copy link

TypeScript Version: 2.4.0

Code

declare function test(num: string): void;

let withString: number | string;
// Error: `Type 'number' is not assignable to type 'string'.`, as expected. withString might be a number, which does not have the necessary properties to act as a string.
test(withString);

let withAny: number | any;
// No error
test(withAny);

Expected behavior:
I expected the second case to give an error. withAny might only have the properties of a number.

Actual behavior:
withAny reduces to the type any, and so does not give an error.

@ahejlsberg
Copy link
Member

This is working as intended. Since any is compatible with any type, the type any | number (which means any or number) is effectively the same as just any.

@ahejlsberg ahejlsberg added the Working as Intended The behavior described is the intended behavior; this is not a bug label Jul 6, 2017
@yeerkkiller1
Copy link
Author

Oh, is there same way to recover from the any case? Given a function which has multiple return types, like:

declare function apiCall(): string;
function pickOne() {
    if (Math.random() > 0.5) {
        return 5;
    } else {
        return apiCall();
    }
}
let x = pickOne();

It seems unfortunate to reduce the type to any when apiCall returns any, like in this case:

declare function apiCall(): any;

function pickOne() {
    if (Math.random() > 0.5) {
        return 5;
    } else {
        return apiCall();
    }
}

let x = pickOne();

In this case because some of the return values are typed it appears that accessing any property not inside of number should result in a type error. Even though it is unknown what apiCall returns (it could be anything), we know there are cases when we will only have a number.

@kitsonk
Copy link
Contributor

kitsonk commented Jul 6, 2017

It seems unfortunate to reduce the type to any when apiCall returns any

Do you have another suggestion? any could be a string... it could be anything... the hint is in the name. It isn't a reduction, it is a widening to all types, because the code said it could be any type.

Even though it is unknown what apiCall returns (it could be anything), we know there are cases when we will only have a number.

And, statistically, an equal number of cases where you could have anything. 😖

You can always re-narrow...

declare function apiCall(): any;
declare function stringsOnly(value: string): void;

function pickOne() {
    if (Math.random() > 0.5) {
        return 5;
    } else {
        return apiCall();
    }
}

let x = pickOne();

if (typeof x === 'number') {
  stringsOnly(x); // Argument of type 'number' is not assignable to parameter of type 'string'.
}

TypeScript is trying (and succeeding) at keeping you from writing dangerous code.

@yeerkkiller1
Copy link
Author

Oh, I guess I just found it odd because usually typescript only allows you to access members common to all parts of a union. For example in the string | number case you can only call .toString() and .valueOf(), but not .toFixed().

But I see that treating any strictly would break backwards compatibility by forcing type narrowing when you have any types. Perhaps there could be a warning when an any is involved in a union? I have encountered cases when a stray any from an external .d.ts library propagates through my code, masking real type errors.

Researching more it looks like this may just be a rehash of #9999, so I will close.

@microsoft microsoft locked and limited conversation to collaborators Jun 14, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug
Projects
None yet
Development

No branches or pull requests

3 participants