Skip to content

Design Meeting Notes, 3/23/2022 #48684

Closed
Closed

Description

satisfies Operator

#47920
#46827

  • Most recent change involves the contextual type of the expression being the intersection of the outer contextual type and the type being checked for satisfaction.
  • Have to be careful - there are places where we don't always create intersections because it's not always desirable to do this.
    • instanceof might do something similar here?
  • Intersections? For things with methods? That will produce overload methods?
    • That can lead to a "bad" contextual type occasionally.

    • Especially generic methods (e.g. array methods)

      interface Movable1 {
          move<U>(distance: U, b: boolean): void;
      }
      
      interface Movable2 {
          move<T, U>(distance: T, b: boolean): void;
      }
      
      const danger: Movable1 & Movable2 = {
          move(s) {
      
          }
      }
  • Do you always want to use the satisfies type before the outer type?
    • We sort of do something like this for destructuring.
  • How does this work for nested satisfies?
    • "I want to satisfy these three interfaces?"
    • Do these stack? How?
    • Is this like implements?
      • Why aren't we doing implements again?
      • Possible future ECMAScript proposals.
  • Inside-to-outside seems pretty intuitive for a lot of usage.
  • We really don't want to create a new typing context.
  • Why did we need to try the intersection type?
    • Feels like many of these cases are motivated by index signatures.

extends on infer in Conditional Types

#48112

  • When we see a ? after an extends SomeType, we always have to assume that we're about to start parsing a conditional type on the right.
  • We do look-ahead, and we also need to intentionally parenthesize these cases.
  • Basically "if there's a question mark following, then you're parsing a conditional type, not
  • Is this just for template literals?
    • No, lots of stuff where we have to have nested conditional types to test on an extracted type.
  • Seems reasonable.

Inferring More Specific Types for Template Constraints

#48094

  • Want to be able to parse out round-trippable JS strings.
  • Added some logic to do this, and can take advantage with implicit bounds with a type helper called Is
  • Prioritized list - if you have a type variable bounded by number | bigint, first try to parse out number. If that isn't round-trippable, try to parse out bigint.

Contextually Typing Boolean Literals

#48363
#48380

type Box<T> = {
    get: () => T;
    set: (x: T) => void;
};

declare function box<T>(x: T): Box<T>;

// okay, Box<number>
const a = box(0);

// okay, Box<number>, `0` gets contextually typed but doesn't make a difference.
const b: Box<number> = box(0);


// okay, Box<boolean>
const c = box(false);

// error!?
// `false` gets contextually typed by `boolean` which is `true | false`
// which makes the type of the extression `false` be the type `false`.
// That means we try to see if the type `Box<false>` is assignable to `Box<boolean>`,
// and it's not because `Box` is assignability is invariant on `T`.
const d: Box<boolean> = box(false);
  • First idea (Widen boolean literals when contextual type is full boolean type #48368): if you're contextually typed by both true and false, then widen to boolean.
    • But you can be contextually typed by boolean because types of properties merge.
  • New idea - if we get a boolean inference from a return type, remove it from the instantiated contextual type, remove it.
  • Very narrow fix for just booleans - but doesn't work for other types. For example, const x: Box<0 | 1> = box(0).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

No one assigned

    Labels

    Design NotesNotes from our design meetings

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions