Skip to content

Design Meeting Notes, 1/19/2018 #21307

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

Closed
DanielRosenwasser opened this issue Jan 19, 2018 · 0 comments
Closed

Design Meeting Notes, 1/19/2018 #21307

DanielRosenwasser opened this issue Jan 19, 2018 · 0 comments
Labels
Design Notes Notes from our design meetings

Comments

@DanielRosenwasser
Copy link
Member

Conditional Types

  • Last time, we needed an idea of when to defer the evaluation of each branch of a conditional type.
  • Idea:
    • spread over unions, if you have any or never, you create a union (since you have no idea where anything will go)
    • If the type is assignable, go to the true branch's type.
    • Otherwise, check whether the type is not possibly assignable, then go to the false branch's type.
      • Type parameters imply the possibility of assignability - erase them to any.
        • What about never instead of any?
          • any works better for contravariant positions.
      • Uses typeMaybeAssignableTo which is like comparability but only at the top-level.
        • Should probably be a new type relationship.
        • Why not use comparability?
          • Ehh, not quite the same.
    • What happens when you can't make a definitive statement about either case?
      • We have to put in some new concepts of how to relate these types.
  • Also: new internal type called a substitution type.
    • In T extends string ? [[A]] : [[B]], you want A to act as something that is also a string in [[A]].
type Diff<T, U> = T extends U ? never: T

Core idea here is that in each branch, once the condition can be "evaluated", T is re-bound to each constituent if the original T was instantiated with a union type.

Means that

interface Box<T> {
    element: T;
}

type BoxEverything<T> = T extends any ? Box<T> : never;

// Same as 'Box<number> | Box<string> | Box<boolean>'.
type Foo = BoxEverything<number | string | boolean>;
  • Should T refer to the original type, or just the constituents?

    • Well, we could say that users need to make distribution over unions explicit.
    • Would need a syntax for iteration over unions.
      • P in T: P extends U ? P : never
    • We've very rarely not wanted the current behavior that automatically distributes over unions.
  • Seems like we want to do this!

    • Types continue operating on the principle of distributing over unions. We should find ways to communicate this to our users.
    • But wanting mapping, seems like we'd want to
  • Do we want to add the helpers to the standard library?

    • Definitely Diff.
      • But it doesn't actually have the ability to negate assignability.
    • What about If, Not, And, and Or?
      • "Yeah, but who's gonna use them?"
        • "Uhh...", [[collective laughter implying that somebody will use these for something crazy]]
      • What about NonNullable?
        • That leads us to the next topic.

Narrowing type parameter constraints

#21182

  • Want to narrow the constraint of a type parameter from number | undefined to number.
    • Conclusion: Experiment with offline.

Variadic Types

  • 13 minutes left in the design meeting, we can't reasonably go over this.

Optionality: missing and undefined

  • Comes up very frequently in React's setState API.

    • Users say "you should be able to pass in a subset of the properties in T (i.e. Partial<T>, meaning T but all optional) but you shouldn't be able to pass in undefined.
    • Currently the type system doesn't know how to differentiate these cases.
  • Today, the type hierarchy looks something vaguely like

            any
        /    |    \
       {}  null undefined
    
  • Could imagine a new subtype of undefined called missing!

            any
        /    |    \
       {}  null undefined
                    |
                missing
    
  • undefined is not assignable to missing, but the opposite is true.

  • Optionality implies unioning the type with missing.

    interface Foo {
        x?: number; // implicitly has the type 'number | missing'.
    }
  • Note! We don't want any to be assignable to missing!

    • any continues to be the top type (missing is assignable to any...) but is no longer quite the bottom type with respect to assignability (any is not assignable to missing!).
    • never continues to be the true bottom type, assignable to missing and everything else.
  • This would definitely be a breaking change.

    • What would Partial become?
      • Might need an Optionalize or Subset or whatever.
  • What about parameter types?

    • Often need to communicate optionality from a set of parameters to another set of parameters.
@DanielRosenwasser DanielRosenwasser added the Design Notes Notes from our design meetings label Jan 19, 2018
@mhegazy mhegazy closed this as completed Jan 19, 2018
@microsoft microsoft locked and limited conversation to collaborators Jul 3, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Design Notes Notes from our design meetings
Projects
None yet
Development

No branches or pull requests

2 participants