Vue组件泛型引发ESLint冗余类型错误,咨询是否为预期行为
Why the difference happens
Yes, this behavior is expected, and it boils down to how TypeScript and ESLint handle generics in Vue's <script setup> versus regular functions:
Vue component context:
When you declare an unconstrained genericTin<script setup>without a default type, TypeScript defaultsTtounknownat the component's top level. Sinceunknownencompasses all possible types (includingnull), the unionT | nulleffectively becomesunknown | null—which is redundant becauseunknownalready includesnull. ESLint's@typescript-eslint/no-redundant-type-constituentsrule picks up on this redundancy and throws the error.Regular function context:
Even though the function'sTis also unconstrained, ESLint doesn't flag it because the function is a generic meant to be instantiated with specific types later. When you callcreateRef<number>(),Tresolves tonumber, makingnumber | nulla valid, non-redundant union. The rule recognizes that the generic's type isn't fixed at the function's definition, so it doesn't treat the union as redundant here.
How to fix the Vue component
You have a few options to resolve the ESLint error while keeping your intended type structure:
Constrain
Tto exclude null:
If you wantTto always be a non-null type, add a constraint to ensure it can't benullorundefined:<script setup lang="ts" generic="T extends NonNullable<unknown>"> import { Ref, ref } from "vue"; const t: Ref<T | null> = ref(null); </script>This makes
T | nulla meaningful union (non-nullTplusnull) that doesn't trigger the redundancy rule.Set a default type for
T:
If you have a common default type in mind forT, specify it to avoidunknownas the default:<script setup lang="ts" generic="T = string"> import { Ref, ref } from "vue"; const t: Ref<T | null> = ref(null); </script>Now
Tdefaults tostring, sostring | nullis a valid, non-redundant union.Disable the rule for the line:
If you expect consumers of your component to always specify a concreteT(sounknownis never used in practice), you can disable the rule for that line:<script setup lang="ts" generic="T"> import { Ref, ref } from "vue"; // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents const t: Ref<T | null> = ref(null); </script>
内容的提问来源于stack exchange,提问作者Arkandias

