Skip to content

Design Meeting Notes, 1/15/2021 #42416

@DanielRosenwasser

Description

@DanielRosenwasser

Smarter Literal/Subtype Reduction

#42353

  • Imagine EnumA and EnumB which each have 1000 members.
  • If you have an array like [EnumA.Member1, EnumB.Member1, someObject], then we'll try to do subtype reduction.
  • Each enum is technically a union, with 1000 literal type members.
  • Subtype reduction is O(n2), so when we try to reduce each enum, that can end up being expensive! We have a heuristic to avoid doing this work by checking up-front if we're going to do a lot of work.
  • However, in this PR, we always start out by doing a literal type reduction pass (a pass which is way cheaper than general subtype reduction), and then do full subtype reduction.
  • We always had a literal type reduction pass, but now we always apply it in the presence of any literal types (not just all-literal types).
  • We also had this other special code to handle enums before; seems like we were able to remove them.
  • The code got smaller from this change! 🎉
  • Some...breaks.
    • We used to keep void | undefined - now we reduce it to undefined.
    • A change where we now do not reduce primitives and object types that have members in common..
      • For example, [someString, { toString(): string { return "hi" } }] doesn't reduce to just the object type.
  • Does it make sense that undefined is reduced to void? Isn't it the other way around?
    • We've always had void being a supertype of undefined.
  • Users try to cast to unknown[] or any[] or whatever, but it doesn't stop the complex computation. Could we peek at that?
    • Potentially - could just do a single assignability check to

Exploding Template String Types

`${theme.colors.grey} ${theme.colors.grey} ${theme.colors.white}`
declare var a: "a" | "whole" | "bunch" | "of" | ... | "strings";

const t = `${a} ${a} ${a}`;
  • Expands out to a very big union type.

  • If the union is too big, it can be too complex.

  • It used to be that you had to opt into template literal types with as const on template strings - now you're sort of always thrown into it.

  • Two proposals

    • One is "this thing is too big" and give a better error message, and
    • make it so that as string allows you to opt out.
  • Do we have any tests for perf?

    • Relatively new feature.
    • Well we know this is strictly never going to be faster.
  • Try to find some project that uses template strings to see what sort of regressions they have.

    • Artsy has some, we can ping them!
  • Also maybe provide a quick fix.*

  • Feels like the usual expectation is "give me a reasonable type, and I'll use as const unless I opt-in."

  • Can convince ourselves of either direction.

  • Thing that's odd about not doing this work

    const x = `somestring`; // this is a literal type
    
    const str = "string;
    const x = `some${str}`; // this is not? fishy.
  • We really should try to avoid doing the full type computation if you're contextually typed, it happens all the time.

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