Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Improved union/intersection type inference#5738

Merged
ahejlsberg merged 4 commits into
mastermicrosoft/TypeScript:masterfrom
unionIntersectionTypeInferencemicrosoft/TypeScript:unionIntersectionTypeInferenceCopy head branch name to clipboard
Nov 24, 2015
Merged

Improved union/intersection type inference#5738
ahejlsberg merged 4 commits into
mastermicrosoft/TypeScript:masterfrom
unionIntersectionTypeInferencemicrosoft/TypeScript:unionIntersectionTypeInferenceCopy head branch name to clipboard

Conversation

@ahejlsberg

Copy link
Copy Markdown
Member

This PR improves type inference involving source and target sides that are both union or intersection types. When inferring from a type S to a type T, if S and T are both union types or both intersection types, we first reduce S and T by removing constituents that are matched by a constituent in the other type. For example, when inferring from string | string[] to string | T, we reduce the types to string[] and T, thus inferring string[] for T.

An example:

type Maybe<T> = T | void;

function isDefined<T>(x: Maybe<T>): x is T {
    return x !== undefined && x !== null;
}

function isUndefined<T>(x: Maybe<T>): x is void {
    return x === undefined || x === null;
}

function getOrElse<T>(x: Maybe<T>, defaultValue: T): T {
    return isDefined(x) ? x : defaultValue;
}

function test1(x: Maybe<string>) {
    let x1 = getOrElse(x, "Undefined");         // string
    let x2 = isDefined(x) ? x : "Undefined";    // string
    let x3 = isUndefined(x) ? "Undefined" : x;  // string
}

function test2(x: Maybe<number>) {
    let x1 = getOrElse(x, -1);         // number
    let x2 = isDefined(x) ? x : -1;    // number
    let x3 = isUndefined(x) ? -1 : x;  // number
}

Fixes #2264.
Fixes #4212.
Fixes #5417.
Fixes #5456.

Comment thread src/compiler/checker.ts

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about

return forEach(target.types, t => isTypeIdenticalTo(source, t) || undefined);

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Definitely an option, but not quite as efficient. I will keep what's there.

@sandersn

Copy link
Copy Markdown
Member

👍

Comment thread src/compiler/checker.ts

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you break this into multiple lines?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use wordwrapping man.

@mariusschulz

Copy link
Copy Markdown
Contributor

@ahejlsberg You've got a little typo in your code example: isUndefined<T> should use or rather than and, shouldn't it? Just trying to avoid confusion here.

function isUndefined<T>(x: Maybe<T>): x is void {
    return x === undefined || x === null;
}

@ahejlsberg

Copy link
Copy Markdown
Member Author

@mariusschulz Yes indeed, thanks for catching that.

@ENikS

ENikS commented Dec 7, 2015

Copy link
Copy Markdown

Will this address issue mentioned in #3215 ?

@ahejlsberg

Copy link
Copy Markdown
Member Author

@ENikS No, the two are unrelated.

@masaeedu

masaeedu commented Feb 9, 2016

Copy link
Copy Markdown
Contributor

@ahejlsberg Would inferring T more accurately in the following scenario be worthwhile:

interface A { a: any; }

function test<T>(arg: A & T): T { ... }

let result = test({a: "", b: 10});

The type of result is inferred as {}, although I would expect it to be inferred as {b: number}. Admittedly I don't have a very clear use case for this at the moment.

@ahejlsberg

Copy link
Copy Markdown
Member Author

@masaeedu We could potentially explore that, but it could get complex and would require type inference to manufacture new types, neither of which I'm crazy about. Specifically, in your example, we'd have to manufacture a new type { b: number } and infer that for T. I think it is desirable to have the property that type inference never infers types that don't already occur in your code.

@microsoft microsoft locked and limited conversation to collaborators Jun 19, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants

Morty Proxy This is a proxified and sanitized view of the page, visit original site.