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 — Negated types by weswigham · Pull Request #29317 · microsoft/TypeScript

Conversation

@weswigham

@weswigham Wesley Wigham (weswigham) commented Jan 9, 2019 •
edited
Loading

Uh oh!

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

Copy link
Copy Markdown
Member

Long have we spoken of them in hushed tones and referenced them in related issues, here they are:

Negated Types

Negated types, as the name may imply, are the negation of another type. Conceptually, this means that if string covers all values which are strings at runtime, a "not string" covers all values which are... not. We had hoped that conditional types would by and large subsume any use negated types would have... and they mostly do, except in many cases we need to apply the constraint implied by the conditional's check to it's result. In the true branch, we can just intersect the extends clause type, however in the false branch we've thus far been discarding the information. This means unions may not be filtered as they should (especially when conditionals nest) and information can be lost. So that ended up being the primary driver for this primitive - it's taking what a conditional type false branch implies, and allowing it to stand alone as a type.

Syntax

not T

where T is another type. I'm open to bikeshedding this, or even shipping without syntax available, but among alternatives (!, ~) not reads pretty well.

Identities

These are little tricks we do on negated type construction to help speed things along (and give negations on algebraic types canonical forms).

  • not not T is T
  • not (A | B | C | ...) is not A & not B & not C & not ...
  • not (A & B & C & ...) is not A | not B | not C | not ...
  • not unknown is never
  • not never is unknown
  • not any is any (since any is the NaN of types and behaves as both the bottom and top)

Assignability Rules

Negated types, for perhaps obvious reasons, cannot be related structurally - the only sane way to relate them is in a higher-order fashion. Thus, the rules governing these relations are very important.

  • A negated type not S is related to a negated type not T if T is related to S.
    This follows from the set membership inversion that a negation implies - if normally a type S and a type T would be related if S is a subset of T, when we take the complements of those sets, not S and not T, those sets share an inverse relationship to the originals.
  • A type S is related to a negated type not T if the intersection of S and T is empty
    We want to check if for all values in S, none of those values are also in T (since if they are, S is not in the negation of T). The intersection of S and T, when simplified and evaluated, is exactly the description of the common domain of the two. If this domain is empty (never), then we can conclude that there is no overlap between the two and that S must lie within not T.
  • A negated type not S is not related to a type T.
    A negated type describes a set of values that reaches from unknown to its bound, while a normal type describes values from its bound to never - it's impossible for a negated type to satisfy a normal type

Assignability Addendum for Fresh Object Types

Frequently we want to consider a fresh object type as a singleton type (indeed, some examples in the refs assume this) - it corresponds to one runtime value, not the bounds on a value (meaning, as a type, both its upper and lower bounds are itself). Using this, we can add one more rule that allows fresh literal types to easily satisfy negated object types.

  • A fresh object type S is related to a negated type not T if S is not related to T.
    Since S is a singleton type, we can assume that so long as it's type is not in T, then it is in not T.

Examples

Examples of negated type usage can be found in the tests of this PR (there's a few hundred lines of them, and probably some more to come for good measure), but here's some of the common ones, pulled from the referenced issues:

declare function ignore<T extends not (object & Promise<any>)>(value: T): void;
declare function readFileAsync(): Promise<string>;
declare function readFileSync(): string;
ignore(readFileSync());     // OK
ignore(readFileAsync());    // Should error

declare function map<T, U extends not void>(values: T[], map: (value: T) => U) : U[]; // validate map callback doesn't return void

function foo() {}

map([1, 2, 3], n => n + 1); // OK
map([1, 2, 3], foo);        // Should error

function asValid<T extends not null>(value: T, isValid: (value: T) => boolean) : T | null {
    return isValid(value) ? value : null;
}

declare const x: number;
declare const y: number | null;
asValid(x, n => n >= 0);    // OK
asValid(y, n => n >= 0);    // Should error

function tryAt<T extends not undefined>(values: T[], index: number): T | undefined {
    return values[index];
}

declare const a: number[];
declare const b: (number | undefined)[];
tryAt(a, 0);    // OK
tryAt(b, 0);    // Should error

Fixes #26240.
Allows #27711 to be cleanly fixed with a lib change (example in the tests).

Ref #4183, #4196, #7648, #12215, #18280

Sorry, something went wrong.

Uh oh!

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

trotyl, NN---, j-oliveras, rimiti, jscheiny, as-ivanov, sindresorhus, MaximeRVY, ikatyang, agentcooper, and 391 more reacted with thumbs up emoji DenisFrezzato, SimonSchick, and enricopolanski reacted with thumbs down emoji Bnaya, JoshuaKGoldberg, SalathielGenese, RyanCavanaugh, j-oliveras, jcalz, newswim, samschaack, alvis, OctoD, and 13 more reacted with laugh emoji sean-vieira, ajafff, trotyl, j-oliveras, rimiti, niieani, Bnaya, Igorbek, SalathielGenese, krryan, and 55 more reacted with hooray emoji gr2m reacted with confused emoji trotyl, j-oliveras, rimiti, alexrock, artman, Bnaya, Igorbek, SalathielGenese, zpdDG4gta8XKpMCd, krryan, and 83 more reacted with heart emoji omril1, Jdender, jcalz, aleclarson, newswim, samschaack, vladimirlogachev, NoFishLikeIan, haltcase, Veetaha, and 49 more reacted with rocket emoji newswim, wsmd, NoFishLikeIan, mmgeorge, Veetaha, giogonzo, tonivj5, macabeus, dimitropoulos, j3bb9z, and 10 more reacted with eyes emoji
All reactions
  • 👍 401 reactions
  • 👎 3 reactions
  • 😄 23 reactions
  • 🎉 65 reactions
  • 😕 1 reaction
  • ❤️ 93 reactions
  • 🚀 59 reactions
  • 👀 20 reactions
@weswigham
Wesley Wigham (weswigham) requested review from Daniel Rosenwasser (DanielRosenwasser), Anders Hejlsberg (ahejlsberg), Ron Buckton (rbuckton) and Nathan Shively-Sanders (sandersn) January 9, 2019 01:46
DanielRosenwasser
Daniel Rosenwasser (DanielRosenwasser) reviewed Jan 9, 2019
View reviewed changes
Comment thread tests/baselines/reference/keyofAndIndexedAccessErrors.errors.txt Outdated
tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(103,9): error TS2322: Type 'Extract<keyof T, string>' is not assignable to type 'K'.
Type 'string & keyof T' is not assignable to type 'K'.
Type 'string' is not assignable to type 'K'.
Type 'string' is not assignable to type 'K'.

@DanielRosenwasser Daniel Rosenwasser (DanielRosenwasser) Jan 9, 2019

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

I'm not complaining, but why'd this go away?

Sorry, something went wrong.

Uh oh!

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

All reactions

@weswigham Wesley Wigham (weswigham) Jan 9, 2019

Copy link
Copy Markdown
Member Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

I accidentally fixed a bug where we duplicated the elaboration - this is as the same as the line above.

Sorry, something went wrong.

Uh oh!

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

ctrlplusb, catb0t, noramass, MKRhere, wongjiahau, grebmeg, and aaditmshah reacted with thumbs up emoji Zzzen, SpencerPark, catb0t, noramass, lazarljubenovic, Quelklef, kjleitz, MKRhere, mheiber, armano2, and 4 more reacted with laugh emoji samhh, catb0t, and aaditmshah reacted with rocket emoji
All reactions
  • 👍 7 reactions
  • 😄 14 reactions
  • 🚀 3 reactions
@DanielRosenwasser

Daniel Rosenwasser (DanielRosenwasser) commented Jan 9, 2019

Copy link
Copy Markdown
Member

First take, without having tried this out:

  • Intersections appear to be the correct mechanism to check for potential overlap, but that also means almost no object type can satisfy a negated object type. If we add negated types, I would prefer not to give the check up at all though.
  • I find it weird, but understandable, that you treat fresh object types differently. But it's clearly weird that these are the only exception to the above issue.

I do have some reservations on the feature for these reasons. If you think about our features trying to satisfy convenience, intent, and safety, then I don't know if this appropriately weighs convenience and intent.

All reactions

Sorry, something went wrong.

Uh oh!

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

@weswigham

Wesley Wigham (weswigham) commented Jan 9, 2019 •
edited
Loading

Uh oh!

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

Copy link
Copy Markdown
Member Author

Intersections appear to be the correct mechanism to check for potential overlap, but that also means almost no object type can satisfy a negated object type. If we add negated types, I would prefer not to give the check up at all though.

not (object & SomeInterface)

It works just dandy~

All reactions

Sorry, something went wrong.

Uh oh!

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

@DanielRosenwasser

Daniel Rosenwasser (DanielRosenwasser) commented Jan 9, 2019 •
edited by weswigham
Loading

Uh oh!

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

Copy link
Copy Markdown
Member

It works just dandy~

What do you mean? Yesterday you mentioned that you couldn't assign an array to a not PromiseLike<any>.

All reactions

Sorry, something went wrong.

Uh oh!

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

@weswigham

Wesley Wigham (weswigham) commented Jan 9, 2019 •
edited
Loading

Uh oh!

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

Copy link
Copy Markdown
Member Author

Nope, you can't, because you can trivially make a

interface PromiseLikeArray extends Array<any> implements PromiseLike<any> { /*...*/ }

so, if you go to the example, I just state that I explicitly return an array that isn't PromiseLike - that is T[] & not PromiseLike<any>

All reactions

Sorry, something went wrong.

Uh oh!

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

@weswigham

Wesley Wigham (weswigham) commented Jan 9, 2019 •
edited
Loading

Uh oh!

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

Copy link
Copy Markdown
Member Author

Per offline feedback from Anders Hejlsberg (@ahejlsberg) I've changed from ~ unary operator to a not keyword type operator (and updated all the text in this PR thus far to match). It does read nicer.

LeartS, worstpractice, and aaronik reacted with thumbs up emoji cshaa, LeartS, worstpractice, and aaronik reacted with heart emoji
All reactions
  • 👍 3 reactions
  • ❤️ 4 reactions

Sorry, something went wrong.

Uh oh!

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

@weswigham Wesley Wigham (weswigham) closed this Jan 9, 2019
@weswigham Wesley Wigham (weswigham) reopened this Jan 9, 2019
@Jessidhia

Jessica Franco (Jessidhia) commented Jan 10, 2019

Copy link
Copy Markdown

Can this be used as a way to restrict the potential type of unbounded types? For example, number & not 0 to allow any number except the literal 0.

This doesn't look very useful at first glance but it can be powerful on mapped types. For example, [key in string and not keyof CSS.Properties<any>] in https://github.com/DefinitelyTyped/DefinitelyTyped/blob/e836acc75a78cf0655b5dfdbe81d69fdd4d8a252/types/styled-components/index.d.ts#L16-L25 could allow the constrained index signature to not have to include CSS.Properties<string | number>[keyof CSS.Properties<string | number>].

chocolateboy, Azarlak, noramass, thw0rted, yinso, Nixinova, ishowta, dalyIsaac, worstpractice, rezonant, and aaditmshah reacted with thumbs up emoji KewinDousse, mgol, GoToLoop, mihailik, fabiancook, noramass, worstpractice, and aaditmshah reacted with hooray emoji
All reactions
  • 👍 11 reactions
  • 🎉 8 reactions

Sorry, something went wrong.

Uh oh!

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

@weswigham

Wesley Wigham (weswigham) commented Jan 10, 2019

Copy link
Copy Markdown
Member Author

Can this be used as a way to restrict the potential type of unbounded types? For example, number & not 0 to allow any number except the literal 0.

Yep. That's a primary driver for 'em.

hassankhan, jackwilsdon, haltcase, krisdages, mgol, SpencerPark, Arrow7000, RichiCoder1, dylans, tommytroylin, and 23 more reacted with thumbs up emoji chocolateboy, noramass, worstpractice, Stumblinbear, aaronik, gustavohenke, and aaditmshah reacted with hooray emoji mheiber, noramass, MKRhere, lgenzelis, worstpractice, Stumblinbear, aaronik, falfiya, and aaditmshah reacted with heart emoji
All reactions
  • 👍 33 reactions
  • 🎉 7 reactions
  • ❤️ 9 reactions

Sorry, something went wrong.

Uh oh!

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

@Jessidhia

Jessica Franco (Jessidhia) commented Jan 10, 2019

Copy link
Copy Markdown
type Exact<T extends object> = T & Partial<Record<not keyof T, never>>

🤔

wojpawlik, nmn, somebody1234, Krumpet, msakrejda, and james-pre reacted with thumbs up emoji nmn and Stumblinbear reacted with hooray emoji nmn and yaroslavvoloshchuk-codaio reacted with heart emoji nmn and Stumblinbear reacted with rocket emoji
All reactions
  • 👍 6 reactions
  • 🎉 2 reactions
  • ❤️ 2 reactions
  • 🚀 2 reactions

Sorry, something went wrong.

Uh oh!

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

@jack-williams

Jack Williams (jack-williams) commented Jan 10, 2019 •
edited
Loading

Uh oh!

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

Copy link
Copy Markdown
Collaborator

Is there an outline of how not interacts with narrowing? Might we have something like?

function foo(x: unknown) {
  if (typeof x === "number") {
    const num: number = x;
  } else {
    const numNot: not number = x;
  }
}

Assignability Addendum for Fresh Object Types

Is there a short example that demonstrates wanting a not for an object literal?


Daniel Rosenwasser (@DanielRosenwasser) Do you mean something like { x: number } is not assignable to not { x: boolean } because { x : number} & { x: boolean } does not get reduced to never.

Meta question for Daniel Rosenwasser (@DanielRosenwasser): You say:

convenience, intent, and safety

that seem like some internal principles the TS team have for designing features? Is there a public description of these? I think it would help feature proposals if external contributors could frame their suggestions with the same language used internally.


@Kovensky I'm not sure that will type-check. The type not keyof T includes any type which isn't one of the keys, such as boolean. You might need:

type Exact<T extends object> = T & Partial<Record<(not keyof T) & string, never>>

though I'm not sure what the semantics will be for not types appearing in mapped type constraints.

agentcooper, peter-leonov, ksaldana1, SalathielGenese, mihailik, Krumpet, and worstpractice reacted with thumbs up emoji
All reactions
  • 👍 7 reactions

Sorry, something went wrong.

Uh oh!

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

@weswigham

Wesley Wigham (weswigham) commented Jan 10, 2019 •
edited
Loading

Uh oh!

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

Copy link
Copy Markdown
Member Author

Is there an outline of how not interacts with narrowing? Might we have something like?

In this PR no negated types are produced by control flow yet; however we've talked over it and negated types make the lib type facts PR elegant to implement, since we can skip using conditionals (which don't compose well) and just filter with intersections of negated types :D

Is there a short example that demonstrates wanting a not for an object literal?

Aye, a test case with an example I pulled from a related issue:

// from https://github.com/Microsoft/TypeScript/issues/4183
type Distinct<A, B> = (A | B) & not (A & B);
declare var o1: {x};
declare var o2: {y};

 declare function f1(x: Distinct<typeof o1, typeof o2>): void;

 f1({x: 0});         // OK
f1({y: 0});         // OK
f1({x: 0, y: 0});   // Should error

though I'm not sure what the semantics will be for not types appearing in mapped type constraints.

Right now they're quietly dropped (aside from filtering out mismatching concrete types), like symbol for the same reason. There's no non-generic concept to map them into. I have a test to that effect. The arbitrary index signatures PR fixes this and would allow an index signature of a, say, string & not "". With that in place mapped types work correctly with 'em, since the intersections trivially desugar to an index signature.

jack-williams, SlurpTheo, ethanresnick, G-Rath, and worstpractice reacted with thumbs up emoji
All reactions
  • 👍 5 reactions

Sorry, something went wrong.

Uh oh!

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

@jack-williams

Jack Williams (jack-williams) commented Jan 10, 2019

Copy link
Copy Markdown
Collaborator

Wesley Wigham (@weswigham) Thanks! And this PR is very cool :)

Re: the object literal example. Should that not be a case where EPC raises an error? I know it doesn't right now because there is no discriminant, but it probably should. Will using negation types become the canonical way of dealing with examples like this? If not, and assuming EPC does get fixed, are there many other use-cases for the special object literal relation.

All reactions

Sorry, something went wrong.

Uh oh!

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

@weswigham

Wesley Wigham (weswigham) commented Jan 10, 2019 •
edited
Loading

Uh oh!

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

Copy link
Copy Markdown
Member Author

Re: the object literal example. Should that not be a case where EPC raises an error? I know it doesn't right now because there is no discriminant, but it probably should. Will using negation types become the canonical way of dealing with examples like this? If not, and assuming EPC does get fixed, are there many other use-cases for the special object literal relation.

Even if excess property checking makes defining a type like Distinct unneeded, you'd still need the relationship to allow a type like Distinct to be satisfiable (with fresh object types) should one be used.

jack-williams 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.

@SalathielGenese

Salathiel Genese (SalathielGenese) commented Jan 15, 2019 •
edited
Loading

Uh oh!

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

Copy link
Copy Markdown

Good job so far, I delayed some projects to wait for this feature - for more than a year.

worstpractice and gillesdemey reacted with thumbs down emoji worstpractice and Vanilagy reacted with laugh emoji
All reactions
  • 👎 2 reactions
  • 😄 2 reactions

Sorry, something went wrong.

Uh oh!

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

@weswigham Wesley Wigham (weswigham) mentioned this pull request Jan 16, 2019
Exact Types #12936
Open
@jack-williams

Jack Williams (jack-williams) commented Jan 16, 2019

Copy link
Copy Markdown
Collaborator

Do these identities hold?
T & (not T) is never.
T & (not U) is T when T and U are disjoint.
"2b" | (not "2b") is unknown, or generally T | (not T) is unknown.

Just wondering what it would take to fix #28131

SlurpTheo, qwertie, Tobias-Scholz, conmaster2112, and msakrejda reacted with thumbs up emoji
All reactions
  • 👍 5 reactions

Sorry, something went wrong.

Uh oh!

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

@weswigham

Wesley Wigham (weswigham) commented Jan 16, 2019

Copy link
Copy Markdown
Member Author

T & (not T) is never.

Yes. More generally, when U extends T, U & not T is never.

T & (not U) is T when T and U are disjoint.

Yes.

"2b" | (not "2b") is unknown, or generally T | (not T) is unknown

More generally when U extends T, T | not U is just unknown (quite literally the opposite of the intersection into never rule). That's correct though I don't remember if I'd actually implemented this one yet - afaik we don't currently have any union identities that cause unions to "simplify" to unknown yet so I remember thinking about how it's best accomplished for a bit.

jack-williams, SlurpTheo, dead-claudia, qwertie, and mscottnelson reacted with thumbs up emoji
All reactions
  • 👍 5 reactions

Sorry, something went wrong.

Uh oh!

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

DanielRosenwasser
Daniel Rosenwasser (DanielRosenwasser) reviewed Jan 23, 2019
View reviewed changes
Comment thread src/compiler/checker.ts Outdated
const result = isRelatedTo(source, (target as NegatedType).type);
return result === Ternary.Maybe ? Ternary.Maybe : result ? Ternary.False : Ternary.True;
}
// Relationship check is S ⊂ T

@DanielRosenwasser Daniel Rosenwasser (DanielRosenwasser) Jan 23, 2019

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

Do you really need to use this symbol? It almost sounds like a joke, but this could affect memory footprint when bootstrapping the compiler since modern engines can avoid full UTF16 representations https://blog.mozilla.org/javascript/2014/07/21/slimmer-and-faster-javascript-strings-in-firefox/

Sorry, something went wrong.

Uh oh!

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

peter-leonov and Bnaya reacted with thumbs up emoji smichel17, papb, msakrejda, crystalbit, fallaciousreasoning, and Sensanaty reacted with laugh emoji Bnaya reacted with rocket emoji
All reactions
  • 👍 2 reactions
  • 😄 6 reactions
  • 🚀 1 reaction

@peter-leonov Peter Leonov (peter-leonov) Jan 23, 2019

Copy link
Copy Markdown

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

A minification step will simply remove this line. The article suggests to minify the code to utilise the inline strings and also help with strings interning. I guess, v8 should not be so much different in this sense and also win from code minification.

Sorry, something went wrong.

Uh oh!

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

boredcity reacted with thumbs up emoji
All reactions
  • 👍 1 reaction
@jack-williams

Jack Williams (jack-williams) commented Jan 24, 2019 •
edited
Loading

Uh oh!

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

Copy link
Copy Markdown
Collaborator

Wesley Wigham (@weswigham) Seems to work, right?

type UnionToInterWorker<T> = not (T extends T ? not T : never);
type UnionToInter<T> = [T] extends [never] ? never : UnionToInterWorker<T>;

Not quite sure what should happen here:

type NotInfer<T> = T extends not (infer U) ? U : never;
type NotString = NotInfer<string> // string extends not U ? U : never;

Currently it doesn't reduce; maybe infer types should be disallowed under not?

All reactions

Sorry, something went wrong.

Uh oh!

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

@weswigham

Wesley Wigham (weswigham) commented Jan 24, 2019 •
edited
Loading

Uh oh!

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

Copy link
Copy Markdown
Member Author

It doesn't reduce because we don't reduce reducible conditionals with infer's in them right now. IMO, it certainly still makes sense to allow an infer inside a not, since not A extends not infer B ofc should infer A for B.

All reactions

Sorry, something went wrong.

Uh oh!

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

@jack-williams

Jack Williams (jack-williams) commented Jan 24, 2019

Copy link
Copy Markdown
Collaborator

Yep, you're right. I guess it could infer U = not string?

All reactions

Sorry, something went wrong.

Uh oh!

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

@RyanCavanaugh Ryan Cavanaugh (RyanCavanaugh) assigned Wesley Wigham (weswigham) Jan 24, 2019
@jack-williams Jack Williams (jack-williams) mentioned this pull request Jan 24, 2019
Provisional - Add not keyword emacs-typescript/typescript.el#98
Closed
@DanielRosenwasser Daniel Rosenwasser (DanielRosenwasser) mentioned this pull request Jan 25, 2019
Design Meeting Notes, 1/25/2019 #29588
Closed
@jiangshanmeta jiangshan (jiangshanmeta) mentioned this pull request May 10, 2022
TypeScript中为primitive type添加名义类型 jiangshanmeta/jiangshanmeta.github.io#45
Open
@MartinJohns Martin Johns (MartinJohns) mentioned this pull request May 15, 2022
Typeguard not working if checked against Exclude #49118
Closed
@qwelias

Ilia Baryshnikov (qwelias) commented May 15, 2022

Copy link
Copy Markdown

Love coming back to this PR about once or twice a year because of not being able to do something.
Is there a chance to get any update on the state of it?

falfiya, NexZhu, dimitropoulos, whzx5byb, qwtel, yannsartori, nmay231, AlexRMU, andrei27m, cyyynthia, and 7 more reacted with thumbs up emoji IllusionMH and jamiebuilds reacted with thumbs down emoji omril1, dumaron, dead-claudia, wbt, NexZhu, and dimitropoulos reacted with laugh emoji rhengles and jsejcksn reacted with eyes emoji
All reactions
  • 👍 17 reactions
  • 👎 2 reactions
  • 😄 6 reactions
  • 👀 2 reactions

Sorry, something went wrong.

Uh oh!

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

@bradzacher Brad Zacher (bradzacher) mentioned this pull request May 20, 2022
Enhancement: [@typescript-eslint/no-unnecessary-condition] Detect unnecessary comparison to falsy values typescript-eslint/typescript-eslint#5021
Closed
4 tasks done
@k4b7

Kevin Barabash (k4b7) commented May 24, 2022

Copy link
Copy Markdown

Would support for negated types make type inference involving conditional types easier and/or more powerful?

All reactions

Sorry, something went wrong.

Uh oh!

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

@sandersn

Nathan Shively-Sanders (sandersn) commented May 24, 2022

Copy link
Copy Markdown
Member

This experiment is pretty old, so I'm going to close it to reduce the number of open PRs.

duhaime, truemogician, msakrejda, Vanilagy, nakasyou, CodeF53, and nikolai-tenev reacted with thumbs down emoji omril1, awerlogus, eli-s-r, falfiya, brandones, jsejcksn, bradharms, danielnixon, mscottnelson, ljharb, and 38 more reacted with confused emoji
All reactions
  • 👎 7 reactions
  • 😕 48 reactions

Sorry, something went wrong.

Uh oh!

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

@sandersn Nathan Shively-Sanders (sandersn) closed this May 24, 2022
@jsejcksn

Jesse Jackson (jsejcksn) commented May 24, 2022

Copy link
Copy Markdown

Nathan Shively-Sanders (@sandersn) Is that a "no" to negated types, or will the concept be tracked somewhere else now? If the latter, I'd like to know where so that I can subscribe to the new conversation.

danielnixon, mscottnelson, cherryblossom000, chrisblossom, mnn, eps1lon, rn0, hlysine, MarcusRiemer, lbenard, and 14 more reacted with thumbs up emoji danielnixon, ritschwumm, mscottnelson, cherryblossom000, chrisblossom, whzx5byb, peternedap, jacobwgillespie, aaronccasanova, borgesius, and 2 more reacted with eyes emoji
All reactions
  • 👍 24 reactions
  • 👀 12 reactions

Sorry, something went wrong.

Uh oh!

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

@sandersn

Nathan Shively-Sanders (sandersn) commented May 25, 2022

Copy link
Copy Markdown
Member

Not "no", but discussion should happen on an issue, #4196 probably, instead of a PR. PRs go stale.

harry0000, brandones, Stephen-ONeil, cherryblossom000, jacobq, and qzb reacted with thumbs up emoji harry0000 reacted with rocket emoji
All reactions
  • 👍 6 reactions
  • 🚀 1 reaction

Sorry, something went wrong.

Uh oh!

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

@weswigham

Wesley Wigham (weswigham) commented May 25, 2022 •
edited
Loading

Uh oh!

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

Copy link
Copy Markdown
Member Author

(Though admittedly the proposal in the PR description is admittedly way more concrete and detailed than anything in that issue rn, and the blockers for this are less about the syntax and behavior and more about implementation and performance + language complexity concerns, all of which are more tied to this PR specifically than the original idea)

haltcase, ljharb, ITenthusiasm, jsejcksn, brandones, Methuselah96, wbt, saghen, btoo, qwtel, and 13 more reacted with thumbs up emoji
All reactions
  • 👍 23 reactions

Sorry, something went wrong.

Uh oh!

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

@dimitropoulos

Dimitri Mitropoulos (dimitropoulos) commented Jun 1, 2022

Copy link
Copy Markdown
Contributor

while I certainly can relate to wanting to keep the PR count down to a manageable number (we have the same problem over on insomnia), I would like to echo the above from Wesley Wigham (@weswigham). I've been following this conversation very closely for years, since it and #29729 are the two features I am the most interested in.

I guess at the end of the day as long as this PR isn't locked we can all keep talking here, but it'd be fantastic to have a better understanding of what needs to happen next for negated types to rise-the-ranks a little in the prioritization. I don't want to spam iteration plans (e.g. #49074) with my wants-and-needs... but I'm not sure what else to do at this point.

I hit the need for negated types on a weekly basis. Should I just drop those use-cases in here whenever I hit them?

evelant, whzx5byb, fsenart, ritschwumm, falfiya, ExE-Boss, WetCouch, dakt, hardworker, 04anubhavv, and 4 more reacted with thumbs up emoji
All reactions
  • 👍 14 reactions

Sorry, something went wrong.

Uh oh!

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

@sandersn

Nathan Shively-Sanders (sandersn) commented Jun 1, 2022

Copy link
Copy Markdown
Member

Dimitri Mitropoulos (@dimitropoulos) #49220 addresses the scenario in #29729 in a different way.

dimitropoulos 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.

@falfiya

falfia falfiya (falfiya) commented Jun 7, 2022

Copy link
Copy Markdown

Thanks for mentioning #49220. I didn't even know I had this problem till I read it. What I'm hearing is that I should follow future discussion of negated types in #4196? They'd be absolutely wonderful to have for stuff like "number without NaN".

All reactions

Sorry, something went wrong.

Uh oh!

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

@fatcerberus Bruce Pascoe (fatcerberus) mentioned this pull request Jun 11, 2022
Inconsistent property type inference #49463
Closed
@sindresorhus Sindre Sorhus (sindresorhus) mentioned this pull request Jul 7, 2022
Add Not<string, 'not me'> sindresorhus/type-fest#417
Closed
@jamiebuilds Jamie Kyle (jamiebuilds) mentioned this pull request Jul 12, 2022
Template strings: Negated match #49867
Open
5 tasks done
@MartinJohns Martin Johns (MartinJohns) mentioned this pull request Oct 12, 2022
Support open-ended unions #26277
Open
4 tasks done
@MartinJohns Martin Johns (MartinJohns) mentioned this pull request Dec 19, 2022
Allow to remove keys from index type #51952
Closed
5 tasks done
@sacru2red sacru2red (sacru2red) mentioned this pull request Jan 3, 2023
allow constructing URLSearchParams directly from FormData #30584
Closed
@gvergnaud Gabriel Vergnaud (gvergnaud) mentioned this pull request Jan 22, 2023
.with and Pattern.not error since 4.1.3 gvergnaud/ts-pattern#138
Closed
@MartinJohns Martin Johns (MartinJohns) mentioned this pull request Mar 30, 2023
Exclude is bottlenecked by depth limit #53583
Closed
@gismya Lars Johansson (gismya) mentioned this pull request Apr 4, 2023
fix: bug in typings after recent PR ftrackhq/ftrack-javascript#95
Merged
4 tasks done
@0-CAT Zero Cat (0-CAT) mentioned this pull request Jun 1, 2023
Add XMP raw string type to ExpandedTags["xmp"] type mattiasw/ExifReader#197
Merged
@Autumn-one Autumn-one mentioned this pull request Jul 13, 2023
Supporting negative types is very convenient #55000
Closed
5 tasks
@Autumn-one

Autumn-one commented Jul 13, 2023

Copy link
Copy Markdown

Why was such a basic and important feature rejected for a type system? That's a pity!

strblr, Autumn-one, rhengles, Vanilagy, aziz512, adueck, crowbait, GulgDev, and nikolai-tenev reacted with thumbs up emoji IllusionMH, MartinJohns, danielfalk, gustavohenke, and dead-claudia reacted with thumbs down emoji omril1 and aziz512 reacted with confused emoji
All reactions
  • 👍 9 reactions
  • 👎 5 reactions
  • 😕 2 reactions

Sorry, something went wrong.

Uh oh!

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

@MartinJohns

Martin Johns (MartinJohns) commented Jul 13, 2023

Copy link
Copy Markdown
Contributor

Autumn-one It wasn't rejected, the issue is still open: #4196

As to why it's not implemented yet? Priorities, time constraints, language constraints, limited resources. Feel free to fork the TypeScript repo and try to implement it, you'll see that it's not an easy task.

omril1, rhysd, dead-claudia, romelperez, Offroaders123, lgenzelis, and GulgDev reacted with thumbs up emoji
All reactions
  • 👍 7 reactions

Sorry, something went wrong.

Uh oh!

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

@fatcerberus Bruce Pascoe (fatcerberus) mentioned this pull request Aug 2, 2023
Partially discriminated union with explicitly defined key loosens inferred type #55239
Closed
@k4b7 Kevin Barabash (k4b7) mentioned this pull request Dec 17, 2023
Negation types escalier-lang/escalier-fsharp#75
Open
@aaditmshah Aadit M Shah (aaditmshah) mentioned this pull request Feb 4, 2024
Intersection of conditional types, acting on a generic type, with another type doesn't narrow the generic type #57246
Closed
@microsoft Microsoft (microsoft) locked as resolved and limited conversation to collaborators Oct 21, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Reviewers

@DanielRosenwasser Daniel Rosenwasser (DanielRosenwasser) DanielRosenwasser left review comments
@sandersn Nathan Shively-Sanders (sandersn) Awaiting requested review from sandersn
@rbuckton Ron Buckton (rbuckton) Awaiting requested review from rbuckton
@ahejlsberg Anders Hejlsberg (ahejlsberg) Awaiting requested review from ahejlsberg
+3 more reviewers
@peter-leonov Peter Leonov (peter-leonov) peter-leonov left review comments
@jack-williams Jack Williams (jack-williams) jack-williams left review comments
@prashantpatare Prashant Patare (prashantpatare) prashantpatare left review comments
Reviewers whose approvals may not affect merge requirements

Uh oh!

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

Assignees

@weswigham Wesley Wigham (weswigham)

Labels

Author: Team Experiment A fork with an experimental idea which might not make it into master typescript@experimental Pull requests tagged with this label are automatically rebased together with master and published

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Conditional type doesn't narrow primitive types

Uh oh!

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

20 participants

@weswigham @DanielRosenwasser @Jessidhia @jack-williams @SalathielGenese @felixfbecker @ethanresnick @be5invis @dead-claudia @Richiban @pelotom @ExE-Boss @jvanbruegge @jcalz @markusjohnsson @mheiber @k4b7 @ajafff @typescript-bot @Jack-Works
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.