fix(vue): eslint/tsconfig migration + resolve type errors

@robonen/vue (toolkit): migrate to eslint flat config + composite tsconfig;
fix composable + test type errors (writable computed returns, null guards,
overload-compatible signatures, typed test helpers) — all type-level.
This commit is contained in:
2026-06-07 16:29:39 +07:00
parent e6919de29e
commit c7644ade69
203 changed files with 23016 additions and 141 deletions
@@ -0,0 +1,74 @@
import { describe, expect, it } from 'vitest';
import { ref } from 'vue';
import { useToString } from '.';
describe(useToString, () => {
it('stringifies a number ref', () => {
const num = ref(42);
const str = useToString(num);
expect(str.value).toBe('42');
});
it('reacts to source changes', () => {
const num = ref(1);
const str = useToString(num);
expect(str.value).toBe('1');
num.value = 2;
expect(str.value).toBe('2');
});
it('stringifies a plain (non-reactive) value', () => {
expect(useToString(10).value).toBe('10');
expect(useToString('hello').value).toBe('hello');
});
it('stringifies booleans', () => {
expect(useToString(true).value).toBe('true');
expect(useToString(false).value).toBe('false');
});
it('stringifies null and undefined like String()', () => {
expect(useToString(null).value).toBe('null');
expect(useToString(undefined).value).toBe('undefined');
});
it('passes through string sources unchanged', () => {
const src = ref('already a string');
expect(useToString(src).value).toBe('already a string');
});
it('stringifies objects via their toString', () => {
expect(useToString({}).value).toBe('[object Object]');
expect(useToString([1, 2, 3]).value).toBe('1,2,3');
});
it('honors a custom toString on objects', () => {
const obj = { toString: () => 'custom' };
expect(useToString(obj).value).toBe('custom');
});
it('supports getter sources', () => {
const base = ref(2);
const str = useToString(() => `item-${base.value}`);
expect(str.value).toBe('item-2');
base.value = 9;
expect(str.value).toBe('item-9');
});
it('reacts to a getter returning different types', () => {
const src = ref<unknown>(0);
const str = useToString(() => src.value);
expect(str.value).toBe('0');
src.value = true;
expect(str.value).toBe('true');
src.value = null;
expect(str.value).toBe('null');
});
it('returns a readonly computed ref', () => {
const str = useToString(ref(1));
expect(typeof str.value).toBe('string');
// ComputedRef exposes a value getter; result is always a string
expect(str.value).toBe('1');
});
});
@@ -0,0 +1,26 @@
import { computed, toValue } from 'vue';
import type { ComputedRef, MaybeRefOrGetter } from 'vue';
/**
* @name useToString
* @category Reactivity
* @description Reactively stringify a value, equivalent to `computed(() => String(toValue(value)))`.
*
* @param {MaybeRefOrGetter<unknown>} value The source value (can be a ref, getter, or plain value)
* @returns {ComputedRef<string>} The string representation of the value
*
* @example
* const count = ref(42);
* const str = useToString(count); // '42'
*
* @example
* // works with getters
* const label = useToString(() => `item-${id.value}`);
*
* @since 0.0.15
*/
export function useToString(
value: MaybeRefOrGetter<unknown>,
): ComputedRef<string> {
return computed<string>(() => `${toValue(value)}`);
}