Skip to content

Design Meeting Notes, 11/17/2023 #56450

Closed

Description

Relating Methods With Generic Mapped Types

#56133

declare class Base<T> {
    someProp: T;

    method<U extends unknown[]>(x: { [K in keyof U]: U[K] }): Base<U>;
}

declare class Derived<T> extends Base<T> {
    method<U extends unknown[]>(x: { [K in keyof U]: U[K] }): Base<U>;
}
  • The signatures between the base and derived class are identical, but TypeScript says the derived isn't compatible.
  • What happens is that we instantiate the source signature in the context of the target.
    • This is basically a process of unifying type parameters.
  • End up inferring from the apparent type at some point, which uses unknown[].
  • Conclusion: experiment with where to avoid getting the apparent type before performing the inference that does already occur in the compiler.

Tightening Enum Assignability

#55915

#55924

  • Historical context is that we did this because you don't always know the values in the case of computed values!
  • New rule: all values must be known and identical.
  • "Must be known" is the controversial part.
  • Think about how a library may evolve
    • One may become computed, or become known.
    • You may shift around members - although you want an error when this happens if the values change!
  • "Must have the same kind" is a reasonable middle ground when a source or target is opaque.
  • Conclusion: we are okay with the break - but we do not want to go as far as rejecting opaque members outright.

Exporting TypeChecker's isAssignableTo Method

#9879 (comment)

  • Didn't want to export this for a while
  • There's at least 3 other type relationship methods we don't export.
    • But everyone expects this one.
  • Everyone secretly relies on this, it's been around since TypeScript 3.7.
  • Okay, let's export it.

type Import Gets Elided Even When Used in Export

#56445

  • Depends on the import not being resolved - needs investigation, will take a look.
  • Maybe 5.3 bound.

Fix Support for Intersections in Template Literal Types

#56434

  • In the last design meeting, a few of us had an inclination to say "preserve the tag in template literals", but it was mixed.
  • Template literals can have two sorts of placeholders:
    • Generic: `hello ${ T }`
    • Non-generic:
      • `hello ${ string }`
      • `hello ${ string & { __tag: void } }`
  • That should afford you enough to know whether this type is instantiable... right?
    • Well....
    • `hello ${ string & { __tag: T } }`
    • Okay, we may be able to handle that...
  • Not necessarily easily...
  • We really don't want to descend and traverse the entire type.
  • It depends on the specific usage - the concept of being generic might be significant in two cases:
    1. Can instantiation result in a different type? i.e. will instantiation actually replace some type variables?
    2. Can instantiation also change the overall kind of type? (i.e. a union to a singleton type, conditional type to one of its branches, mapped types to a primitive, object, array...)
  • isGenericType really refers to the second.
  • So we should be able to get away with a change that says that `hello ${ string & { __tag: T } }` is not generic per se - it is not generic according to isGenericType.
  • Let's add that test case to the PR.
  • Is this the only place this could go wrong?
  • Wait what abut `hello ${ "world" & { __tag?: T } }` - can this be reduced?
  • Needs more discussion.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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