Closed
Description
TypeScript Version: 3.6.3, 3.7.0-beta
Search Terms: inference, wrong, type parameter
Code
interface Instance {
test: string
}
type DataDef<Data, Props> = Data | ((this: Readonly<Props> & Instance) => Data)
export type ThisTypedComponentOptionsWithArrayProps<Data, PropNames extends string> =
object &
ComponentOptions<DataDef<Data, Record<PropNames, any>>, PropNames[]> &
ThisType<Instance & Data & Readonly<Record<PropNames, any>>>;
type DefaultData<V> = object | ((this: V) => object);
type DefaultProps = Record<string, any>;
export interface ComponentOptions<Data = DefaultData<Instance>, PropsDef = PropsDefinition<DefaultProps>> {
props?: PropsDef;
data?: Data;
watch?: Record<string, WatchHandler<any>>;
}
export type ArrayPropsDefinition<T> = (keyof T)[];
export type PropsDefinition<T> = ArrayPropsDefinition<T>;
export type WatchHandler<T> = (val: T, oldVal: T) => void;
declare function test<Data, PropNames extends string = never>(options?: ThisTypedComponentOptionsWithArrayProps<Data, PropNames>): void;
declare function test(options?: never): void
test({
data () {
return {
foo: true
}
},
watch: {
testWatch (value: boolean) {
this.test // any
}
}
})
Expected behavior:
this.test
in testWatch
is of type string
.
Actual behavior:
this.test
in testWatch
is of type any
.
Looks like Instance
keys are used as PropNames
and they override actual instance type.
Note that if I do either following things, it behaves as expected:
- Remove
value
´s type annotation. - Do not annotate
this
type ofDataDef
callback. - Do not use overload for
test
function.
Related Issues:
This is quite similar issue with #33164 but different as it can reproduce on v3.6.3 which the issue is already fixed.
Metadata
Metadata
Assignees
Labels
Type
Projects
Milestone
Relationships
Development
No branches or pull requests
Activity
sandersn commentedon Jan 23, 2020
Here's a simpler repro that gives some clues as to what is going on:
In the error case,
this.p
is now of typenever
and the type argument oftest
is inferred to be"p"
.In the correct case,
this.p
is still of typestring
and the type argument is inferred to benever
.It appears that
K
is instantiated asnever
in the correct case and inI
,Record<never, number> = {}
. In the error case it'sK="p"
, resulting inRecord<"p", number> = { p: number }
. Then{ p: string } & { p: number } = { p: never }
. Quick info for the type ofthis
backs this up.Also, the error only reproduces if some type (I haven't figured out which one yet) is not a subtype of
value
--value: boolean
causes the repro, as doesInnerHTML
, butunknown
does not.The error is entirely down to the result of inference; using
"p"
as the type argument always gives the wrong result andnever
always give the right one. Changing the three variables you give above determines which type argument is inferred but nothing else about the behaviour ofthis.p
.So I think this can be broken down into two problems:
"p"
andnever
when changing the 3 things outlined above?this
be given type arguments'p'
andnever
, respectively?For (2), I think the current behaviour is correct, actually. That means a smaller repro for (1) is this:
Right now I guess that this repro needs
watch
needs to be context sensitive.data
needs to have athis
parameter.(2) might actually be something to do with assignability, and (3) might be something to do with intersections in
ThisType
, since removingData &
from ThisType's argument also makes the repro stop working.sandersn commentedon Jan 23, 2020
Briefly, I can get rid of
ThisType
as long asD & I<K>
is somewhere inThusly
, as well as change the parameter name ofdata
:So there doesn't appear to be this-type inference here; just contextual typing interfering with type inference.
sandersn commentedon Jan 23, 2020
Works on 2.3 - 3.5 — although after sleeping on it, I think that the inference from
bad
is probably correct andgood
is not.I'll bisect 3.5 – 3.6 to see which PR broke things.
[-]Type parameter inference chooses wrong type from callback 'this' type[/-][+]Contextual typing interferes with type argument inference [/+]sandersn commentedon Jan 23, 2020
The break happens at #32558. However, I believe the
bad
type is correct and that the real bug is that contextual typing still prevents inference from working correctly in thegood
case.I'm going to put this in the backlog since I think it's low priority. @ahejlsberg you might be interested in this, especially if I've mis-diagnosed the role of contextual typing.
RyanCavanaugh commentedon Mar 5, 2024
It's
string
now