Recoil utility types (#45206)

This commit is contained in:
Christian 2020-06-12 14:16:24 -04:00 committed by GitHub
parent dd707289fc
commit 07d88fbb9e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 264 additions and 16 deletions

View File

@ -177,3 +177,92 @@ export class RecoilValueReadOnly<T> extends AbstractRecoilValueReadonly<T> {}
export type RecoilValue<T> = RecoilValueReadOnly<T> | RecoilState<T>;
export function isRecoilValue(val: unknown): val is RecoilValue<any>;
/** Utilities */
// bigint not supported yet
export type Primitive = undefined | null | boolean | number | symbol | string;
export type SerializableParam = Primitive | SerializableParam[] | { [key: string]: SerializableParam };
export interface AtomFamilyOptions<T, P extends SerializableParam> {
key: NodeKey;
dangerouslyAllowMutability?: boolean;
default: RecoilValue<T> | Promise<T> | T | ((param: P) => T | RecoilValue<T> | Promise<T>);
}
export function atomFamily<T, P extends SerializableParam>(
options: AtomFamilyOptions<T, P>,
): (param: P) => RecoilState<T>;
export interface ReadOnlySelectorFamilyOptions<T, P extends SerializableParam> {
key: string;
get: (param: P) => (opts: { get: GetRecoilValue }) => Promise<T> | RecoilValue<T> | T;
// cacheImplementation_UNSTABLE?: () => CacheImplementation<Loadable<T>>,
// cacheImplementationForParams_UNSTABLE?: () => CacheImplementation<
// RecoilValue<T>,
// >,
dangerouslyAllowMutability?: boolean;
}
export interface ReadWriteSelectorFamilyOptions<T, P extends SerializableParam> {
key: string;
get: (param: P) => (opts: { get: GetRecoilValue }) => Promise<T> | RecoilValue<T> | T;
set: (
param: P,
) => (
opts: { set: SetRecoilState; get: GetRecoilValue; reset: ResetRecoilState },
newValue: T | DefaultValue,
) => void;
// cacheImplementation_UNSTABLE?: () => CacheImplementation<Loadable<T>>,
// cacheImplementationForParams_UNSTABLE?: () => CacheImplementation<
// RecoilValue<T>,
// >,
dangerouslyAllowMutability?: boolean;
}
export function selectorFamily<T, P extends SerializableParam>(
options: ReadWriteSelectorFamilyOptions<T, P>,
): (param: P) => RecoilState<T>;
export function selectorFamily<T, P extends SerializableParam>(
options: ReadOnlySelectorFamilyOptions<T, P>,
): (param: P) => RecoilValueReadOnly<T>;
export function constSelector<T extends SerializableParam>(constant: T): RecoilValueReadOnly<T>;
export function errorSelector(message: string): RecoilValueReadOnly<never>;
export function readOnlySelector<T>(atom: RecoilValue<T>): RecoilValueReadOnly<T>;
export function noWait<T>(state: RecoilValue<T>): RecoilValueReadOnly<Loadable<T>>;
export type UnwrapRecoilValue<T> = T extends RecoilValue<infer R> ? R : never;
export type UnwrapRecoilValueLoadables<T extends Array<RecoilValue<any>> | { [key: string]: RecoilValue<any> }> = {
[P in keyof T]: Loadable<UnwrapRecoilValue<T[P]>>;
};
export function waitForNone<RecoilValues extends Array<RecoilValue<any>> | [RecoilValue<any>]>(
param: RecoilValues,
): RecoilValueReadOnly<UnwrapRecoilValueLoadables<RecoilValues>>;
export function waitForNone<RecoilValues extends { [key: string]: RecoilValue<any> }>(
param: RecoilValues,
): RecoilValueReadOnly<UnwrapRecoilValueLoadables<RecoilValues>>;
export function waitForAny<RecoilValues extends Array<RecoilValue<any>> | [RecoilValue<any>]>(
param: RecoilValues,
): RecoilValueReadOnly<UnwrapRecoilValueLoadables<RecoilValues>>;
export function waitForAny<RecoilValues extends { [key: string]: RecoilValue<any> }>(
param: RecoilValues,
): RecoilValueReadOnly<UnwrapRecoilValueLoadables<RecoilValues>>;
export function waitForAll<RecoilValues extends Array<RecoilValue<any>> | [RecoilValue<any>]>(
param: RecoilValues,
): RecoilValueReadOnly<UnwrapRecoilValueLoadables<RecoilValues>>;
export function waitForAll<RecoilValues extends { [key: string]: RecoilValue<any> }>(
param: RecoilValues,
): RecoilValueReadOnly<UnwrapRecoilValueLoadables<RecoilValues>>;

View File

@ -13,6 +13,15 @@ import {
useRecoilCallback,
isRecoilValue,
RecoilState,
atomFamily,
selectorFamily,
constSelector,
errorSelector,
readOnlySelector,
noWait,
waitForNone,
waitForAny,
waitForAll,
} from 'recoil';
// import { atomFamily } from 'recoil/utils';
@ -31,13 +40,18 @@ const mySelector1 = selector({
get: () => 5,
});
const mySelector2 = selector({
key: 'asds',
get: () => '',
});
// $ExpectError
selector({
key: 'asdfasfds',
get: () => '',
}) as RecoilValueReadOnly<boolean>;
const readOnlySelector = selector({
const readOnlySelectorSel = selector({
key: 'asdfasf',
get: ({ get }) => {
get(myAtom) + 10;
@ -56,8 +70,8 @@ const writeableSelector = selector({
set(myAtom, 5);
reset(myAtom);
set(readOnlySelector, 2); // $ExpectError
reset(readOnlySelector); // $ExpectError
set(readOnlySelectorSel, 2); // $ExpectError
reset(readOnlySelectorSel); // $ExpectError
},
});
@ -68,7 +82,7 @@ RecoilRoot({
set(myAtom, 5);
setUnvalidatedAtomValues(new Map());
set(readOnlySelector, 2); // $ExpectError
set(readOnlySelectorSel, 2); // $ExpectError
setUnvalidatedAtomValues({}); // $ExpectError
},
});
@ -92,33 +106,33 @@ useRecoilValue<number>(nsAtom); // $ExpectError
useRecoilValue(myAtom);
useRecoilValue(mySelector1);
useRecoilValue(readOnlySelector);
useRecoilValue(readOnlySelectorSel);
useRecoilValue(writeableSelector);
useRecoilValue({}); // $ExpectError
useRecoilValueLoadable(myAtom);
useRecoilValueLoadable(readOnlySelector);
useRecoilValueLoadable(readOnlySelectorSel);
useRecoilValueLoadable(writeableSelector);
useRecoilValueLoadable({}); // $ExpectError
useRecoilState(myAtom);
useRecoilState(writeableSelector);
useRecoilState(readOnlySelector); // $ExpectError
useRecoilState(readOnlySelectorSel); // $ExpectError
useRecoilState({}); // $ExpectError
useRecoilStateLoadable(myAtom);
useRecoilStateLoadable(writeableSelector);
useRecoilStateLoadable(readOnlySelector); // $ExpectError
useRecoilStateLoadable(readOnlySelectorSel); // $ExpectError
useRecoilStateLoadable({}); // $ExpectError
useSetRecoilState(myAtom);
useSetRecoilState(writeableSelector);
useSetRecoilState(readOnlySelector); // $ExpectError
useSetRecoilState(readOnlySelectorSel); // $ExpectError
useSetRecoilState({}); // $ExpectError
useResetRecoilState(myAtom);
useResetRecoilState(writeableSelector);
useResetRecoilState(readOnlySelector); // $ExpectError
useResetRecoilState(readOnlySelectorSel); // $ExpectError
useResetRecoilState({}); // $ExpectError
useRecoilCallback(async ({ getPromise, getLoadable, set, reset }) => {
@ -138,10 +152,155 @@ isRecoilValue(myAtom);
isRecoilValue(null);
isRecoilValue(mySelector1);
// UTILS
/**
* ================ UTILS ================
*/
// atomFamily
// atomFamily({
// key: 'asdfs',
// default: (a) => {return ''},
// });
/**
* atomFamily() tests
*/
{
const myAtomFam = atomFamily({
key: 'myAtomFam1',
default: (param: number) => param,
});
const atm = myAtomFam(2); // $ExpectType RecoilState<number>
useRecoilValue(atm); // $ExpectType number
myAtomFam(''); // $ExpectError
}
/**
* selectorFamily() tests
*/
{
const mySelectorFam = selectorFamily({
key: 'myAtomFam1',
get: (param: number) => ({ get }) => {
get(mySelector1); // $ExpectType number
return param;
},
});
const atm = mySelectorFam(2); // $ExpectType RecoilValueReadOnly<number>
useRecoilValue(atm); // $ExpectType number
mySelectorFam(''); // $ExpectError
useRecoilState(mySelectorFam(3)); // $ExpectError
const mySelectorFamWritable = selectorFamily({
key: 'myAtomFam1',
get: (param: number) => ({ get }) => {
get(mySelector1); // $ExpectType number
return param;
},
set: (param: number) => () => {},
});
useRecoilState(mySelectorFamWritable(3))[0]; // $ExpectType number
}
/**
* constSelector() tests
*/
{
const mySel = constSelector(1);
const mySel2 = constSelector('hello');
const mySel3 = constSelector([1, 2]);
const mySel4 = constSelector({ a: 1, b: '2' });
useRecoilValue(mySel); // $ExpectType 1
useRecoilValue(mySel2); // $ExpectType "hello"
useRecoilValue(mySel3); // $ExpectType number[]
useRecoilValue(mySel4); // $ExpectType { a: number; b: string; }
constSelector(new Map()); // $ExpectError
constSelector(new Set()); // $ExpectError
}
/**
* errorSelector() tests
*/
{
const mySel = errorSelector('Error msg');
useRecoilValue(mySel); // $ExpectType never
errorSelector(2); // $ExpectError
errorSelector({}); // $ExpectError
}
/**
* readOnlySelector() tests
*/
{
const myWritableSel: RecoilState<number> = {} as any;
readOnlySelector(myWritableSel); // $ExpectType RecoilValueReadOnly<number>
}
/**
* noWait() tests
*/
{
const numSel: RecoilValueReadOnly<number> = {} as any;
const mySel = noWait(numSel);
useRecoilValue(mySel); // $ExpectType Loadable<number>
}
/**
* waitForNone() tests
*/
{
const numSel: RecoilValueReadOnly<number> = {} as any;
const strSel: RecoilValueReadOnly<string> = {} as any;
const mySel = waitForNone([numSel, strSel]);
const mySel2 = waitForNone({ a: numSel, b: strSel });
useRecoilValue(mySel)[0]; // $ExpectType Loadable<number>
useRecoilValue(mySel)[1]; // $ExpectType Loadable<string>
useRecoilValue(mySel2).a; // $ExpectType Loadable<number>
useRecoilValue(mySel2).b; // $ExpectType Loadable<string>
}
/**
* waitForAny() tests
*/
{
const numSel: RecoilValueReadOnly<number> = {} as any;
const strSel: RecoilValueReadOnly<string> = {} as any;
const mySel = waitForAny([numSel, strSel]);
const mySel2 = waitForAny({ a: numSel, b: strSel });
useRecoilValue(mySel)[0]; // $ExpectType Loadable<number>
useRecoilValue(mySel)[1]; // $ExpectType Loadable<string>
useRecoilValue(mySel2).a; // $ExpectType Loadable<number>
useRecoilValue(mySel2).b; // $ExpectType Loadable<string>
}
/**
* waitForAll() tests
*/
{
const numSel: RecoilValueReadOnly<number> = {} as any;
const strSel: RecoilValueReadOnly<string> = {} as any;
const mySel = waitForAll([numSel, strSel]);
const mySel2 = waitForAll({ a: numSel, b: strSel });
useRecoilValue(mySel)[0]; // $ExpectType Loadable<number>
useRecoilValue(mySel)[1]; // $ExpectType Loadable<string>
useRecoilValue(mySel2).a; // $ExpectType Loadable<number>
useRecoilValue(mySel2).b; // $ExpectType Loadable<string>
}