Closed
Description
Relating Methods With Generic Mapped Types
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
- 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
- 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
- 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
- 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 } }`
- Generic:
- 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:
- Can instantiation result in a different type? i.e. will instantiation actually replace some type variables?
- 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 toisGenericType
. - 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