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

vue-tsc failed to infer generic types of custom directives within templates #4682

Closed
mon-jai opened this issue Aug 12, 2024 · 4 comments · Fixed by #4686
Closed

vue-tsc failed to infer generic types of custom directives within templates #4682

mon-jai opened this issue Aug 12, 2024 · 4 comments · Fixed by #4686
Labels
enhancement New feature or request

Comments

@mon-jai
Copy link

mon-jai commented Aug 12, 2024

Vue - Official extension or vue-tsc version

Same as playground

Vue version

3.5.0-beta.1

TypeScript version

5.6.0-beta

System Info

No response

Steps to reproduce

<template>
  <!--
    vue-tsc failed to infer type of T
    Type '(newUser: User) => void' is not assignable to type '(newValue: { id: number; }) => void'.
      Types of parameters 'newUser' and 'newValue' are incompatible.ts(2322)
  -->
  <div v-example="[user, setUser]"></div>
</template>

<script lang="ts" setup>
import { ref } from "vue";

type User = {
  id: number;
  name: string;
};

const user = ref<User>({ id: 0, name: "User" });

function setUser(newUser: User) {
  user.value = newUser;
}

const vExample = {
  mounted<T extends { id: number }>(
    _elContainingTbody: HTMLElement,
    _binding: { value: [T, (newValue: T) => void] }
  ) { },
};

// T is inferred correctly by TypeScript
vExample.mounted(
  document.createElement("div"),
  { value: [user.value, setUser] }
)
</script>

What is expected?

vue-tsc should infer the type of T correctly in the template.

What is actually happening?

Type '(newUser: User) => void' is not assignable to type '(newValue: { id: number; }) => void'.
  Types of parameters 'newUser' and 'newValue' are incompatible.ts(2322)

Link to minimal reproduction

Playground link

Any additional comments?

No response

@mon-jai mon-jai changed the title vue-tsc failed to infer generic aguments vue-tsc failed to infer generic arguments of custom directives Aug 12, 2024
@mon-jai mon-jai changed the title vue-tsc failed to infer generic arguments of custom directives vue-tsc failed to infer generic arguments of custom directives within templates Aug 12, 2024
@mon-jai mon-jai changed the title vue-tsc failed to infer generic arguments of custom directives within templates vue-tsc failed to infer generic types of custom directives within templates Aug 12, 2024
@KermanX KermanX added enhancement New feature or request and removed pending triage enhancement New feature or request labels Aug 13, 2024
@KermanX
Copy link
Collaborator

KermanX commented Aug 13, 2024

This is a possible improvement. I thought of some methods, but was stuck on why TypeScript can't resolve types like ((a:number)=>number) | ((a:number)=>number). (playground)

@mon-jai
Copy link
Author

mon-jai commented Aug 13, 2024

@KermanX In the example you provided, f is actually inferred as never. You can verify this by hovering over type F here: playground.

It seems that type annotation has no effect in this case: null! is always inferred as never in TypeScript. You’re essentially telling the compiler that "this is null, but also not null at the same time".

However, ((a: number) => number) | ((a: number) => number) works as expected. You just need to initialize the variable with something that matches the type (e.g. null! as any). (playground)

@KermanX
Copy link
Collaborator

KermanX commented Aug 13, 2024

It seems that type annotation has no effect in this case: null! is always inferred as never in TypeScript. You’re essentially telling the compiler that "this is null, but also not null at the same time".

However, ((a: number) => number) | ((a: number) => number) works as expected. You just need to initialize the variable with something that matches the type (e.g. null! as any). (playground)

Thanks a lot! Adding as any works. However, in the first playground link, hovering f shows const f: ((a: number) => number) | ((a: number) => number) instead of never, which seems a TypeScript bug.

@mon-jai
Copy link
Author

mon-jai commented Aug 14, 2024

However, in the first playground link, hovering f shows const f: ((a: number) => number) | ((a: number) => number) instead of never, which seems a TypeScript bug.

Reported at: microsoft/TypeScript#59626

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants