core: Error: [@vue/compiler-sfc] Failed to resolve index type into finite keys
Vue version
3.3.1
Link to minimal reproduction
https://github.com/dimatakoy/vue-ts-bug
Steps to reproduce
Just use a common pattern that allows for convenient autocomplete code in SFC components
interface MyButtonProps extends ButtonHTMLAttributes {
variant: 'blue' | 'white'
}
// or
type MyButtonTypeProps = {
variant: 'blue | 'white'
} & ButtonHTMLAttributes
// or
interface MyButtonProps extends ButtonHTMLAttributes {
}
# Or just build repro example, you will see error in terminal.
npm run build
What is expected?
works
What is actually happening?
[vite:vue] [@vue/compiler-sfc] Failed to resolve index type into finite keys
__masked__/vue-ts-bug/node_modules/@vue/runtime-dom/dist/runtime-dom.d.ts
1258| }
1259| type EventHandlers<E> = {
1260| [K in keyof E]?: E[K] extends (...args: any) => any ? E[K] : (payload: E[K]) => void;
| ^^^^^^^
1261| };
1262|
file: __masked__/vue-ts-bug/src/MyButton.vue
error during build:
Error: [@vue/compiler-sfc] Failed to resolve index type into finite keys
__masked__/vue-ts-bug/node_modules/@vue/runtime-dom/dist/runtime-dom.d.ts
1258| }
1259| type EventHandlers<E> = {
1260| [K in keyof E]?: E[K] extends (...args: any) => any ? E[K] : (payload: E[K]) => void;
| ^^^^^^^
1261| };
1262|
at ScriptCompileContext.error (__masked__/vue-ts-bug/node_modules/@vue/compiler-sfc/dist/compiler-sfc.cjs.js:15839:11)
at resolveStringType (__masked__/vue-ts-bug/node_modules/@vue/compiler-sfc/dist/compiler-sfc.cjs.js:18187:14)
at resolveMappedType (__masked__/vue-ts-bug/node_modules/@vue/compiler-sfc/dist/compiler-sfc.cjs.js:18080:16)
at innerResolveTypeElements (__masked__/vue-ts-bug/node_modules/@vue/compiler-sfc/dist/compiler-sfc.cjs.js:17926:14)
at resolveTypeElements (__masked__/vue-ts-bug/node_modules/@vue/compiler-sfc/dist/compiler-sfc.cjs.js:17900:35)
at innerResolveTypeElements (__masked__/vue-ts-bug/node_modules/@vue/compiler-sfc/dist/compiler-sfc.cjs.js:17945:16)
at resolveTypeElements (__masked__/vue-ts-bug/node_modules/@vue/compiler-sfc/dist/compiler-sfc.cjs.js:17900:35)
at resolveInterfaceMembers (__masked__/vue-ts-bug/node_modules/@vue/compiler-sfc/dist/compiler-sfc.cjs.js:18068:25)
at innerResolveTypeElements (__masked__/vue-ts-bug/node_modules/@vue/compiler-sfc/dist/compiler-sfc.cjs.js:17912:14)
at resolveTypeElements (__masked__/vue-ts-bug/node_modules/@vue/compiler-sfc/dist/compiler-sfc.cjs.js:17900:35)
System Info
System:
OS: macOS 13.3.1
CPU: (8) arm64 Apple M1
Memory: 103.86 MB / 8.00 GB
Shell: 5.9 - /bin/zsh
Binaries:
Node: 18.16.0 - ~/.n/bin/node
Yarn: 1.22.19 - ~/.n/bin/yarn
npm: 9.6.6 - ~/.n/bin/npm
Browsers:
Chrome: 113.0.5672.92
Safari: 16.4
npmPackages:
vue: ^3.3.1 => 3.3.1
Any additional comments?
looks like it works on 3.2.* and breaks after 3.3.*
About this issue
- Original URL
- State: closed
- Created a year ago
- Reactions: 2
- Comments: 20 (3 by maintainers)
Links to this issue
Commits related to this issue
- fix(compiler-sfc): raise specific warning for failed extends and allow ignoring extends ref #8286 — committed to vuejs/core by yyx990803 a year ago
- :bug: add @vue-ignore ref: https://github.com/vuejs/core/issues/8286 — committed to traPtitech/traQ_S-UI by ras0q a year ago
The magical comment is not a good DX friendly solution, IMHO
If understand correctly this issue (which I also ran into) basically means that Vue 3 only supports “trivial” TypeScript types for props.
In my opinion this in fact means that “Vue does not actually support TypeScript (but just a small subset of it)” - while the documentation misstates that it “provides first-class TypeScript support”.
Please either fix the issue or at least change the documentation to state that the TypeScript support is “limited” at best and not “first class” at all.
The original repro (and any usage that used a
Propsinterface that extends external types) seemed to work in 3.2, but the 3.2 behavior was actually silently ignoring the extends. So it allowed those props to be passed at the type / IDE level, but at runtime they are not treated as actual props, but fallthrough attrs.It was an oversight in 3.2 - technically we should’ve just thrown errors in this case. But somehow many users considered this a “workaround” or accidentally relied on it without realizing it’s being ignored for runtime codegen. However, this may be exactly what the user wants in certain scenarios, e.g. they just want a component to allow all HTML attrs at the type level, but treat them as fallthrough attrs.
In 3.3, the compiler will now actually attempt to resolve the base type, and in this case the base type involves a complex type that is not supported, so it fails with an error.
I’ve made this case to produce a more specific error message in 82350721 - the commit also allows you to explicitly ignore the extend (i.e. the 3.2 behavior) with an inline
/* @vue-ignore */comment. This should allow 3.2 code that used to work to retain the same behavior.Any news about this?
Vue doesn’t aim to be a fully functional typescript resolver, so this issue will never be resolved since vue doesn’t use typescript api, but a custom resolver based on babel AST. It only tries to resolve basic types we use (because creating a working type resolver requires a lot of work - see checker.ts!). If you rely on these complex types, I’ve created a new project: https://github.com/so1ve/unplugin-vue-complex-types which uses the typescript compiler’s API to resolve these types. It’s not finished yet, but stay tuned! 😃
Update: It has basic functionality now, but pretty slow! 😦
This is a rather strange situation, it turns out that if you want to use basic html attributes on a component, you have to specify them all explicitly or use a hack with ignore comment.
Given that we have attribute passing down, and we don’t need to validate them, vue-tsc could suggest valid attributes for html elements by itself.
This seems like a more elegant solution for a situation where we don’t need to validate attributes in runtime.
@yyx990803, сan you share your thoughts?
As a workaround, component definition with
defineComponentin vue 3.3 (doc) works well with complex types. I think it works on both SFC and TSX.