Reputation: 2111
I have a Vue 3 composable function.
It returns an object that contains one reactive()
variable and one ref()
variable.
And I would like to set a return type on this function to satisfy an eslint error.
But I'm new to Vue and TypeScript and not sure what the return type should be.
unknown
then TS throws an error Object is of type 'unknown'.ts(2571)
when calling the function.any
eslint complains with another error because it doesn't like the any
typeobject
eslint complains that I should use <Record<string, unknown>
instead because object
is currently hard to use<Record<string, unknown>
then I get a ton of errors on the function itself regarding unassignable types.So what should I use as the useCollection()
return type?
import { ref, reactive, watchEffect } from "vue";
import { projectFirestore } from "@/firebase/config";
import {
query,
orderBy,
onSnapshot,
DocumentData,
collection,
} from "firebase/firestore";
const useCollection: any = (collectionPath: string) => { //<-- Need to replace this "any" with something else
const documentsArray = reactive<Record<string, unknown>[]>([]);
const error = ref<string | null>(null);
// references
const collectionReference = collection(projectFirestore, collectionPath);
const collectionOrdered = query(
collectionReference,
orderBy("createdAt", "desc")
);
// updates
const unsubscribe = onSnapshot(
collectionOrdered,
(snapshot) => {
documentsArray.splice(0);
snapshot.forEach((doc: DocumentData) => {
documentsArray.push({ ...doc.data(), id: doc.id });
});
error.value = null;
},
(err) => {
console.log(err.message);
documentsArray.splice(0);
error.value = err.message;
}
);
watchEffect((onInvalidate) => {
console.log("watchEffect fired");
onInvalidate(() => {
console.log("onInvalidate fired");
unsubscribe();
});
});
return { documentsArray, error };
};
export default useCollection;
Upvotes: 3
Views: 7170
Reputation: 223104
reactive
returns the same object type as provided, with inner refs being unwrapped, which can be ignored depending on specified object.
ref
returns Ref
type.
For this function a type would be:
(collectionPath: string) => { documentsArray: Record<string, unknown>[] , error: Ref<string | null> }
There may be no need to specify the type for useCollection
variable because it's inferred from the function. Return type is inferred from the single return value, { documentsArray, error }
, where both documentsArray
and error
are constants that have their types inferred on assignment either.
If a type needs to be more specific than inferred one, e.g. collection values are known, this is handled by generics:
const useCollection = <T extends unknown = unknown>(collectionPath: string) => {
const documentsArray = reactive<Record<string, T>[]>([]);
const error = ref<string | null>(null);
...
const c = useCollection<string | number>(...);
Upvotes: 3
Reputation: 549
Mine works with any
but I guess it is because of your project rules like eslint or tsconfig.
You need to define your return type like this.
const useCollection: (collectionPath: string) : { documentsArray: reactive<Record<string, unknown>[]>; error: ref<string | null>; } => {
// write your code
}
Or you can use by defining interface.
interface CollectionResult {
documentsArray: reactive<Record<string, unknown>[]>;
error: ref<string | null>;
}
const useCollection: (collectionPath: string) : CollectionResult => {
// write your code
}
Upvotes: -1