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

Intersection with type parameter doesn't subtract properties #20536

Closed
smoogly opened this issue Dec 7, 2017 · 6 comments
Closed

Intersection with type parameter doesn't subtract properties #20536

smoogly opened this issue Dec 7, 2017 · 6 comments
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug

Comments

@smoogly
Copy link

smoogly commented Dec 7, 2017

TypeScript Version: 2.6.1 && 2.7.0-dev.20171207

Code

interface InternalProps {
    a: number;
}
interface ExternalProps {
    b: string;
}

function make<T = {}>(arg: T & InternalProps): T & ExternalProps {
    return 1 as any;
}

const x = make<{}>({a: 1});
console.log(x.a); // Correct: type error

const y = make({a: 1});
console.log(y.a); // Incorrect: no type error

Expected behavior:
Property a should not be expected to exist on y.
Both examples should fail.

Actual behavior:
Only first example is considered a type error.

@ghost
Copy link

ghost commented Dec 7, 2017

Looks like a duplicate of #20505.

@smoogly
Copy link
Author

smoogly commented Dec 7, 2017

I'm not sure, but I don't think it's a duplicate.
In this case looks like T is inferred to be InternalProps, which is unexpected:

interface InternalProps {
    a: number;
}
interface ExternalProps {
    b: string;
}

function make<T = {}>(arg: T & InternalProps): T & ExternalProps {
    return 1 as any as T & ExternalProps;
}

const x = make<{}>({a: 1});
console.log(x.a); // Correct: type error
console.log(x.blah); // Correct: type error

const y = make({a: 1});
console.log(y.a); // Incorrect: no type error
console.log(y.blah); // Correct: type error
./node_modules/.bin/tsc test.ts                                                                            
test.ts(13,15): error TS2339: Property 'a' does not exist on type 'ExternalProps'.
test.ts(14,15): error TS2339: Property 'blah' does not exist on type 'ExternalProps'.
test.ts(18,15): error TS2339: Property 'blah' does not exist on type '{ a: number; } & ExternalProps'.

@smoogly smoogly changed the title Incorrect behaviour of default generic Incorrect behaviour of default generic with union types Dec 7, 2017
@ghost
Copy link

ghost commented Dec 7, 2017

The thing they have in common is that adding a default to a function's type parameter doesn't turn off type inference. So if a type can be inferred, that type will be used instead of the default.

But in this case I see that T could be inferred as {} since the input is T & InternalProps and InternalProps can handle the a property. One alternative to subtraction types (#4183) that I've heard discussed in the past I think looked something like this:

declare function removeA<T>(arg: T & { a: any }): T;
const o = removeA({a: 1});
o.a; // Should be an error?

@ghost ghost changed the title Incorrect behaviour of default generic with union types Intersection with type parameter doesn't subtract properties Dec 7, 2017
@smoogly
Copy link
Author

smoogly commented Dec 7, 2017

@andy-ms, yes if the example you show was implemented,
my scenario would produce the results I expect as well.

@mhegazy
Copy link
Contributor

mhegazy commented Jan 31, 2018

The compiler can not make these assumptions that the property exclusively exists in one constituent of the intersection.. i.e. T & { a: number } does not guarantee that T itself does not have a property "a" with the same type or a different one. I think what you need is Diff (#19569).

@mhegazy mhegazy added the Working as Intended The behavior described is the intended behavior; this is not a bug label Jan 31, 2018
@typescript-bot
Copy link
Collaborator

Automatically closing this issue for housekeeping purposes. The issue labels indicate that it is unactionable at the moment or has already been addressed.

@microsoft microsoft locked and limited conversation to collaborators Jul 3, 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