Skip to content

Design Meeting Notes, 8/25/2021 #45577

Description

The Awaited Type in lib.d.ts

#45350

  • When we introduced await into TypeScript, we added some logic to recursively unwrap a type.

  • At the time, we had no recursion mechanism within the type system.

  • First we started out with an awaited type operator.

  • Problem: if you have generics, you end up with higher-order type operators.

    async function f<T>(x: T) {
        await x; // awaited T
    }
    • This is technically correct, but very cumbersome.
    • The problem is that awaited T is not necessarily assignable to T (nor vice versa).
  • Had ideas for a top-level type alias...

  • And that's what we do here, but right now are only introducing the alias to be used in lib.d.ts.

    • Behavior is based on what the await operator does.
  • Preserves the incorrect behavior to avoid errors on awaited T -> T in async functions, but better-models lib.d.ts.

  • Ideally, other overloads take care of the breaks.

  • Does this break existing code?

    • Probably, but question is how much.
    • Have to run our tests.
  • Having Awaited makes sense in general.

  • Worth thinking about whether users will be able to understand how to use this.

  • Should we get rid of the other overloads?

    • Want to try to!
  • Conclusions

    • Need to see what this breaks.
    • Need to see if we can remove overloads.
    • Maybe see if this can be leveraged by await?

--noErasingImportedNames

#44619

  • Current behavior is that if you write an import for something, if you don't use it you lose it.
    • [[How did nobody think of phrasing it that way until now?]]
  • Under this mode, every imported name is preserved if it has a value meaning.
  • Under isolatedModules, it will warn you that some compiler won't know how to drop types.
    • Then the name is a misnomer. It's about dropping values.
    • Great, we can bikeshed this.
  • Who would use this?
  • Useful for
    • Svelte.

      <script>
      import Layout from "./Layout.svelte";
      </script>
      <Layout />
      • TypeScript doesn't see what the transformer does, needs to not drop Layout.
    • Vue

      • Not vanilla Vue SFCs. <script setup>.
      • Similar to Svelte use-case - top-level declarations are implicitly brought into the template code.
  • noErasingImportedNames hard to parse.
    • preserveValueImports
      • "importsNotUsedAsValues": "preserve" 😢

Stack Overflow on Type Instantiation

#45576

  • We increased the type instantiation limit from 50 to 500.
  • How do we know we're about to blow the stack?
    • Nothing we can do?
  • Least common denominator?
    • Changing target, could be dynamic on the browser itself.
  • Can try to guard against these with a try/catch.
    • try/catch at the top of instantiateType?
    • Could, but how do you guard against inconsistent state?
  • Could pre-emptively blow the stack and create a guesstimate from that.
    • [[Think my idea just got laughed down. 😅]]

Activity

  1. awerlogus commented on Aug 26, 2021

    @awerlogus

    Daniel Rosenwasser (@DanielRosenwasser) have you tried to solve the stack overflow problem using trampoline technique?

    const trampoline = f => (...args) => {
      let result = f
      
      do { result = result(...args) }
      while (typeof result === 'function')
        
      return result
    }
    
    const factorial = n => factorialAcc(1n, n)
      
    const factorialAcc = (acc, n) => {
      if (n <= 1) { return acc }
      
      return () => factorialAcc(acc * BigInt(n), n - 1)
    }
    
    const factorialT = trampoline(factorial)
    
    console.log(factorialT(300))

    Performance tests for the large call stack case:

    No trampoline test for factorial(2500):  8.612300038337708 ms
    No trampoline test for factorial(2500):  8.430999994277954 ms
    No trampoline test for factorial(2500):  8.416900038719177 ms
    No trampoline test for factorial(2500):  8.343400001525879 ms
    No trampoline test for factorial(2500):  8.81769996881485 ms
    
    Trampoline test for factorial(2500):  6.159500002861023 ms
    Trampoline test for factorial(2500):  6.034699976444244 ms
    Trampoline test for factorial(2500):  6.161700010299683 ms
    Trampoline test for factorial(2500):  5.963100016117096 ms
    Trampoline test for factorial(2500):  5.686100006103516 ms

    Performance tests for the small call stack case:

    No trampoline test for factorial(100):  0.05640000104904175 ms
    No trampoline test for factorial(100):  0.0591999888420105 ms
    No trampoline test for factorial(100):  0.07770001888275146 ms
    No trampoline test for factorial(100):  0.06279999017715454 ms
    No trampoline test for factorial(100):  0.05779999494552612 ms
    
    Trampoline test for factorial(100):  0.08009999990463257 ms
    Trampoline test for factorial(100):  0.08600002527236938 ms
    Trampoline test for factorial(100):  0.0835999846458435 ms
    Trampoline test for factorial(100):  0.0821000337600708 ms
    Trampoline test for factorial(100):  0.08160001039505005 ms
  2. DanielRosenwasser commented on Aug 26, 2021

    @DanielRosenwasser
    MemberAuthor

    I didn't capture it in the notes but

    1. We raised generators as an option, and the overhead of generators (both down-leveled for ES5, and maintained for ES2015 targets) had a considerable performance hit.
    2. Re-writing with a manual trampoline (as Wesley Wigham (@weswigham) did for other constructs like checking binary operands) is possible, but makes the code harder to maintain and update in our opinion. I don't know if our trampolining works similarly to what you have up there.

    Wesley can correct me if I got any of the details wrong.

  3. weswigham commented on Aug 26, 2021

    @weswigham
    Member

    I mean, our existing trampolines function as state machines rather than recreating closures all the time, but yes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

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