Skip to content

Commit

Permalink
internal: Test TypeScript 4.0, 4.1, 4.3 (#2505)
Browse files Browse the repository at this point in the history
  • Loading branch information
ntucker committed Mar 21, 2023
1 parent fca33f9 commit d865ad5
Show file tree
Hide file tree
Showing 10 changed files with 100 additions and 59 deletions.
12 changes: 7 additions & 5 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -121,10 +121,11 @@ jobs:
- run:
name: typecheck
command: |
yarn run tsc --project examples/todo-app/tsconfig.json
if [ "<< parameters.typescript-version >>" == "latest" ] || [ "<< parameters.typescript-version >>" == "~4.8" ]; then
yarn run tsc --project examples/todo-app/tsconfig.json
yarn run tsc --project examples/github-app/tsconfig.json
fi
yarn run tsc --project examples/todo-app/tsconfig.typetest.json
esmodule-loosenulltypes:
docker: *docker
Expand Down Expand Up @@ -177,10 +178,11 @@ workflows:
matrix:
parameters:
# 3.7 is min version for 'full enforcement' (TODO: we need to do a test without rest lib for this to work)
# 4.1 is min version for rest package working
# 4.3 is min version for rest package working well
# TODO: Add back "~4.1", "~4.3", once we can get around linaria types
typescript-version: ["~4.8", "latest"]
# 4.0 is min version for rest package working
# 4.1 is min version for rest package working well
# 4.3
# 4.7 (but its broken so we do 4.8) lets you apply a generic type to a function type to see its return value
typescript-version: ["~4.0", "~4.1", "~4.3", "~4.8", "latest"]
requires:
- setup
- esmodule-loosenulltypes:
Expand Down
8 changes: 6 additions & 2 deletions .github/workflows/benchmark.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ on:
- 'packages/endpoint/src/schemas/**'
- 'packages/core/**'
- 'examples/benchmark/**'
- '.github/workflows/benchmark.yml'
push:
branches:
- master
Expand All @@ -23,17 +24,20 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2-beta
- uses: actions/checkout@v3
with:
fetch-depth: 1
- uses: actions/setup-node@v3
with:
node-version: '18'
- name: Build packages
cache: 'yarn'
- name: Install packages
run: |
npm install -g corepack
corepack enable
yarn install --immutable
- name: Build packages
run: |
NODE_ENV=production BROWSERSLIST_ENV=modern yarn workspaces foreach -ptivR --from @rest-hooks/core run build:lib && NODE_ENV=production BROWSERSLIST_ENV=modern yarn workspaces foreach -ptivR --from @rest-hooks/endpoint run build:lib
- name: Run benchmark
run: yarn workspace example-benchmark build && yarn workspace example-benchmark start | tee output.txt
Expand Down
12 changes: 8 additions & 4 deletions examples/todo-app/src/resources/TodoResource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,17 @@ export const TodoResource = {
},
}),
create: TodoResourceBase.create.extend({
searchParams: {} as { userId?: string | number } | undefined,
getOptimisticResponse(snap, body) {
return body;
},
update: (newResourceId: string, urlParams) => ({
[TodoResourceBase.getList.key({ userId: urlParams?.userId })]: (
resourceIds: string[] = [],
) => [...resourceIds, newResourceId],
update: (
newResourceId: string,
urlParams?: { userId?: string | number },
) => ({
[TodoResourceBase.getList.key(
urlParams?.userId ? { userId: urlParams?.userId } : undefined,
)]: (resourceIds: string[] = []) => [...resourceIds, newResourceId],
}),
}),
delete: TodoResourceBase.delete.extend({
Expand Down
7 changes: 7 additions & 0 deletions examples/todo-app/tsconfig.typetest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"extends": "./tsconfig",
"compilerOptions": {
"skipDefaultLibCheck": true,
},
"include": ["typetest.ts"],
}
29 changes: 29 additions & 0 deletions examples/todo-app/typetest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { useCache, useController, useSuspense } from '@rest-hooks/react';

import { queryRemaining, TodoResource } from './src/resources/TodoResource';
import { UserResource } from './src/resources/UserResource';

function useTest() {
const ctrl = useController();
const payload = { id: 1, title: '', userId: 1 };
ctrl.fetch(TodoResource.create, payload);

const todos = useSuspense(TodoResource.getList, { userId: 1 });
useSuspense(TodoResource.getList);
todos.map((todo) => {
todo.pk();
todo.title;
ctrl.fetch(
TodoResource.partialUpdate,
{ id: todo.id },
{ completed: true },
);
});

const remaining = useCache(queryRemaining, { userId: 1 });

const users = useSuspense(UserResource.getList);
users.map((user) => {
user.name;
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ type NormalizeNullable<S> = Extract<S, EntityInterface> extends never ? Extract<
declare const RIC: (cb: (...args: any[]) => void, options: any) => void;

type ResultEntry<E extends EndpointInterface> = E['schema'] extends undefined | null ? ResolveType<E> : Normalize<E>;
type EndpointUpdateFunction<Source extends EndpointInterface, Updaters extends Record<string, any> = Record<string, any>> = (source: ResultEntry<Source>, ...args: Parameters<Source>) => {
type EndpointUpdateFunction<Source extends EndpointInterface, Updaters extends Record<string, any> = Record<string, any>> = (source: ResultEntry<Source>, ...args: any) => {
[K in keyof Updaters]: (result: Updaters[K]) => Updaters[K];
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -562,7 +562,7 @@ type EndpointParam<E> = E extends (first: infer A, ...rest: any) => any ? A : E
} ? A : never;
/** What the function's promise resolves to */
type ResolveType<E extends (...args: any) => any> = ReturnType<E> extends Promise<infer R> ? R : never;
type PartialArray<A> = A extends [] ? [] : A extends [infer F] ? [F] | [] : A extends [infer F, ...infer Rest] ? [F] | [F, ...PartialArray<Rest>] : A extends (infer T)[] ? T[] : never;
type PartialParameters<T extends (...args: any[]) => any> = T extends (...args: infer P) => any ? Partial<P> : never;

type FetchFunction<A extends readonly any[] = any, R = any> = (...args: A) => Promise<R>;
/** @deprecated */
Expand Down Expand Up @@ -759,7 +759,7 @@ interface EndpointInstanceInterface<
* @param thisArg An object to which the this keyword can refer inside the new function.
* @param argArray A list of arguments to be passed to the new function.
*/
bind<E extends FetchFunction, P extends PartialArray<Parameters<E>>>(
bind<E extends FetchFunction, P extends PartialParameters<E>>(
this: E,
thisArg: ThisParameterType<E>,
...args: readonly [...P]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -562,7 +562,7 @@ type EndpointParam<E> = E extends (first: infer A, ...rest: any) => any ? A : E
} ? A : never;
/** What the function's promise resolves to */
type ResolveType<E extends (...args: any) => any> = ReturnType<E> extends Promise<infer R> ? R : never;
type PartialArray<A> = A extends [] ? [] : A extends [infer F] ? [F] | [] : A extends [infer F, ...infer Rest] ? [F] | [F, ...PartialArray<Rest>] : A extends (infer T)[] ? T[] : never;
type PartialParameters<T extends (...args: any[]) => any> = T extends (...args: infer P) => any ? Partial<P> : never;

type FetchFunction<A extends readonly any[] = any, R = any> = (...args: A) => Promise<R>;
/** @deprecated */
Expand Down Expand Up @@ -759,7 +759,7 @@ interface EndpointInstanceInterface<
* @param thisArg An object to which the this keyword can refer inside the new function.
* @param argArray A list of arguments to be passed to the new function.
*/
bind<E extends FetchFunction, P extends PartialArray<Parameters<E>>>(
bind<E extends FetchFunction, P extends PartialParameters<E>>(
this: E,
thisArg: ThisParameterType<E>,
...args: readonly [...P]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,7 @@ declare class Union<Choices extends EntityMap = any> implements SchemaClass$1 {
* Represents variably sized objects
* @see https://resthooks.io/rest/api/Values
*/
declare class Values<Choices extends Schema = any> implements SchemaClass$1 {
declare class Values$1<Choices extends Schema = any> implements SchemaClass$1 {
constructor(
definition: Choices,
schemaAttribute?: Choices extends EntityMap<infer T>
Expand Down Expand Up @@ -506,8 +506,6 @@ type schema_d_All<S extends EntityMap | EntityInterface = EntityMap | EntityInte
declare const schema_d_All: typeof All;
type schema_d_Union<Choices extends EntityMap = any> = Union<Choices>;
declare const schema_d_Union: typeof Union;
type schema_d_Values<Choices extends Schema = any> = Values<Choices>;
declare const schema_d_Values: typeof Values;
type schema_d_StrategyFunction<T> = StrategyFunction<T>;
type schema_d_SchemaFunction<K = string> = SchemaFunction<K>;
type schema_d_MergeFunction = MergeFunction;
Expand All @@ -523,7 +521,7 @@ declare namespace schema_d {
schema_d_All as All,
Object$1 as Object,
schema_d_Union as Union,
schema_d_Values as Values,
Values$1 as Values,
schema_d_StrategyFunction as StrategyFunction,
schema_d_SchemaFunction as SchemaFunction,
schema_d_MergeFunction as MergeFunction,
Expand Down Expand Up @@ -562,7 +560,7 @@ type EndpointParam<E> = E extends (first: infer A, ...rest: any) => any ? A : E
} ? A : never;
/** What the function's promise resolves to */
type ResolveType<E extends (...args: any) => any> = ReturnType<E> extends Promise<infer R> ? R : never;
type PartialArray<A> = A extends [] ? [] : A extends [infer F] ? [F] | [] : A extends [infer F, ...infer Rest] ? [F] | [F, ...PartialArray<Rest>] : A extends (infer T)[] ? T[] : never;
type PartialParameters<T extends (...args: any[]) => any> = T extends (...args: infer P) => any ? Partial<P> : never;

type FetchFunction<A extends readonly any[] = any, R = any> = (...args: A) => Promise<R>;
/** @deprecated */
Expand Down Expand Up @@ -755,7 +753,7 @@ interface EndpointInstanceInterface<
* @param thisArg An object to which the this keyword can refer inside the new function.
* @param argArray A list of arguments to be passed to the new function.
*/
bind<E extends FetchFunction, P extends PartialArray<Parameters<E>>>(
bind<E extends FetchFunction, P extends PartialParameters<E>>(
this: E,
thisArg: ThisParameterType<E>,
...args: readonly [...P]
Expand Down Expand Up @@ -960,7 +958,7 @@ declare class AbortOptimistic extends Error {
}

type OnlyOptional<S extends string> = S extends `${infer K}?` ? K : never;
type OnlyRequired<S extends string> = S extends `${string}?` ? never : S;
type OnlyRequired$1<S extends string> = S extends `${string}?` ? never : S;
/** Computes the union of keys for a path string */
type PathKeys<S extends string> = string extends S ? string : S extends `${infer A}\\:${infer B}` ? PathKeys<A> | PathKeys<B> : S extends `${infer A}\\?${infer B}` ? PathKeys<A> | PathKeys<B> : PathSplits<S>;
type PathSplits<S extends string> = S extends `${string}:${infer K}/${infer R}` ? PathSplits<`:${K}`> | PathSplits<R> : S extends `${string}:${infer K}:${infer R}` ? PathSplits<`:${K}`> | PathSplits<`:${R}`> : S extends `${string}:${infer K}` ? K : never;
Expand All @@ -969,12 +967,36 @@ type PathArgs<S extends string> = PathKeys<S> extends never ? unknown : KeysToAr
type KeysToArgs<Key extends string> = {
[K in Key as OnlyOptional<K>]?: string | number;
} & {
[K in Key as OnlyRequired<K>]: string | number;
[K in Key as OnlyRequired$1<K>]: string | number;
};
/** Removes the last :token */
type ShortenPath<S extends string> = string extends S ? string : S extends `${infer B}:${infer R}` ? TrimColon<`${B}:${ShortenPath<R>}`> : '';
type TrimColon<S extends string> = string extends S ? string : S extends `${infer R}:` ? R : S;

type OptionsToFunction<O extends PartialRestGenerics, E extends RestInstance & {
body?: any;
}, F extends FetchFunction> = 'path' extends keyof O ? RestFetch<'searchParams' extends keyof O ? O['searchParams'] & PathArgs<Exclude<O['path'], undefined>> : PathArgs<Exclude<O['path'], undefined>>, 'body' extends keyof O ? O['body'] : E['body'], O['process'] extends {} ? ReturnType<O['process']> : ResolveType<F>> : 'body' extends keyof O ? RestFetch<'searchParams' extends keyof O ? O['searchParams'] & PathArgs<Exclude<E['path'], undefined>> : PathArgs<Exclude<E['path'], undefined>>, O['body'], O['process'] extends {} ? ReturnType<O['process']> : ResolveType<F>> : 'searchParams' extends keyof O ? RestFetch<O['searchParams'] & PathArgs<Exclude<E['path'], undefined>>, E['body'], O['process'] extends {} ? ReturnType<O['process']> : ResolveType<F>> : (this: ThisParameterType<F>, ...args: Parameters<F>) => Promise<O['process'] extends {} ? ReturnType<O['process']> : ResolveType<F>>;

/** Extracts only the keys that will be required
*
* Removes optional, as well as unbounded (aka 'string')
*
* @example
```
RequiredKeys<{
opt?: string;
bob: string;
alice: number;
[k: string]: string | number | undefined;
}> // = 'bob' | 'alice'
```
*/
type RequiredKeys<T> = Values<OnlyRequired<T>>;
type OnlyRequired<T> = {
[K in keyof T as string extends K ? never : K]-?: {} extends Pick<T, K> ? never : K;
};
type Values<T> = T[keyof T];

/* eslint-disable @typescript-eslint/ban-types */


Expand Down Expand Up @@ -1115,39 +1137,6 @@ type OptionsToRestEndpoint<
}
>;

type OptionsToFunction<
O extends PartialRestGenerics,
E extends RestInstance & { body?: any },
F extends FetchFunction,
> = 'path' extends keyof O
? RestFetch<
'searchParams' extends keyof O
? O['searchParams'] & PathArgs<Exclude<O['path'], undefined>>
: PathArgs<Exclude<O['path'], undefined>>,
'body' extends keyof O ? O['body'] : E['body'],
O['process'] extends {} ? ReturnType<O['process']> : ResolveType<F>
>
: 'body' extends keyof O
? RestFetch<
'searchParams' extends keyof O
? O['searchParams'] & PathArgs<Exclude<E['path'], undefined>>
: PathArgs<Exclude<E['path'], undefined>>,
O['body'],
O['process'] extends {} ? ReturnType<O['process']> : ResolveType<F>
>
: 'searchParams' extends keyof O
? RestFetch<
O['searchParams'] & PathArgs<Exclude<E['path'], undefined>>,
E['body'],
O['process'] extends {} ? ReturnType<O['process']> : ResolveType<F>
>
: (
this: ThisParameterType<F>,
...args: Parameters<F>
) => Promise<
O['process'] extends {} ? ReturnType<O['process']> : ResolveType<F>
>;

type RestExtendedEndpoint<
O extends PartialRestGenerics,
E extends RestInstance,
Expand Down Expand Up @@ -1362,6 +1351,10 @@ type ParamFetchWithBody<P, B = {}, R = any> = IfTypeScriptLooseNull<
? (this: EndpointInstanceInterface, body: B) => Promise<R>
: undefined extends P
? (this: EndpointInstanceInterface, body: B) => Promise<R>
: RequiredKeys<P> extends never
?
| ((this: EndpointInstanceInterface, body: B) => Promise<R>)
| ((this: EndpointInstanceInterface, params: P, body: B) => Promise<R>)
: (this: EndpointInstanceInterface, params: P, body: B) => Promise<R>
>;

Expand All @@ -1375,6 +1368,8 @@ type ParamFetchNoBody<P, R = any> = IfTypeScriptLooseNull<
? (this: EndpointInstanceInterface) => Promise<R>
: undefined extends P
? (this: EndpointInstanceInterface) => Promise<R>
: RequiredKeys<P> extends never
? (this: EndpointInstanceInterface, params?: P) => Promise<R>
: (this: EndpointInstanceInterface, params: P) => Promise<R>
>;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ type EndpointParam<E> = E extends (first: infer A, ...rest: any) => any ? A : E
} ? A : never;
/** What the function's promise resolves to */
type ResolveType$1<E extends (...args: any) => any> = ReturnType<E> extends Promise<infer R> ? R : never;
type PartialArray<A> = A extends [] ? [] : A extends [infer F] ? [F] | [] : A extends [infer F, ...infer Rest] ? [F] | [F, ...PartialArray<Rest>] : A extends (infer T)[] ? T[] : never;
type PartialParameters<T extends (...args: any[]) => any> = T extends (...args: infer P) => any ? Partial<P> : never;

type FetchFunction$1<A extends readonly any[] = any, R = any> = (...args: A) => Promise<R>;
interface EndpointExtraOptions$1<F extends FetchFunction$1 = FetchFunction$1> {
Expand Down Expand Up @@ -246,7 +246,7 @@ interface EndpointInstanceInterface<
* @param thisArg An object to which the this keyword can refer inside the new function.
* @param argArray A list of arguments to be passed to the new function.
*/
bind<E extends FetchFunction$1, P extends PartialArray<Parameters<E>>>(
bind<E extends FetchFunction$1, P extends PartialParameters<E>>(
this: E,
thisArg: ThisParameterType<E>,
...args: readonly [...P]
Expand Down

1 comment on commit d865ad5

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Benchmark

Benchmark suite Current: d865ad5 Previous: c0248d6 Ratio
normalizeLong 241 ops/sec (±0.65%) 293 ops/sec (±0.19%) 1.22
infer All 4665 ops/sec (±0.32%) 5595 ops/sec (±0.24%) 1.20
denormalizeLong 106 ops/sec (±1.52%) 136 ops/sec (±1.07%) 1.28
denormalizeLong with mixin Entity 109 ops/sec (±0.81%) 142 ops/sec (±0.82%) 1.30
denormalizeLong withCache 3396 ops/sec (±2.46%) 4845 ops/sec (±0.87%) 1.43
denormalizeLong All withCache 4020 ops/sec (±0.20%) 4786 ops/sec (±0.11%) 1.19
denormalizeLong Query-sorted withCache 4010 ops/sec (±0.36%) 4816 ops/sec (±0.50%) 1.20
getResponse 3715 ops/sec (±2.96%) 4343 ops/sec (±3.43%) 1.17
getSmallResponse 1560 ops/sec (±3.18%) 1876 ops/sec (±3.15%) 1.20
getSmallInferredResponse 1389 ops/sec (±0.15%) 1570 ops/sec (±0.09%) 1.13
getResponse Query-sorted 365 ops/sec (±1.81%) 461 ops/sec (±1.16%) 1.26
setLong 243 ops/sec (±0.25%) 295 ops/sec (±0.24%) 1.21
setLongWithMerge 95.86 ops/sec (±1.05%) 123 ops/sec (±0.38%) 1.28
setLongWithSimpleMerge 102 ops/sec (±0.82%) 133 ops/sec (±0.21%) 1.30

This comment was automatically generated by workflow using github-action-benchmark.

Please sign in to comment.