Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # 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 }[]

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
Design Notes Notes from our design meetings
Projects
None yet
Development

No branches or pull requests

2 participants