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

Design Meeting Notes, 5/13/2022 #49137

Closed
DanielRosenwasser opened this issue May 16, 2022 · 0 comments
Closed

Design Meeting Notes, 5/13/2022 #49137

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

Comments

@DanielRosenwasser
Copy link
Member

Limiting Type Argument Inference from Binding Patterns

#49086

declare function f<T>(): T;

// Inference from binding patterns makes suspicious code like this work.
const { foo } = f(); // T: { foo: any }

// Motivation
declare function pick<T, K extends keyof T>(keys: K[], obj?: T): Pick<T, K>;
const _ = pick(["b"], { a: "a", b: "b", }); // T = "b"
const {} = pick(["b"], { a: "a", b: "b", }); // T = "b" | "a" (!?) (before fix)
  • Arguably, these anys should be implicit anys that get an error under noImplicitAny.

  • Inference from return types is generally suspicious, but binding patterns are kind of in the same domain.

  • Idea last time: binding patterns are useful for tuples, but not objects.

    declare function f<T>(cb: () => T): T;
    const [e1, e2, e3] = f(() => [1, "hi", true]);
    • But then

      declare function f<T>(): T;
      const [foo] = f(); // ?
  • So when does an object binding pattern provide a useful contextual type?

    • If the binding pattern has a default.

    • For literals it seems useless.

    • More complex defaults?

      // Union of literals
      declare const oneOrZero: 0 | 1;
      const { b = oneOrZero } = f({ b: 0 });
      
      // Contextually sensitive parameters
      function doSomething(x: string): string;
      const { func = doSomething } = f({ func: x => x });
  • Is this another level of inference priority?

    • No, we just have two sets of inference contexts.
  • Conclusion: do it, get reviewed

Narrowing Type Parameters (un)Constrained to unknown

#49091
#49119

function deepEquals<T extends unknown>(a: T, b: T): boolean {
    if (typeof a !== 'object' || typeof b !== 'object' || !a || !b) {
        return false;
    }
    if (Array.isArray(a) || Array.isArray(b)) {
        return false;
    }
    if (Object.keys(a).length !== Object.keys(b).length) { // Error here
        return false;
    }
    return true;
}
  • Given someUnknown: unknown, typeof someUnknown === "object today narrows to object | null, but it doesn't narrow a T extends unknown
  • Added some changes to do this, then added some changes so keyof NonNullable<T>keyof T succeeds.
    • Needed this when you index into these types, you need to preserve new behavior on higher order NonNullable<T> that you get (rather than on the previous T).
  • Have a parallel effort to improve how intersections with {} operate - could unlock the same scenarios.
    • Ideally, NonNullable<T> would just be T & {}, especially because intersections compose way better than conditional types.
    • With more aggressive subtype supertype reduction with {}, we can get there.
    • Also, need to be able to allow unknown to be split between object, null, undefined, and {} and remerged in CFA.
  • Can we do this without more aggressive subtype reduction?
    • Actually, this isn't doing more aggressive subtype reduction, it's just supertype reduction.
    • [[Above notes now reflect this]]
  • Two approaches here, one focuses on the negative cases, the other on the positive cases.
    • Both apply new narrowing
    • Each PR has different "fallout", and has mitigations for the fallout.
  • Conclusion: See if we can smush these changes together and take the best of each?
@DanielRosenwasser DanielRosenwasser added the Design Notes Notes from our design meetings label May 16, 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