Desired: for each element in the array passed to the createStore function, the second type of the selector should match the type of the value.
Ex: if the selector property is of type Selector<boolean, number>, the value property should be of type number, independent of what the other elements of the array's types.
export type Selector<S, Result> = (state: S) => Result;
export interface SelectorWithValue<S, Result> {
selector: Selector<S, Result>;
value: Result;
}
export interface Config<T, S, Result> {
initialState?: T;
selectorsWithValue?: SelectorWithValue<S, Result>[];
}
export function createStore<T = any, S = any, Result = any>(
config: Config<T, S, Result> = {}
): Store<T, S, Result> {
return new Store(config.initialState, config.selectorsWithValue);
}
export class Store<T, S, Result> {
constructor(
public initialState?: T,
public selectorsWithValue?: SelectorWithValue<S, Result>[]
) {}
}
const selectBooleanFromString: Selector<string, boolean> = (str) => str === 'true';
const selectNumberFromBoolean: Selector<boolean, number> = (bool) => bool ? 1 : 0;
createStore({
selectorsWithValue: [
{ selector: selectBooleanFromString, value: false },
{ selector: selectNumberFromBoolean, value: 'string' } // should error since isn't a number
],
});
Here's my first attempt modifying the Typescript playground @jcalz provided for the nested array use case:
Clarification: The above is my attempt to enforce an error on the second element of the array. However, it does error, but for the wrong reason. Here's my original attempt where no error is given at all:
export type Selector<S, Result> = (state: S) => Result;
export interface SelectorWithValue<S, Result> {
selector: Selector<S, Result>;
value: Result;
}
export interface Config<T> {
initialState?: T;
selectorsWithValue?: SelectorWithValue<any, any>[];
}
export function createStore<T = any>(
config: Config<T> = {}
): Store<T> {
return new Store(config.initialState, config.selectorsWithValue);
}
export class Store<T> {
constructor(
public initialState?: T,
public selectorsWithValue?: SelectorWithValue<any, any>[]
) {}
}
const selectBooleanFromString: Selector<string, boolean> = (str) => str === 'true';
const selectNumberFromBoolean: Selector<boolean, number> = (bool) => bool ? 1 : 0;
createStore({
selectorsWithValue: [
{ selector: selectBooleanFromString, value: false },
{ selector: selectNumberFromBoolean, value: 'string' } // should error unless value is a number.
//the passed `selector` property is type Selector<boolean, number>, therefor, the `value` should be a number
//the second type of the selector property should match the type of value
],
});
Here's the Typescript Playground.
// should error since isn't a number", it does error. Can you make something that doesn't error but should? Otherwise I'm having a hard time following.