Skip to content

Design Meeting Notes, 9/9/2016 #10826

Closed
Closed
@DanielRosenwasser

Description

@DanielRosenwasser

Always Infer Literal Types (#6554, #10676)

Basics

  • Based on complaints we've seen in the past about how literals don't "stick" for const

    // Type has type 'string' instead of '"hello"'
    const x = "hello";
  • Idea: the literal 1 should always start out with the type 1.

    • No more literal type locations.
    • In a read-only location, a literal type will keep its type.
    • In a mutable location, a literal type will gain its base primitive type, unless it has a contextual type.
  • Every literal type has a base primitive type.

Changes to Function Return Type Inference

  • Other change is that multiple return statements always return a union of each returned type.
  • For a singleton literal type, widen to the base primitive type.
    • Rationale - definitely no point to inferring a singleton. Arguable whether you want the same behavior on unions.

Changes to Type Argument Inference

For a type parameter T, a literal type argument will be inferred for T if

  • T is inferred from "top-level" occurrences (allows widening to take place later on).
  • T has no primitive/literal constraint (user wanted it).
  • T does not occur at the "top-level" in the return type (more complicated reasons).

Substitute Value of super() For this (#7574, #10762)

Summary:

  • Not pretty.
  • Not that bad.
  • Perf numbers aren't much worse.

👍

@mhegazy notes:

  • Issue: Return value of super() calls not used for this #7574
  • PR: Use returned values from super calls as 'this' #10762
  • ES6 semantics for inheritance indicates that the result of calling super becomes the new this
  • This is why this cannot be used before super is called.
  • perf tests on the generated output seems to be on par with the previous emit, no major slowdowns
  • This does not completely handle cases requiring new.target e.g. extending Array and Error
  • The output is not as clean as it was. but not different from capture of this in arrow functions
  • 👍

keysof Operator (#1295, #10425)

Libraries like Ember, Backbone, and Immutable all use string literals to access properties.

Idea keysof T: a "keys query", which returns a union of literal types for each property in T.
Following this, you could have T[K] which, when K is a literal type, returns the type of a property with the name K on T.

function get<T, K extends keysof T>(obj: T, key: K): T[K] {
    obj[key];
}

// Returns 'string'
get({name: "Daniel" }, "name");

// Error: '{ name: string }' has no property named 'nmae'.
get({name: "Daniel" }, "nmae");
  • Question: Why doesn't key just have the type keysof T?
    • Because if T was something like { name: string; age: number }, then keysof T would be "name" | "age".
      Even if you pass in "name" for key, the type system keeps the type as "name" | "age".
      That means the return type will be T["name" | "number"].
      In reality, you want to grab the specific literal "name" to do a query.
      • We could do the "right thing", but that'd require an implicit type parameter, which would get complicated.

Caveats: any object contxtually typed with a string index signature will have keysof effectively return string on it.

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