Skip to content

Design Meeting Notes, 7/28/2023 #55188

Closed
Closed
@DanielRosenwasser

Description

@DanielRosenwasser

Allowing Calls Ending with Unions

#55185

  • Today, you can already spread in a value that's a tuple when performing a call.
  • Naturally, the next step is to make this work for tuples as well.
  • In the example in Error when spreading a union of tuples in a call #42508, the right fix is to switch the signature to take a: number, b: number, c?: number instead of two signatures.
    • May not be in control of the signature.
  • This approach just tries to create a new "combined" tuple for the effective argument list.
    • So [number, number] | [string, number] becomes [number, string | number].
  • Technically this is conservative. Won't work for [number, number] | [string, string].
  • Internals get gnarly. Have to funnel around more information about the minimum argument count that might be passed in.
  • Ideally we could try out multiple signatures. However, architecturally TypeScript assumes it can assign types for symbols once and never again, and this is a large boulder to move. It's been a long-standing problem in the compiler. But also, doing so could cause us to do a lot of work.
    • Stack of PRs before that's reasonable for us to do.
    • [[Meta: What's the canonical issue for this?]]

Covariance breaks when checking for undefined in a type

#55161

  • We use the identity relation when comparing Ts in Foo extends T ? A : B to figure out variance here.
    • In type Setter<T> = undefined extends T ? () => undefined : {};, we decide that T is invariant.
    • Transitively, U is invariant in type Test<U> = { 0: Setter<U> }; which is undesirable. Direct structural instantiation will often permit types.
  • We have a PR that fixes this by marking T as unmeasurable (Mark conditional extends as Unmeasurable and use a conditional-opaque wildcard for type erasure #43887)
    • Breaks things...
    • Makes things slower too because we can't trust variance measurements...
  • Falling back to structural checking is very very slow.
  • We also have anecdotally seen types that rely on the fact that TypeScript uses the identity relationship to compare conditional types in this way.
  • Had a PR from @Andarist which introduced new variance measurement types which saved some work - basically signaled "unmeasurable" but require the identity relationship.
    • Basically in the example, variance of T in Setter is marked as a special type of unmeasurable. Instances of Setter would be compared in an invariant manner; however, any variance checks for type parameters that are fed into Setter (i.e. U) are marked as unmeasurable.
    • Still might end up in structural checks anyway.
  • Feels like at that point, might as well just mark as unmeasurable.
  • Just had to do a revert of correctly marking types as Unreliable, but not of Unmeasurable.
  • We need Better Variance™️?
  • It's not great, but maybe it's okay to be more conservative?
    • Not just a matter of being more conservative. In our type system, conditional types can make choice; but they may make choices based on incorrect variance checks.
  • Can defeat this with an Evaluate alias.
  • If we had a better way to do structural checking more efficiently, that would allow us to fix these issues up.
  • Conclusion:
    • We don't know!
    • We want a running list of places where variance is measured incorrectly.

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