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/22/2019 #30547

Closed
DanielRosenwasser opened this issue Mar 22, 2019 · 6 comments
Closed

Design Meeting Notes, 3/22/2019 #30547

DanielRosenwasser opened this issue Mar 22, 2019 · 6 comments
Labels
Design Notes Notes from our design meetings

Comments

@DanielRosenwasser
Copy link
Member

Avoiding fixing during inference

  • Requesting the type of a type parameter T for a function expression for contextual typing often "fixes" a type parameter to its constraint {}.
  • Idea: when a function expression needs a contextual type, give the "current" view of the type to get the left side, but don't fix the type.

3.4 Breaks

#30390

  • Not just "we do inference better so we catch more bugs"
    • Maybe this is a larger problem - people really don't mean true | false when we say boolean.
  • Have this implicit assumption that when you have an explicit return type annotation, when you return something that's assignable to that type, it should be "fine".
    • Not true here.
  • The literal types might be defensible. The problem is that we've discarded at least one branch of inference.

#30419

Remove block-scoped bindings from globalThis

#30477
#30510

  • Turns out let and const and class shouldn't show up on this, global, window, or globalThis.
    • Uh oh. That's how it works in master.
    • We've never made a differentiation between
  • Complications
    • We'd also have to change things in the global scope like Object, Number, String back from const to var
    • But you can change them! Why were they ever const?
      • Because you can "technically" do a lot of stuff in an untyped language, but that's not our bar.
  • So how do you express a constant var?
    • const var?
    • readonly var?
    • public static void readonly virtual var?
    • Not 3.4-prioritized.
  • We also down-level const to var.
    • Technically, at runtime you can access
  • Sounds like we should do this today.
  • Also, add a keyof typeof globalThis?

Strictly-typed Generators

#2983

  • First we needed boolean literal types.
  • Then we needed to not break Node so we needed typesVersions.
  • But we'd still hit a big breaking change by changing the type.
  • Started looking into a strictGeneratorTypes so this becomes opt-in
    • Strongly typed return types, and strongly typed yield as well.
    • You can annotate the return type of a generator to be Generator<YieldOutputType, OutputType, NextInputType>
    • yield expressions use contextual types to infer their input type (i.e. what a caller can give when they have .next()).
  • Can we do this without putting it under strict?
  • [[Out of time]]
@DanielRosenwasser DanielRosenwasser added the Design Notes Notes from our design meetings label Mar 22, 2019
@weswigham
Copy link
Member

@ahejlsberg I believe #28445 fits into the category of issues you were looking into for the first part of the design meeting - minimally I can confirm that the code behaves as expected when the contextual type is instantiated with the nonfixing parameter mapper.

@weswigham
Copy link
Member

Also maybe #29775 ? It looks similar (identical?), anyway.

@zen0wu
Copy link

zen0wu commented Apr 2, 2019

Not sure if this is the best place to comment. Apologize if not :)

Super excited about the strictly-typed generator! Just curious, what does yield expressions use contextual types to infer their input type (i.e. what a caller can give when they have .next()) mean? How does it work?

I'm actually thinking about the same thing (if I understand the sentence correctly), where generator can somehow simulate a state machine, where each time a yield is encountered, the NextInputType returning from yield should be somewhat dependent on what was yielded. This would open the door for strongly typing complicated control flow, which is awesome! But I'm having a hard time picturing how that works.

@DanielRosenwasser
Copy link
Member Author

@rbuckton can explain but the idea is that you can pass in values to calls to next(), and the ways in which yield is used will change the values you can pass in.

function* foo() {
  let x: number = yield; // This 'yield' expression is contextually typed as 'number'
  console.log("x is", x);
}

var iterA = foo();
iterA.next(0);   // the first call to 'next()' is ignored, but the argument is type-checked
iterA.next(100); // this argument is also type-checked, and at runtime this logs 'x is 100'

var iterB = foo();
iterB.next("hello"); // error! 'string' is not assignable to 'number'
iterB.next(100);     // error! 'string' is not assignable to 'number'

@rbuckton
Copy link
Member

rbuckton commented Apr 2, 2019

@DanielRosenwasser is correct. Also keep in mind that we will aggregate all of the types used in this way:

function* foo() { // : Generator<undefined, void, A & B>
let x: A = yield;
let y: B = yield;
}

We would have to intersect the provided types as we cannot type a generator in such a way as to "unroll" the types used on each iteration. As a result, what you send into the generator must satisfy all of the possible input values.

@zen0wu
Copy link

zen0wu commented Apr 3, 2019

Thanks guys for responding! I wasn't thinking about the intersection thing, now I get it :)

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

4 participants