TypeScript Version: 3.6.1-rc, 3.6.2
Search Terms:
mapped types, argument, overload, readonly, intersection
Code
interface Instance {
_instanceBrand: never
}
type DataDef<Data, Props> = (this: Readonly<Props> & Instance) => Data
type PropsDefinition<T> = {
[K in keyof T]: T[K]
}
interface Options<
Data = object | ((this: Instance) => object),
PropsDef = PropsDefinition<Record<string, any>>
> {
data?: Data
props?: PropsDef
watch?: Record<string, WatchHandler<any>>
}
type WatchHandler<T> = (val: T, oldVal: T) => void;
type ThisTypedOptions<Data, Props> =
object &
Options<DataDef<Data, Props>, PropsDefinition<Props>> &
ThisType<Data & Readonly<Props> & Instance>
declare function test<Data, Props>(fn: ThisTypedOptions<Data, Props>): void;
declare function test(fn: Options): void;
test({
props: {
foo: ''
},
data(): { bar: boolean } {
return {
bar: true
}
},
watch: {
foo(newVal: string, oldVal: string): void {
this.bar = false
}
}
})
Expected behavior:
No errors. test should choose the first overload.
Actual behavior:
There is an error because the test choose the fallback overload and this is not typed as expected.
Type 'false' is not assignable to type 'WatchHandler<any>'.
If you change the fallback overload's argument type to never, you can see that it wrongly infers Props type parameter in error message.
This will not happen if you do either following things:
- Replace all appearance of
PropsDefinition<XXX> with just XXX (PropsDefinition is just returning the same type but using mapped type)
- Replace the
this type of DataDef (Readonly<Props> & Instance) with Props & Instance
Playground Link:
http://www.typescriptlang.org/play/#code/JYOwLgpgTgZghgYwgAgJIgM5jiJyDeAUMsgPqhY5IBCUOAJgFzIgQBu0hAvoYWAJ4AHFABE42ERBgAeMdgA0yAApQA9oIwA+ZAF5kACjAALYBmYAlCHHqqQAG37SV6rcgBkaTNlwQAlLu05OF4BYWU1DUkYUGAwYFtpABVtPSISAG0AaWRQZABrCH5VGGREgF1mRKyy7l5QSFhEFAB5QTjbDGliZCDdZFUAIwArCAQwZAAfA0MTM09KH38dbUGRsd95budIqT7tjCiY9pBpSwRVKHppLChQAHNFHH5NTUJtNOR6cTgAfmYg7qCCIYP7hFxRboAd3ECCMoLOFyuN3uigA6jCjAAJBh2aDSJ4vWp8IQodFgWHYkD0XFQJIpAxsOB2SqKVR2egANSZlSW2jYqmA9AA3CESaVZokSfRWsdOkFFPsUt1VqNxm5ujL4phZN8ojqFGCNJoFcDDiBYlqnMCXu5uokJST9XB3MhLNZbA4rS5tB50AskK9CPRRnY4FAUDAAK64Y7ISBYJ0m736GAgSoO4TStpauXfJNG3zMfmCkXBhCh8PIKMxrVxiBYFNp5CajqF5DF4UhetgfQfIEuZgfEgwVSqZgAcnH3S4m26X2w+jb+GQAzDzAGo9xOGQXAI3RI4bAkagID3JHPK7XcagkYg+5309nJGh5KMg-vI9U+lYkK5zOQyIgA8-Tsn+zCAXcbYdmeF5xrMAB0q5QH08B2Bgd4XjwJA8FwvhAA
(There is no error on playground as the Ts version is 3.5)
Related Issues:
This is originally reported on Vue.js repo.
vuejs/vue#10455
TypeScript Version: 3.6.1-rc, 3.6.2
Search Terms:
mapped types, argument, overload, readonly, intersection
Code
Expected behavior:
No errors.
testshould choose the first overload.Actual behavior:
There is an error because the
testchoose the fallback overload andthisis not typed as expected.If you change the fallback overload's argument type to
never, you can see that it wrongly infersPropstype parameter in error message.This will not happen if you do either following things:
PropsDefinition<XXX>with justXXX(PropsDefinitionis just returning the same type but using mapped type)thistype ofDataDef(Readonly<Props> & Instance) withProps & InstancePlayground Link:
http://www.typescriptlang.org/play/#code/JYOwLgpgTgZghgYwgAgJIgM5jiJyDeAUMsgPqhY5IBCUOAJgFzIgQBu0hAvoYWAJ4AHFABE42ERBgAeMdgA0yAApQA9oIwA+ZAF5kACjAALYBmYAlCHHqqQAG37SV6rcgBkaTNlwQAlLu05OF4BYWU1DUkYUGAwYFtpABVtPSISAG0AaWRQZABrCH5VGGREgF1mRKyy7l5QSFhEFAB5QTjbDGliZCDdZFUAIwArCAQwZAAfA0MTM09KH38dbUGRsd95budIqT7tjCiY9pBpSwRVKHppLChQAHNFHH5NTUJtNOR6cTgAfmYg7qCCIYP7hFxRboAd3ECCMoLOFyuN3uigA6jCjAAJBh2aDSJ4vWp8IQodFgWHYkD0XFQJIpAxsOB2SqKVR2egANSZlSW2jYqmA9AA3CESaVZokSfRWsdOkFFPsUt1VqNxm5ujL4phZN8ojqFGCNJoFcDDiBYlqnMCXu5uokJST9XB3MhLNZbA4rS5tB50AskK9CPRRnY4FAUDAAK64Y7ISBYJ0m736GAgSoO4TStpauXfJNG3zMfmCkXBhCh8PIKMxrVxiBYFNp5CajqF5DF4UhetgfQfIEuZgfEgwVSqZgAcnH3S4m26X2w+jb+GQAzDzAGo9xOGQXAI3RI4bAkagID3JHPK7XcagkYg+5309nJGh5KMg-vI9U+lYkK5zOQyIgA8-Tsn+zCAXcbYdmeF5xrMAB0q5QH08B2Bgd4XjwJA8FwvhAA
(There is no error on playground as the Ts version is 3.5)
Related Issues:
This is originally reported on Vue.js repo.
vuejs/vue#10455