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, 3/11/2019 #30329

Closed
DanielRosenwasser opened this issue Mar 12, 2019 · 1 comment
Closed

Design Meeting Notes, 3/11/2019 #30329

DanielRosenwasser opened this issue Mar 12, 2019 · 1 comment
Labels
Design Notes Notes from our design meetings

Comments

@DanielRosenwasser
Copy link
Member

DanielRosenwasser commented Mar 12, 2019

Rest enumeration fixes

Timebox: 10 minutes

#29616
#29676
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/propertyIsEnumerable

  • This should only be an issue in ES3 if you're using a Symbol polyfill
    • Which means that your Symbol polyfill must be a string anyway, so that branch of code would never run.
  • Does it mean that you run into this when you're targeting ES5 but running in an ES2015 environment?
  • Actually, object rest is an ES2017 feature, so downleveling is definitely legit.
  • Action items: merge the PR and update tslib.
    • TypeScript 3.5, since master is frozen for 2 weeks.

globalThis implicit any errors

Timebox: 15 minutes

#30139

  • this in the global scope now has the type typeof globalThis.
    • That means that grabbing properties off of this may now be an error.
    • But it's unclear if the error should be under noImplicitAny vs noImplicitThis
    • The change in 3.4 punts a bunch of noImplicitThis errors to noImplicitAny.
  • What about people who want to avoid this at the top level?
    • That seems more like a lint rule.
    • But doesn't this at the top level have different behavior in JS strict mode? And in modules?
  • Maybe --globalThis needs to change its behavior under "use strict" to include undefined in the type?
  • One other thing to note is that when we know about a type, we'll give the specific type, but if a property doesn't exist, we pretend that it's okay.
    • It basically extends implicit any types arising from element accesses to property accesses.
  • Why is noImplicitThis useful now then?
    • Catching untyped this shadowing in functions.
  • Conclusion:
    • Sounds like it's okay to move these into noImplicitAny.
    • Account for "use strict" behavior.

Dropped Index Signature for Spreads

Timebox: 15 minutes

#27273
ajafff@a626e4e

declare var v: Record<string, string>;

let v2 = {...v}; // works
let v3 = {a: '', ...v}; // index signature lost
let v4 = {...v, a: ''}; // same as above
let v5 = {a: 1, ...v}; // index signature lost, should be '{a: number, [x: string]: number | string}'
let v6 = {[Number()]: 1, ...v}; // empty object type ò,Ó, should be '{[x: string]: number | string}'
  • When you spread something with an index signature, should the resulting object have an index signature, or not?
    • Today, the answer is "no", but...it should probably be yes?
  • What do you do with properties in the object type that don't satisfy the index signature?
    • Intersections?
    • Unions just because the general assumption of covariance.
  • Paraphrased: "If you have something with an index signature, you know that all properties in the object must adhere to the index signature."
  • How close to a perfect identity should spreading something be?
    • Seems bizarre to discard it.
  • Maybe it's okay to discard the index signature, but not to discard the type of the index signature.
    • What does that mean?
    • Subsequent spread-in values with index signatures could possibly override a property with a different type later on.
  • So should we take a breaking change on v5 from the example?
    • Sounds like no?
  • Let's go case-by-case.
    • v2 has "good" behavior.
    • v3 you can make the argument that the object should keep the index signature as well.
    • v4 is a case where you can invalidate the index signature.
    • v5 is "easily debatable"
    • v6 this is "interesting" because it has an "inferred" index signature from the computed property that that doesn't have a literal value.
  • Well...it sounds like v2 and v3 are also "easily debatable".
let wat1: Record<string, number> = {...v, a: 4}; // works
let wat2: Record<string, number> = {...v};       // doesn't work
  • Seems like wat1 shouldn't work, but that would be a breaking change.
  • Index signatures should probably never make concrete properties go away.
  • How do optional properties work?
    • Those should never survive.
  • What are the principles?
    • Want to be conservative regarding spreads of things with index signatures.
      • Compute the worst-case resulting type of the index signature.
        • That would be a union of all spread-in index signatures unioned with any property types.
        • That might introduce undefineds for optional properties.
          • But it'll potentially override the underlying type.
          • But that's okay.
      • The resulting type of earlier properties should be "poisoned" by the types of subsequent spreads.
        • Effectively { a: 10, ...somethingWithAnIndex } should have a property of type a whose type is number | (typeof somethingWithAnIndex)[PropertyKey].

What do you think we should do with intersections of 10**33 members?

Timebox: 20 minutes

#30068
#29949

  • "It's a React component, so it's doing a little bit of composition or something."
    • The code gets every key of React.ReactHTML, and there's a LOT of properties on there!
    • Comp itself is effectively a union of every HTML element constructor.
    • When performing overload resolution, we try to create the intersection of all options bags that are expected.
    • When you try to get the type of ref on that intersection to see if your ref is compatible, then you create a REALLY big intersection since ref is a union of different types where each member gets intersected with the ref of every other object type.
    • And then you get 2**111 types created (~10**33)
  • Sounds like it's heuristics time!
    • ...or some sort of deferred operation time?
      • well then it's just a land-mine down the road
      • and it's already deferred anyway.
  • Part of the issue is that the types are partially unsatisfiable - ref is expected to be a ref object, or a function, or a string, or null, or undefined.
    • Function types that are never expected to have properties should be thrown out.
    • Intersections of primitives and objects should be thrown out.
    • Unfortunately we don't.
  • Would be helpful if you could say "non-callable objects"
    • This could be done with the negated types branch.
    • Could also have unfulfillable signatures?
      • (...args: unknown[]) => never is effectively the bottom type for functions.
  • It's only properties that these things have in common that could ensue in an empty domain.
    • But you do have to construct the set of properties - thought that's not that expensive.
    • And you only have to do that for symbols that exist in both, don't need to resolve them.
    • Might be worth pursuing.
@DanielRosenwasser DanielRosenwasser added the Design Notes Notes from our design meetings label Mar 12, 2019
@ajafff
Copy link
Contributor

ajafff commented Mar 17, 2019

Re: Dropped Index Signatures for Spread:

  • The resulting type of earlier properties should be "poisoned" by the types of subsequent spreads.
    • Effectively { a: 10, ...somethingWithAnIndex } should have a property of type a whose type is number | (typeof somethingWithAnIndex)[PropertyKey].

Why is this different for object literals with inferred index signatures from computed properties?

let obj = { a: 10, [String()]: 'foo' };

In this example { [x: string]: string | number; a: number; } is inferred. With your reasoning regarding index signatures in spread you would also need to change the inferred type of this object literal to { [x: string]: string | number; a: number | string; }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Design Notes Notes from our design meetings
Projects
None yet
Development

No branches or pull requests

2 participants