Skip to content

Design Meeting Notes, 8/26/2016 #10566

@DanielRosenwasser

Description

@DanielRosenwasser

Expanded Inference (Open & Expando Style Types)

There's lots of code out there that has no type annotations at all, no initializers, starts out as an empty object.
That's mostly existing JavaScript code.
Anders has been working on using CFA to track types completely in certain situations.

function foo() {
    let x;
    if (!!true) {
        x = 1;
    }
    else {
        x = "hello";
    }
    x; // has type 'number | string'
}

This works pretty well if we have an accurate picture of the control flow graph; however, you can't model this that well if these variables are captured in another function.
For instance:

function foo() {
    let x;
    if (!!true) {
        x = 1;
    }
    else {
        x = "hello";
    }
    x; // has type 'number | string'

    function captor() {
        x; // implicitly has type 'any'.
    }
}

That means that 'any' has a much more limited scope of being implicitly introduced.

This makes Salsa way more powerful!

Expando Objects

Expando is a (somewhat documented) feature and pattern in JS where you can continue tacking properties on to objects after their creation.

In certain sites, we can decide that an object is meant to be created as an "expando" type.
For instance, how useful is the type {} on its own?
The answer is "not very useful" (unless you're just using it for object identity), so we can build up the type as you assign properties to that object.

let x = {};      // after this, 'x' has type '{}'
x.a = 1;         // after this, 'x' has type '{ a: number }'
x.b = {};        // after this, 'x' has type '{ a: number; b: {} }'
x.b.y = "hello"; // after this, 'x' has type '{ a: number; b: { y: string} }'
x;               // 'x' has type '{ a: number; b: { y: string} }' here.

Every occurrence of x above has its own type.

Side note: This is widely used and the VS JS language service lost out a lot on this in switching to Salsa.
Both TypeScript and the Salsa JS LS would get this for free.

Q: Does this work for element access expressions?
A: No, haven't worked that far yet.

Q: Could we do this sort of thing for this in constructors?
A: Potentially very bad experience - what happens if users set a value to undefined? It's worth experimenting with though.

Q: Does this work for aliasing?
A: No, alias tracking would get pretty messy.

Expanded Array Element Inference

What about arrays?

This hasn't been implemented yet, but we have some ideas here.
Look for locations in which the array is added to (indexing, push, unshift).

let x = [];
x[0] = 4;        // 'x' has type 'number[]'
x.push("hello"); // 'x' has type '(number | string)[]'

Changes of Inference

General discussion about why an initializer is different from a deferred initialization.

Questions about inferring literal types, concerns about breaking changes.

tsconfig.json Inheritance

  • "Is there a reason why we wouldn't?"
  • "No."
  • "Then why don't we do it?"
  • Open questions (duh!).

Merge or Overwrite?

Overwrite.

Multiple or Single Inheritance

Everyone: "SINGLE."

That was easy.

Object Literal Rest & Spread

let x = { a: 0, b: "hi" };
let y = { a: true};

// This is equivalent to 'Object.assign({}, x, {a: 2 }, y)'
let z = {
    ...x,
    a: 2,
    ...y
};

// Ideally, has type '{ a: boolean, b: string }'
z;

Problem: Object.assign gives an intersection of its types.

Easy to do when types aren't generic.
But what if they are?

// What is the return type here?
function merge<T, U>(o: T, ext: U) {
    return {...o, ...ext};
}

Idea: new type operator like {...T, ...U}

Q: What about if U has an optional property that exists in T?
A: Probably union the types of each property.

Enumerable & Own Properties

class C {
    a = 0;
    b = "stuff";
    method() {
    }
}

let c = new C();
let d = { ...c };

Problem is that d doesn't get method because it's not enumerable or an own-property.
We'd need a new modifier in type members.

"Optionalization"

function setState<T>(o: T, ext: optional T) {
    return {...o, ...ext};
}

There are often scenarios where you want to create a type with optional portions.
Not a lot of time to discuss this today.

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