From 6ee1d62a9090e9d80d546a6098a088da7a554c2f Mon Sep 17 00:00:00 2001 From: Anton Kalmanovich Date: Wed, 24 Apr 2024 01:36:04 +0200 Subject: [PATCH] refactor: name duplication detection types (#8) --- src/index.ts | 23 ++++++----------------- tests/02_type.spec.tsx | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 17 deletions(-) diff --git a/src/index.ts b/src/index.ts index 0096964..dad2571 100644 --- a/src/index.ts +++ b/src/index.ts @@ -25,15 +25,6 @@ type InferState = Configs extends [ } & InferState : unknown; -type IsDuplicated = Names extends [ - infer One, - ...infer Rest, -] - ? One extends Name - ? true - : IsDuplicated - : false; - type HasDuplicatedNames< Configs, Names extends string[] = [], @@ -41,11 +32,9 @@ type HasDuplicatedNames< SliceConfig, ...infer Rest, ] - ? Name extends Names[number] - ? true - : IsDuplicated extends true - ? true - : HasDuplicatedNames + ? Extract extends never + ? HasDuplicatedNames + : true : false; type HasDuplicatedArgs = Configs extends [ @@ -78,9 +67,9 @@ export function createSlice< return config; } -// FIXME no any in a reasonable way? -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export function withSlices[]>( +export function withSlices< + Configs extends SliceConfig>[], +>( ...configs: Configs ): IsValidConfigs extends true ? ( diff --git a/tests/02_type.spec.tsx b/tests/02_type.spec.tsx index 1961488..dfde703 100644 --- a/tests/02_type.spec.tsx +++ b/tests/02_type.spec.tsx @@ -26,6 +26,44 @@ test('slice type: single slice', () => { >(true); }); +test('slice type: withSlices', () => { + const countSlice = createSlice({ + name: 'count', + value: 0, + actions: { + inc: () => (prev) => prev + 1, + reset: () => () => 0, + }, + }); + + const textSlice = createSlice({ + name: 'text', + value: 'Hello', + actions: { + updateText: (newText: string) => () => newText, + reset: () => () => 'Hello', + }, + }); + + type CountTextState = { + count: number; + inc: () => void; + text: string; + updateText: (newText: string) => void; + reset: () => void; + }; + + const slices = withSlices(countSlice, textSlice); + + expectType< + ( + set: (fn: (prevState: CountTextState) => Partial) => void, + ) => CountTextState + >(slices); + + expectType>(false); +}); + test('name collisions: same slice names', () => { const countSlice = createSlice({ name: 'count',