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, 11/13/2020 #41538

Closed
DanielRosenwasser opened this issue Nov 14, 2020 · 4 comments
Closed

Design Meeting Notes, 11/13/2020 #41538

DanielRosenwasser opened this issue Nov 14, 2020 · 4 comments
Labels
Design Notes Notes from our design meetings

Comments

@DanielRosenwasser
Copy link
Member

DanielRosenwasser commented Nov 14, 2020

abstract Constructors

#36392

  • Add support for abstract constructor types #36392 (comment)
  • You don't need to be abstract if you're extending from a value with an abstract constructor - but you do if it's a generic bounded to a type with an `abstract constructor.
  • abstract class C {
        abstract xyz(): void;
    }
    
    class D extends C {
        xyz() {
        }
    }
    
    let Foo: abstract new () => C;
    
    class Yadda extends Foo {
    }
    • Yadda must be declared abstract because it doesn't implement xyz.
      • Really!?
    • But could you write that as an interface?
  • Could say that for an interface, you can declare members as abstract.
  • Could also imagine class "types".
    • Don't know how to reason about this right now.
  • Neither necessarily needed right now.
  • If this is for mixins only, have we
    • TypeDoc and API Extractor use mixins heavily as a decent example.
    • Also, InstanceType doesn't work on abstract types.
  • The InstanceType thing seems like a clear scenario.
    • Many on the team can't actually understand some of the mixin type recipes.
    • What's the minimal mixin pattern thing we're trying to support?
    • interface Mixin {  }
      abstract class Base {  }
      
      declare function Mixin1<TBase extends new (...args: any[]) => {}>      (base: TBase):
          TBase & (new (...args: any[]) => Mixin);
      
      class Sub1 extends Mixin1(Base) { }
  • Seems like we're okay with the base proposal.

Middle Spreads in Tuples

  • We used to normalize in the presence of spreads not in the middle and just turn all subsequent elements into a single rest element with all types unioned.

    • [number, ...string[], number] -> [number, ...(string | number)[]]

    • Is also an error when explicitly written.

      type Yadda = [number, ...string[], number]
      //                    ~~~~~~~~~~~
      // A rest element must be last in a tuple type.
  • Idea: preserve these spreads in the middle.

    • They work as constraints for types
    • You get the above "normalizing" behavior as above when reading an element.
    • You can now have a rest in the middle, and fixed elements and in the beginning and the end.
  • This also means you can encode parameter lists with a fixed set of trailing elements, and a rest element at the beginning.

    function foo(...args: [...string, number]) {
    
    }
  • Was this doable today?

    type T12 = [number, ...([string | undefined] | []), boolean];
    • I dunno, maybe. Doesn't enforce union logic.
  • Motivating scenarios?

    function pipe<T extends readonly unknown[], R>(
        ...p: [...args: T, f: (...args: T) => R]
    ): R
  • Does TypeScript know how to get the "last" element?

    • No, currently not correlating foo[foo.length - 1]
    • We could do that!
    • TC39 is looking into range types, wait to align and make something intuitive.
  • Will put out a PR for this.

Static Index Signatures

#37797

  • This index signature is different from other index signatures in that it doesn't enforce a requirement on all properties.
    • Acts like a "rest" index signature.
    • Sounds like this is a bug.
    • What about Function.prototype?
      • Object has the same issues.
  • Treat it as a bug, wait on the implementation to fix it up.

Better Types for querySelector

#29037

  • querySelector is used all the time when writing any sort of DOM code.
  • Once we got template literal types in TypeScript 4.1, you can start parsing out these selectors to tell with certainty that "you have a div element."
  • There's a "meet in the middle" sort of thing - yes, it works, but you have to write the element type as well.
  • Currently doesn't work for multiple selectors split by ,
  • This isn't a GraphQL parser, is it that bad?
    • It looks expensive, but probably not that bad?
  • We generally don't have types this complicated in our .d.ts files.
  • We don't really know where the performance goes bad.
  • When you write a query selector wrong, you probably want to know.
    • But you're saving people from the element types, not the class names.
  • Probably good practice to name the element types, if you need you can split the selector.
    • Makes this more complicated.
  • How does this work with CustomElements?
  • The next-most complicated thing we have is Array.prototype.flat().
    • Something this complicated, we would definitely have to test thoroughly.
  • Not 100% sold on this.
@DanielRosenwasser DanielRosenwasser added the Design Notes Notes from our design meetings label Nov 14, 2020
@danvk
Copy link
Contributor

danvk commented Nov 14, 2020

It would really make my day to get rid of all the type assertions required to use querySelector!

If performance is the main issue, could we have an opt-in lib.dom.fancytypes.d.ts to add the relevant overloads? Then you could enable it via lib in your tsconfig.json:

{
  "lib": [
    "DOM",
    "DOM.Iterable",
    "DOM.FancyTypes",
  ]
}

@weswigham
Copy link
Member

Arbitrary Index Signatures

That's what you had in the meeting notice as the topic as well, but instead we talked about class static index signatures. It's probably a good idea to update the header to match.

@DanielRosenwasser
Copy link
Member Author

Done, thanks for the catch!

@orta
Copy link
Contributor

orta commented Nov 22, 2020

@danvk - the lib option isn't too valuable (it basically leaves it the same as it is now, because there are npm modules which augment the definition and both are sort of manual opt-in) - we'd need it to be default to affect JS users

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

4 participants