I'm using
- Pop!_OS 21.04 (Ubuntu)
- node v16.11.1
- npm v7.5.2
- Vue CLI v4.5.13
and want to create a Vue3 app using the Pinia package until Vuex5 will be ready. I run
vue create foo
# manually select TypeScript and Jest for unit tests
cd foo
npm install pinia
Inside the generated example.spec.ts file I setup a custom type, a sample store and a single test
import { defineStore, setActivePinia, createPinia } from "pinia";
import { computed, ComputedRef, ref, Ref } from "vue";
/*
Define a custom type for demo purposes
*/
type MyValue = { isTrue: boolean };
/*
Define the store using the composition API
*/
const useStore = defineStore("myValues", () => {
const myValues: Ref<MyValue[]> = ref<MyValue[]>([]);
const myTruthyValues: ComputedRef<MyValue[]> = computed<MyValue[]>(() =>
myValues.value.filter((myValue: MyValue) => myValue.isTrue));
return { myTruthyValues };
});
/*
Use the store somewhere in the project
*/
describe("Store", (): void => {
beforeEach(() => {
setActivePinia(createPinia());
});
it("returns truthy values", (): void => {
const myValuesStore = useStore();
expect(myValuesStore.myTruthyValues.every((myValue: MyValue) => myValue.isTrue)).toBeTruthy();
});
});
The test passes. But when changing the type definition of MyValue
to type MyValue = { isTrue: boolean; createdAt: Date; };
the test fails with
TypeScript diagnostics (customize using `[jest-config].globals.ts-jest.diagnostics` option):
tests/unit/example.spec.ts:13:9 - error TS2322: Type 'Ref<{ isTrue: boolean; createdAt: { toString: () => string; toDateString: () => string; toTimeString: () => string; toLocaleString: { (): string; (locales?: string | string[] | undefined, options?: DateTimeFormatOptions | undefined): string; }; ... 39 more ...; getVarDate: () => VarDate; }; }[]>' is not assignable to type 'Ref<MyValue[]>'.
Type '{ isTrue: boolean; createdAt: { toString: () => string; toDateString: () => string; toTimeString: () => string; toLocaleString: { (): string; (locales?: string | string[] | undefined, options?: DateTimeFormatOptions | undefined): string; }; ... 39 more ...; getVarDate: () => VarDate; }; }[]' is not assignable to type 'MyValue[]'.
Type '{ isTrue: boolean; createdAt: { toString: () => string; toDateString: () => string; toTimeString: () => string; toLocaleString: { (): string; (locales?: string | string[] | undefined, options?: DateTimeFormatOptions | undefined): string; }; ... 39 more ...; getVarDate: () => VarDate; }; }' is not assignable to type 'MyValue'.
Types of property 'createdAt' are incompatible.
Property '[Symbol.toPrimitive]' is missing in type '{ toString: () => string; toDateString: () => string; toTimeString: () => string; toLocaleString: { (): string; (locales?: string | string[] | undefined, options?: DateTimeFormatOptions | undefined): string; }; ... 39 more ...; getVarDate: () => VarDate; }' but required in type 'Date'.
13 const myValues: Ref<MyValue[]> = ref<MyValue[]>([]);
~~~~~~~~
node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts:114:5
114 [Symbol.toPrimitive](hint: "default"): string;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'[Symbol.toPrimitive]' is declared here.
tests/unit/example.spec.ts:32:47 - error TS2769: No overload matches this call.
Overload 1 of 2, '(predicate: (value: { isTrue: boolean; createdAt: { toString: () => string; toDateString: () => string; toTimeString: () => string; toLocaleString: { (): string; (locales?: string | string[] | undefined, options?: DateTimeFormatOptions | undefined): string; }; ... 39 more ...; getVarDate: () => VarDate; }; }, index: number, array: { ...; }[]) => value is { ...; }, thisArg?: any): this is { ...; }[]', gave the following error.
Argument of type '(myValue: MyValue) => boolean' is not assignable to parameter of type '(value: { isTrue: boolean; createdAt: { toString: () => string; toDateString: () => string; toTimeString: () => string; toLocaleString: { (): string; (locales?: string | string[] | undefined, options?: DateTimeFormatOptions | undefined): string; }; ... 39 more ...; getVarDate: () => VarDate; }; }, index: number, arr...'.
Types of parameters 'myValue' and 'value' are incompatible.
Type '{ isTrue: boolean; createdAt: { toString: () => string; toDateString: () => string; toTimeString: () => string; toLocaleString: { (): string; (locales?: string | string[] | undefined, options?: DateTimeFormatOptions | undefined): string; }; ... 39 more ...; getVarDate: () => VarDate; }; }' is not assignable to type 'MyValue'.
Types of property 'createdAt' are incompatible.
Property '[Symbol.toPrimitive]' is missing in type '{ toString: () => string; toDateString: () => string; toTimeString: () => string; toLocaleString: { (): string; (locales?: string | string[] | undefined, options?: DateTimeFormatOptions | undefined): string; }; ... 39 more ...; getVarDate: () => VarDate; }' but required in type 'Date'.
Overload 2 of 2, '(predicate: (value: { isTrue: boolean; createdAt: { toString: () => string; toDateString: () => string; toTimeString: () => string; toLocaleString: { (): string; (locales?: string | string[] | undefined, options?: DateTimeFormatOptions | undefined): string; }; ... 39 more ...; getVarDate: () => VarDate; }; }, index: number, array: { ...; }[]) => unknown, thisArg?: any): boolean', gave the following error.
Argument of type '(myValue: MyValue) => boolean' is not assignable to parameter of type '(value: { isTrue: boolean; createdAt: { toString: () => string; toDateString: () => string; toTimeString: () => string; toLocaleString: { (): string; (locales?: string | string[] | undefined, options?: DateTimeFormatOptions | undefined): string; }; ... 39 more ...; getVarDate: () => VarDate; }; }, index: number, arr...'.
Types of parameters 'myValue' and 'value' are incompatible.
Type '{ isTrue: boolean; createdAt: { toString: () => string; toDateString: () => string; toTimeString: () => string; toLocaleString: { (): string; (locales?: string | string[] | undefined, options?: DateTimeFormatOptions | undefined): string; }; ... 39 more ...; getVarDate: () => VarDate; }; }' is not assignable to type 'MyValue'.
32 expect(myValuesStore.myTruthyValues.every((myValue: MyValue) => myValue.isTrue)).toBeTruthy();
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts:114:5
114 [Symbol.toPrimitive](hint: "default"): string;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'[Symbol.toPrimitive]' is declared here.
The additional date field should not affect the test, although it seems to struggle with that type because an additional number
field works fine.
Unfortunately I don't know what's wrong
- My code? (but the test passes without the date field)
- Vue provides a wrong TS config?
- Jest struggles with it?
I don't think this issue is related to Pinia...
Any ideas?
CodePudding user response:
This is a limitation of TypeScript, as described in an answer to a similar question. However, the proposed solution there does not work for some reason.
Option 1: Update typescript
to 4.3
The TypeScript issue is fixed in 4.3, so perhaps the quickest solution is to update your typescript
version:
npm i -D typescript@^4.4.3
Option 2: Omit Symbol.toPrimitive
If you prefer to keep the older version of typescript
, you can omit Symbol.toPrimitive
from Date
for the createdAt
property type:
type MyValue = { isTrue: boolean, createdAt: Omit<Date, SymbolConstructor['toPrimitive']> };
Option 3: Use type inference
A workaround that avoids the type conflict is to lean on type inference instead of typing everything. In the example below, only the myValues
ref
is explicitly typed, while all related variable types are inferred