Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error: [@vue/compiler-sfc] Failed to resolve index type into finite keys #8286

Closed
dimatakoy opened this issue May 11, 2023 · 20 comments
Closed

Comments

@dimatakoy
Copy link

dimatakoy commented May 11, 2023

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.*

@dimatakoy
Copy link
Author

@yyx990803 , can you check this issue? Looks like code was broken after refactoring.

@dimatakoy
Copy link
Author

dimatakoy commented May 11, 2023

The documents say that the syntax I use is possible
Screenshot 2023-05-11 at 21 44 47

Update:
hmm, since EventHandlers uses generic, then extending from HTMLAttributes is impossible? But how it works in previous versions?

@ahnpnl
Copy link

ahnpnl commented May 11, 2023

I ran into same issue if I do

type ButtonProps = Pick<ButtonHTMLAttributes, 'type' | 'id' | 'name'>;

defineProps<ButtonProps>();

@yendyr
Copy link

yendyr commented May 12, 2023

downgrade to exact version: 3.2.47 will resolve this issue.. i've been faced same issue

@LeoFeng23
Copy link

same problem

yyx990803 added a commit that referenced this issue May 12, 2023
@yyx990803
Copy link
Member

yyx990803 commented May 12, 2023

The original repro (and any usage that used a Props interface 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 8235072 - 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.

@ahnpnl
Copy link

ahnpnl commented May 12, 2023

Hi @yyx990803, complex type includes also all the types which are created from type utility like Pick, Omit etc?

@dimatakoy
Copy link
Author

Hi @yyx990803, complex type includes also all the types which are created from type utility like Pick, Omit etc?

It ANY type that have underline type-computations (even &, |, and generics(any utility types too)). HTMLAttributes extends EventHandlers, so for now we cannot use this trick without @vue-ignore comment.

@seahindeniz
Copy link

The magical comment is not a good DX friendly solution, IMHO

@marsidev
Copy link

There is a safe way (without /* @vue-ignore */) to extends Props with HTMLAttributes?

@dimatakoy
Copy link
Author

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?

ras0q added a commit to traPtitech/traQ_S-UI that referenced this issue May 31, 2023
@gorankarlic
Copy link

gorankarlic commented Jun 8, 2023

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.

@dimatakoy
Copy link
Author

In my personal view its so painfully. We have limited typescript and usual typescript together, in one place. This feels strange, unpredictable and boilerplaty, since we must declare app types and special types for half of components.

Generating runtime checks from declarations was a bad idea, since its so limited. Its job that can be done on another side(api layer/business logic layer), even for simple cases.

Also, its pretty useless, since (as i know) we cannot catch this runtime validation error and then change app behavior.

@DeVoresyah
Copy link

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.

agree, hope vue will fully support typescript in the future

@Disservin
Copy link
Contributor

Disservin commented Jun 16, 2023

I agree with the comments above me. I recently ran into this issue when trying to extend from a global interface.

You can find the code here:
https://github.com/Disservin/vue-ts-error

I personally think this case is rather common, where you have a global interface but a component needs to extend it because has additional properties that the base does not have. Adding /* @vue-ignore */ is a bit cumbersome

@fabon-f
Copy link

fabon-f commented Jun 18, 2023

As a workaround, component definition with defineComponent in vue 3.3 (doc) works well with complex types. I think it works on both SFC and TSX.

<script lang="ts">
import { h } from 'vue';

export default defineComponent((props: ComplexType, context) => {
  return () => h('div')
}, { props: ['prop1', 'prop2'] })
</script>

<!-- or -->

<script lang="tsx">
export default defineComponent((props: ComplexType, context) => {
  return () => <div></div>
}, { props: ['prop1', 'prop2'] })
</script>

@brunoalod
Copy link

Any news about this?

@wokalek
Copy link

wokalek commented Aug 13, 2023

Still need to be fixed...

@so1ve
Copy link
Member

so1ve commented Aug 20, 2023

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! :(

@binochoi
Copy link

binochoi commented Sep 3, 2023

@vue-ignore is even pretty weird.
when i use complex type of the other lib, i should to use interface. type is unavailabled.

interface Props extends /** @vue-ignore */ Extended { }

its forced use case.
cannot using type. only recommended interface with complex type..
and if u developing with eslint, no-empty-interface rule ignoring is forced too.

I think there should be any other solution except vue-ignore.

@github-actions github-actions bot locked and limited conversation to collaborators Sep 18, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests