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, 3/23/2022 #48684

Closed
DanielRosenwasser opened this issue Apr 13, 2022 · 1 comment
Closed

Design Meeting Notes, 3/23/2022 #48684

DanielRosenwasser opened this issue Apr 13, 2022 · 1 comment
Labels
Design Notes Notes from our design meetings

Comments

@DanielRosenwasser
Copy link
Member

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).
@DanielRosenwasser DanielRosenwasser added the Design Notes Notes from our design meetings label Apr 13, 2022
@Akxe
Copy link

Akxe commented Apr 22, 2022

I am not sure if anyone can write here, but why would the satisfies operator have a need to nest? I thought it was supposed to be used for the declaration; That it is supposed to typecheck the expression to a constrain while preserving the original type;

import { PrismaClient, PostFindManyArgs } from '@prisma/client';

const prisma = new PrismaClient();

export const postQuery = {
  select: {
    title: true,
  },
  where: {
    deleted: { equals: false },
  }
} satisfies PostFindManyArgs as const;

const posts = await prisma.post.findMany(postQuery); // { title: string }[]

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