GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Predefined conditional types by ahejlsberg · Pull Request #21847 · microsoft/TypeScript

Conversation

@ahejlsberg

@ahejlsberg Anders Hejlsberg (ahejlsberg) commented Feb 9, 2018 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member

This PR adds several predefined conditional types to lib.d.ts:

  • Exclude<T, U> -- Exclude from T those types that are assignable to U.
  • Extract<T, U> -- Extract from T those types that are assignable to U.
  • NonNullable<T> -- Exclude null and undefined from T.
  • ReturnType<T> -- Obtain the return type of a function type.
  • InstanceType<T> -- Obtain the instance type of a constructor function type.

Some examples:

type T00 = Exclude<"a" | "b" | "c" | "d", "a" | "c" | "f">;  // "b" | "d"
type T01 = Extract<"a" | "b" | "c" | "d", "a" | "c" | "f">;  // "a" | "c"

type T02 = Exclude<string | number | (() => void), Function>;  // string | number
type T03 = Extract<string | number | (() => void), Function>;  // () => void

type T04 = NonNullable<string | number | undefined>;  // string | number
type T05 = NonNullable<(() => string) | string[] | null | undefined>;  // (() => string) | string[]

function f1(s: string) {
    return { a: 1, b: s };
}

class C {
    x = 0;
    y = 0;
}

type T10 = ReturnType<() => string>;  // string
type T11 = ReturnType<(s: string) => void>;  // void
type T12 = ReturnType<(<T>() => T)>;  // {}
type T13 = ReturnType<(<T extends U, U extends number[]>() => T)>;  // number[]
type T14 = ReturnType<typeof f1>;  // { a: number, b: string }
type T15 = ReturnType<any>;  // any
type T16 = ReturnType<never>;  // any
type T17 = ReturnType<string>;  // Error
type T18 = ReturnType<Function>;  // Error

type T20 = InstanceType<typeof C>;  // C
type T21 = InstanceType<any>;  // any
type T22 = InstanceType<never>;  // any
type T23 = InstanceType<string>;  // Error
type T24 = InstanceType<Function>;  // Error

The Exclude type is a proper implementation of the Diff type suggested here #12215 (comment). We've used the name Exclude to avoid breaking existing code that defines a Diff, plus we feel that name better conveys the semantics of the type. We did not include the Omit<T, K> type because it is trivially written as Pick<T, Exclude<keyof T, K>>.

When applying ReturnType<T> and InstanceType<T> to types with multiple call or construct signatures (such as the type of an overloaded function), inferences are made from the last signature (which, presumably, is the most permissive catch-all case). It is not possible to perform overload resolution based on a list of argument types (this would require us to support typeof for arbitrary expressions, as suggested in #6606, or something similar).

Fixes #19569.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

vincentbel, vhfmag, KiaraGrouwstra, bogomya, ibezkrovnyi, robotlolita, andrekosak, wanganjun, kastermester, no23reason, and 68 more reacted with thumbs up emoji marcind, johnfn, pelotom, chrismcleod, wand3r, Pajn, dfilatov, mrmlnc, gallayl, olaf89, and 61 more reacted with hooray emoji karol-majewski, piotrwitek, listepo-alterpost, louy, davidkpiano, andrewbranch, mightyiam, aikoven, vhfmag, KiaraGrouwstra, and 36 more reacted with heart emoji
All reactions
  • 👍 78 reactions
  • 🎉 71 reactions
  • ❤️ 46 reactions
Anders Hejlsberg (ahejlsberg) added 3 commits February 9, 2018 14:22
@ahejlsberg
Add Exclude, Extract, NonNullable, ReturnType, and InstanceType types
2aba29f
@ahejlsberg
Update tests
92b8ce7
@ahejlsberg
Accept new baselines
11a075c
@ahejlsberg
Anders Hejlsberg (ahejlsberg) requested review from Daniel Rosenwasser (DanielRosenwasser) and Mohamed Hegazy (mhegazy) February 9, 2018 22:57
mhegazy
Mohamed Hegazy (mhegazy) approved these changes Feb 9, 2018
View reviewed changes
@ahejlsberg
Anders Hejlsberg (ahejlsberg) merged commit f1d7afe into master Feb 9, 2018
@ahejlsberg
Anders Hejlsberg (ahejlsberg) deleted the predefinedConditionalTypes branch February 9, 2018 23:40
@mhegazy Mohamed Hegazy (mhegazy) mentioned this pull request Feb 10, 2018
Subtraction types #4183
Closed
@pelotom Tom Crockett (pelotom) mentioned this pull request Feb 11, 2018
Proposal: Get the type of any expression with typeof #6606
Closed
@KiaraGrouwstra

kiara (KiaraGrouwstra) commented Feb 11, 2018

Copy link
Copy Markdown
Contributor

We did not include the Omit<T, K> type because it is trivially written as Record<T, Exclude<keyof T, K>>.

I think that should have been Pick rather than Record. :)
Moreover, thanks for all the new features!

sebald reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@ahejlsberg

Anders Hejlsberg (ahejlsberg) commented Feb 11, 2018

Copy link
Copy Markdown
Member Author

@tycho01 Right you are! Fixed.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@yortus Troy Gerwien (yortus) mentioned this pull request Feb 14, 2018
Exclude<T, U> type not working like Diff<T, U> #21929
Closed
@AriaMinaei

Aria (AriaMinaei) commented Feb 16, 2018

Copy link
Copy Markdown

I wonder if it is possible to detect plain objects using the Exclude type? Something like:

const plainObj = {foo: 'bar'}
const nonPlainObj = new Error()
IsPlainObject<typeof plainObj> // true
IsPlainObject<typeof nonPlainObj> // false
IsPlainObject<string> // false
All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@KiaraGrouwstra

kiara (KiaraGrouwstra) commented Feb 17, 2018 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

Aria (@AriaMinaei): for what it's worth, I'm not aware of any way we can do that so far. I think it comes down to getting a prototype, but as far as I know the type-level operators we have don't do much with JS prototypes.
Out of curiosity, what's your use-case?

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@AriaMinaei

Aria (AriaMinaei) commented Feb 17, 2018

Copy link
Copy Markdown

@tycho01 Thanks, now I know I shouldn't try more :)

Here is my use-case though:

export type Atomify<V> = {
  '1': 
  V extends Array<infer T> ? ArrayAtom<Atomify<T>> :
  V extends AbstractAtom<$IntentionalAny> ? V :
  // following is commented out as I don't know how to detect plain objects in TS
  // V extends {constructor: Function} ? BoxAtom<V> :
  V extends object ? DictAtom<{[K in keyof V]: Atomify<V[K]>}> :
  BoxAtom<V>
}[V extends number ? '1' : '1']

const atomifyDeep = <V extends {}>(jsValue: V): Atomify<V> => {
  if (Array.isArray(jsValue)) {
    return fromJSArray(jsValue)
  } else if (isPlainObject(jsValue)) {
    return fromJSObject(jsValue as $IntentionalAny)
  } else if (jsValue instanceof AbstractAtom) {
    return jsValue as $IntentionalAny
  } else {
    return fromJSPrimitive(jsValue)
  }
}

const fromJSArray = (jsArray: $IntentionalAny): $IntentionalAny => {
  return new ArrayAtom(jsArray.map(atomifyDeep))
}

const fromJSObject = (jsObject: {[key: string]: mixed}): $IntentionalAny => {
  return new DictAtom(mapValues(jsObject, atomifyDeep))
}

const fromJSPrimitive = (jsPrimitive: mixed): $IntentionalAny => {
  return new BoxAtom(jsPrimitive)
}

export default atomifyDeep

This atomifyDeep() function takes any js value as input, and returns a "reactive" data structure. Arrays and plain objects are deeply wrapped into these structures which tracks their changes deeply, while JS primitives, functions, and instances of any class are wrapped in a BoxAtom which tracks their changes via reference.

As you see, I used your [V extends number ? '1' : '1'] trick to recursively call AtomifyDeep, and it passes all of my type test cases, except those for non-plain JS objects. It detects them as plain JS objects and wraps them in a DictAtom.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@aikoven Daniel Lytkin (aikoven) mentioned this pull request Feb 20, 2018
Typings for dispatch props aikoven/typescript-fsa#51
Closed
@phiresky

phiresky commented Feb 22, 2018

Copy link
Copy Markdown

Why are the "other" cases for ReturnType and InstanceType any and not never?

When would you want ReturnType<"notafunction"> to be any? This seems really bad since then you would just propagate any everywhere if you make a mistake while using ReturnType somwhere.

KiaraGrouwstra, paldepind, tommytroylin, leonadler, PgBiel, and eugirdor reacted with thumbs up emoji
All reactions
  • 👍 6 reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@eemelisoderholm Eemeli Söderholm (eemelisoderholm) mentioned this pull request Feb 23, 2018
Could typeOf narrowing work without explicit generics in TypeScript 2.8? redux-observable/redux-observable#437
Closed
@KiaraGrouwstra kiara (KiaraGrouwstra) mentioned this pull request Mar 1, 2018
Non-null assertion type operator ! #14366
Closed
@azu azu (azu) mentioned this pull request Mar 2, 2018
TypeScript: improve UseCase#execute typing almin/almin#107
Closed
This was referenced Mar 2, 2018
Way to specify that type can't be null #14967
Closed
Non-null assertion operator and the typeof operator #17370
Closed
Non null property in map type #19608
Closed
StrictNullCheck incorrectly prevents the use of the indexed access operator #20141
Closed
Suggestion: Type assertion operator (!) with mapped types #13253
Closed
@bcherny Boris Cherny (bcherny) mentioned this pull request Mar 4, 2018
Get union of all possible return types of a function #20350
Closed
@forabi M-Fawaz Orabi (forabi) mentioned this pull request Mar 5, 2018
Upgrade to TS 2.8 hollowverse-archive/hollowverse#342
Merged
@JasonKleban

JasonKleban commented Mar 6, 2018 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown

Awesome!!

I get a few errors attempting to combine the use of type mapping with ReturnType. Is there a way to assert that T[M] will be compatible as the generic argument to ReturnType?

interface X {
    a : (,) => Promise<string>
    b : (,,,) => Promise<number>
    c : () => Promise<UserData>
}

type Cached<T> = { [M in keyof T] : ReturnType<T[M]> } // ❌ Type 'T[M]' does not satisfy the constraint '(...args: any[]) => any'.
const ex : Cached<X> = <any>null; 

type Cached2<T extends { [m : string] : (...args: any[]) => any }> = { [M in keyof T] : ReturnType<T[M]> }
const ex2 : Cached2<X> = <any>null; // ❌ Index signature is missing in type 'X'.
All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@JasonKleban

JasonKleban commented Mar 6, 2018

Copy link
Copy Markdown

Nevermind. WOW!! This works:

type Cached<T> = { [M in keyof T] : ReturnType<T[M] extends (...args: any[]) => any ? T[M] : any> }
const ex : Cached<X> = <any>null;

And so does this, to extract the return type out of the promise!! Amazing

type Cached2<T> = { [M in keyof T] : ReturnType<T[M] extends (...args: any[]) => any ? T[M] : any> extends Promise<infer Y> ? Y : ReturnType<T[M] extends (...args: any[]) => any ? T[M] : any> }
const ex2 : Cached2<X> = <any>null;
All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@SalathielGenese Salathiel Genese (SalathielGenese) mentioned this pull request Mar 9, 2018
Allow negated types + F-bounded mapped types #18280
Closed
@mhegazy Mohamed Hegazy (mhegazy) mentioned this pull request Mar 9, 2018
Generic return value of a mixin constructor #22431
Closed
@SalathielGenese Salathiel Genese (SalathielGenese) mentioned this pull request Mar 9, 2018
Negated types #4196
Open
@aldendaniels Alden Daniels (aldendaniels) mentioned this pull request Mar 12, 2018
Implementing defaultProps with ts 2.0 strict null checks DefinitelyTyped/DefinitelyTyped#11640
Closed
@Grmiade Jérémy Fauvel (Grmiade) mentioned this pull request Mar 12, 2018
react-router: withRouter narrows components with any prop type to {} DefinitelyTyped/DefinitelyTyped#24070
Closed
2 of 4 tasks
@rdhelms Robby Helms (rdhelms) mentioned this pull request Mar 14, 2018
Some way to express a non-null / non-undefined any would be nice #7648
Closed
@michaeljota

Michael De Abreu (michaeljota) commented Mar 19, 2018 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown

I am playing around with this, and I would like to know a type mapper that resembles Flow $Diff, meaning, one that returns properties that are in both, T and U, but, without expressing T nor U as union types, but intersecting their own properties.

Edit: I mean to say, that $Diff returns a property exclusion between the properties of A, and the properties of B. As in the example below, where I also use the work 'intersection' although is quite the opposite as the real thing I wanted to say. Sorry.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@KiaraGrouwstra

kiara (KiaraGrouwstra) commented Mar 19, 2018

Copy link
Copy Markdown
Contributor

Michael De Abreu (@michaeljota) kinda like Pick<A, Extract<keyof A, keyof B>>?

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@michaeljota

Michael De Abreu (michaeljota) commented Mar 19, 2018 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown

@tycho01 Almost! Thanks you so much! I test it, and is just

class A {
  a: string;
  b: string;
}

class B {
  a: string;
  c: string;
}

type Diff<T, U> = Pick<T, Exclude<keyof T, keyof U>>;

type C = Diff<A, B>;
// C = { b: string; }

Maybe I did not explain myself, but $Diff in Flow is a intersection exclusion of A and B properties.

KiaraGrouwstra and jedrzejginter reacted with thumbs up emoji
All reactions
  • 👍 2 reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@michaeljota

Michael De Abreu (michaeljota) commented Mar 20, 2018

Copy link
Copy Markdown

Any chance for Typescript to have a type mapper with this? Although the naming will be harder than usual.

KiaraGrouwstra reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@lazywithclass Alberto Zaccagni (lazywithclass) mentioned this pull request Mar 23, 2018
Exclude type not preventing to pass "excluded" types #22822
Closed
@piotrwitek Piotr Witek (piotrwitek) mentioned this pull request Mar 26, 2018
New API - v2.0 piotrwitek/typesafe-actions#22
Closed
@chrisgervang Chris Gervang (chrisgervang) mentioned this pull request Apr 6, 2018
TypeScript 2.7 and 2.8 features niieani/typescript-vs-flowtype#26
Open
@googol Miika Hänninen (googol) mentioned this pull request Apr 17, 2018
[Ramda]: fixed pick and omit type signatures to reflect projections DefinitelyTyped/DefinitelyTyped#24936
Merged
8 tasks done
@jods4

jods (jods4) commented May 8, 2018

Copy link
Copy Markdown

ReturnType design doesn't support generic functions, right?

Is there a syntax that would work for this:

// Doesn't work in 2.8
function f<T>(x: T): T { return x }

type R = ReturnType<typeof f<string>>; // = string
All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@mhegazy

Mohamed Hegazy (mhegazy) commented May 8, 2018

Copy link
Copy Markdown
Contributor

ReturnType design doesn't support generic functions, right?

it is not ReturnType, values can not have generic type arguments. type arguments are only available in certain syntactic locations, like call/new expressions, extends clauses and type references.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@jods4

jods (jods4) commented May 9, 2018

Copy link
Copy Markdown

Mohamed Hegazy (@mhegazy) That's what I figured, thanks.

Should I open a suggestion for allowing a type argument when a generic function is used in typeof?
ReturnType is a good use case for that.

I know there is an open suggestion for allowing arbitrary expression in typeof anyway, would it be enough?

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@mhegazy

Mohamed Hegazy (mhegazy) commented May 9, 2018

Copy link
Copy Markdown
Contributor

typeof is not the issue either. typeof allows a limited subset of expression syntax. I think #15877 is what you are looking for.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@michaeljota

Michael De Abreu (michaeljota) commented May 9, 2018

Copy link
Copy Markdown

Mohamed Hegazy (@mhegazy) about the PR, do you plan to include Omit type helper. I know how to implemented, but still I think Omit is commonly used and will be worth to include it.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@mhegazy

Mohamed Hegazy (mhegazy) commented May 9, 2018

Copy link
Copy Markdown
Contributor

do you plan to include Omit type helper.

No. we have avoided to use the names Omit and Diff to avoid breaking users who already defined these types. Omit is trivially implemented as Pick<T, Exclude<keyof T, K>>.

SlurpTheo reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@jmagaram Justin Magaram (jmagaram) mentioned this pull request Jun 14, 2018
Compile error using TypeScript "ReturnType" angular/angular#24499
Closed
@microsoft Microsoft (microsoft) locked and limited conversation to collaborators Jul 31, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Reviewers

@DanielRosenwasser Daniel Rosenwasser (DanielRosenwasser) Awaiting requested review from DanielRosenwasser
1 more reviewer
@mhegazy Mohamed Hegazy (mhegazy) mhegazy approved these changes
Reviewers whose approvals may not affect merge requirements

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

8 participants

@ahejlsberg @KiaraGrouwstra @AriaMinaei @phiresky @JasonKleban @michaeljota @jods4 @mhegazy
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.