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, 12/8/2017 #20724

Closed
DanielRosenwasser opened this issue Dec 15, 2017 · 0 comments
Closed

Design Meeting Notes, 12/8/2017 #20724

DanielRosenwasser opened this issue Dec 15, 2017 · 0 comments
Labels
Design Notes Notes from our design meetings

Comments

@DanielRosenwasser
Copy link
Member

DanielRosenwasser commented Dec 15, 2017

in operators as a type guard

interface Foo {
    abc: number;
}

interface Bar {
    def: string;
}

declare let x: Foo | Bar;

if ("abc" in x) {
    x // Foo
}
else {
    x // Bar
}
  • Since types are open, in the true branch/then branch of the if, it"s not appropriate to say that the x couldn't be a Bar.
    • But we already have this behavior for property access expressions, and most of the time these things are intent-based.
  • Introduces a break to RxJS
  • Conclusion
    • 👍
    • Document that it's a breaking change.

The override keyword

#2000
#13217

  • Without flag, feature is not extremely useful.
  • What about .d.ts files?
    • Would users need overrride
  • Allow users to use override when flag is off.
  • With a flag, it's an error to not use override.
  • Would it go in --strict?
    • Not certain if it feels appropriate.
  • Generally, team feels ambivalent about whether the feature pays for its own complexity.
  • Marked as Accepting PRs last year.
    • Need to be discuss things more in depth before we decide these things.
  • Conclusion: can't accept at this time, would like to think more about annotations after decorators reach stage 3.

Conditional Types

#12424

  • New type operator: T extends U ? X : Y

    • Breaks T does to its union constituents (or T itself if not a union), checks if each of those types is assignable to U.
      • When assignable, you get X, otherwise Y.
    • If T is not known, the type remains unevaluated.
    • Have been back and forth as to whether if T is a union, this distributes over the union.
      • In general, distributing over Tseems to make the most sense.
  • Can make some handy types!

    type Diff<T, U> = T extends U ? never : T;
    
    type TypeName<T> = 
        T extends string ? "string" :
        T extends number ? "number" :
        T extends boolean ? "boolean" :
        T extends undefined ? "undefined" :
        T extends Function ? "function" :
        T extends string ? "string" :
        "object";
    
    type NonNullable<T> = Diff<T, null | undefined>;
    
    type DeepReadonly<T> = T extends object ?
        { readonly [P in keyof T]: DeepReadonly<T[P]> } :
        T;
    
    // Type: "a" | "d"
    type T0 = Diff<"a" | "b" | "c" | "d", "b" | "c">;
    
    // Type: "string" | "function"
    type T1 = TypeName<string | (() => void)>;
    
    // Type: string | number
    type T2 = Diff<string | number | (() => void), Function>;
    
    
    function f1<T>(x: T, y: NonNullable<T>) {
        x = y;
        y = x;
    }
  • How do these interact with any and never?

    • any gives both branches of the conditional.
    • never gives never.
  • Question: Should T extends U be a separate type operator from X ? Y : Z?

  • Should we have && operators as well?`

  • If we did that, it introduces some more syntactical ambiguity.

    • Currently we deal with this by saying "the ambiguities are rare for any useful code.
    • But f<T && U>(5), while a strange way to write f < T && U > 5, feels odd.
    • f<T && U>
  • What about inference for a given branch?

    • A new infer operator?
    • Maybe something like type ReturnTypeOf<T> = from T infer R in (...args: any[]) => R: R
      • Note: would need a constraint on T like (...args: any[]) => R.
    • Then could deconstruct types anywhere?
  • Why did we move away from thinking about match types?

    • Kind of a "Swiss army knife" that does many things.
    • Has curlies which can confuse folks that might think it ends up being an object type.
    • Evaluation order might not be totally obvious to users, whereas conditionals are more explicit about order.
  • Does this give you the awaited type?

    • No.
      • Why not?
        • Evaluation of type aliases is eager, making them lazy would be difficult.
        • But if the type acted on isn't concrete, aren't we deferring evaluation anyway?
        • Maybe it does.
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

1 participant