Skip to content

Design Meeting Notes, 7/22/2022 #50008

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

Closed
DanielRosenwasser opened this issue Jul 22, 2022 · 0 comments
Closed

Design Meeting Notes, 7/22/2022 #50008

DanielRosenwasser opened this issue Jul 22, 2022 · 0 comments
Labels
Design Notes Notes from our design meetings

Comments

@DanielRosenwasser
Copy link
Member

Inference Change Between Unions of undefined

#49938

Lots of examples

Here's a minimal break.

type B = { foo: string, };
type D = { foo: string, bar: number };

declare function equals<T>(a: T, b: T): boolean;

function f(b: B, d: D | undefined) {
    // Used to work, now infers `B` and fails.
    if (equals(b, d)) {

    }
}

Playground link

Narrowing Changes Against Top-ish Types

#49988

  • The isMap type predicate now narrows values to a Map<...> | ReadonlyMap<...> instead of Map<...> if that's what you already had.

  • Introduced by Improve narrowing logic for instanceof, type predicate functions, and assertion functions #49625

  • Start with this example.

    type Falsy = false | 0 | 0n | '' | null | undefined;
    
    declare function isFalsy(value: unknown): value is Falsy;
    
    function fx1(x: string | number | undefined) {
        if (isFalsy(x)) {
            x;  // "" | 0 | undefined, previously undefined
        }
    }
  • But people depend on the old behavior.

  • This is now different

    declare function isMap<T>(object: T | {}): object is T extends ReadonlyMap<any, any> ? (unknown extends T ? never : ReadonlyMap<any, any>) : Map<unknown, unknown>;
    declare const romor: ReadonlyMap<any, any> | Record<any, any>
    if (isMap(romor)) {
        romor; // Previously `ReadonlyMap<any, any>`, now `ReadonlyMap<any, any> | Map<any, any>`
    }
  • But ReadonlyMap<...> | Map<...> just provides all the same methods as ReadonlyMap<...>.

    • Are they sufficiently identical between their methods?
    • Often these signatures are not, which makes them effectively uncallable.
    • We think yes.
  • The isObject case is worse.

    • Previous behavior was weird! (see playground)

      declare function isObject(value: unknown): value is Record<string, unknown>;
      
      function f1(obj: {}) {
          if (isObject(obj)) {
              // Worked, obj is narrowed to Record<string, unknown>
              obj["stuff"]
          }
      }
      
      function f2(obj: {} | undefined) {
          if (isObject(obj)) {
              // Doesn't work obj is not narrowed.
              obj["stuff"]
          }
      }
    • Now neither example works. (see playground)

    • Will need to think through these.

  • WeakRef example

    • Very incorrect. T is never witnessed, and WeakRef is supposed to be a proxy around T itself.
@DanielRosenwasser DanielRosenwasser added the Design Notes Notes from our design meetings label Jul 22, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Design Notes Notes from our design meetings
Projects
None yet
Development

No branches or pull requests

2 participants