Skip to content

Design Meeting Notes, 2/9/2018 #21838

@DanielRosenwasser

Description

@DanielRosenwasser

Type Operators

  • Not crazy about giving these things names that people've been using.

  • Not crazy about Diff

    • Semantics are fuzzy between "union member" diff and "object member" diff.
  • Ideas

    • Diff -> Exclude
    • Filter -> Extract
      • "This reminds me of Ruby's inject etc. where I don't know what any of the methods actually do."
    • ReturnType sticks around
    • InstanceType is the new "whatever this constructs"

Example:

type NonNullable<T> = Exclude<T, null | undefined>

By the way you can do some crazy stuff.

type JsonifiedObject<T extends object> = { [K in keyof T]: Jsonified<T[K]> };
type Jsonified<T> =
    T extends string | number | boolean | null ? T
    : T extends undefined | Function ? undefined
    : T extends { toJSON(): infer R } ? R
    : T extends object ? JsonfifiedObject<T>
    : "wat";

"Recursive" Conditional Types

Start off with the way that await unboxes Promises to their wrapped type.

type Awaited<T> = T extends Promise<infer R> ? R : T;

Problem: await keeps unwrapping until it gets something that isn't then-able.

You kind of want this:

type Awaited<T> = while T extends Promise<infer R> ? R : T;

or this:

type Awaited<T> = T extends Promise<infer R> ? Awaited<R> : T;

More awaited work

What about this?

type Awaited<T> =
    T extends { then(onfulfilled: (value: infer U) => any): any } ? U :
    T extends { then(...args: any[]): any } ? never : T

Then we modify the definition of Promise to something like this:

interface Promise {
    then<TResult1, TResult2>(
        onFulfilled: (value: Awaited<T>) => TResult1,
        onRejected:  (err: any) => TResult2):
            Promise<Awaited<TResult1 | TResult2>>
}

This almost works!
But there's a problem.
Because the type system doesn't know how to relate an arbitrary T to an Awaited<T> (and vice-versa).
Even if we had the "while types"/recursive conditional types, we'd have the same general problem unless we could think of a general way to handle this.

Resolve JSX namespaces from their factories

#18131

  • What is the motivating scenario?
    • Well there should be nothing preventing you from using multiple versions of React most of the time.
  • But we have this problem with Node.
    • But you only have one runtime environment; you can have multiple versions of React at runtime.
  • [[Something about UMD]]
    • What happens when you have multiple versions of UMD globals that come from different packages?
  • Also, we want to make JSX not global given the next issue...
  • Conclusion: Do this, fall back to a global JSX if nothing is available.

Decoupling JSX.Element from JSX expression return types.

#21699

  • Also, using the JSX namespace is currently being used for too many things!
    • JSX expressions don't always return the type specified by JSX.Element.
  • But people are now depending on this.
  • Conclusion: Do this.

Per-file JSX emit

#21218

  • Do we want a comment?
    • It's the way Babel does it; why be different for no reason?
  • Conclusion: do this.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Design NotesNotes from our design meetings

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions