Skip to content

Commit

Permalink
internal: Test TypeScript 4.1, 4.3
Browse files Browse the repository at this point in the history
  • Loading branch information
ntucker committed Mar 20, 2023
1 parent c0248d6 commit 3c5b1f4
Show file tree
Hide file tree
Showing 13 changed files with 369 additions and 61 deletions.
7 changes: 4 additions & 3 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 @@ -179,8 +180,8 @@ workflows:
# 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.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.1", "~4.3", "~4.8", "latest"]
requires:
- setup
- esmodule-loosenulltypes:
Expand Down
6 changes: 5 additions & 1 deletion .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 @@ -29,11 +30,14 @@ jobs:
- 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
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;
});
}
2 changes: 2 additions & 0 deletions packages/endpoint/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@
/dist
/legacy
/index.d.ts
/ts3.4
/ts4.0
/ts4.2
15 changes: 12 additions & 3 deletions packages/endpoint/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,22 @@
"unpkg": "dist/index.umd.min.js",
"types": "lib/index.d.ts",
"typesVersions": {
">=4.2": {
">=4.8": {
"": [
"lib/index.d.ts"
],
"*": [
"lib/index.d.ts"
]
},
">=4.2": {
"": [
"ts4.2/index.d.ts"
],
"*": [
"ts4.2/index.d.ts"
]
},
">=4.0": {
"": [
"ts4.0/index.d.ts"
Expand Down Expand Up @@ -51,6 +59,7 @@
"src",
"dist",
"lib",
"ts4.2",
"ts4.0",
"ts3.4",
"node.mjs",
Expand All @@ -64,9 +73,9 @@
"build:js:node": "BROWSERSLIST_ENV=node12 rollup -c && echo '{\"type\":\"commonjs\"}' > dist/package.json",
"build:js:browser": "BROWSERSLIST_ENV=legacy rollup -c",
"build:bundle": "run-s build:js:\\*",
"build:clean": "rimraf lib dist legacy ts3.4 ts4.0 *.tsbuildinfo",
"build:clean": "rimraf lib dist legacy ts3.4 ts4.0 ts4.2 *.tsbuildinfo",
"build": "yarn run build:lib && yarn run build:legacy:lib && yarn run build:bundle",
"build:legacy-types": "yarn run downlevel-dts lib ts3.4 && yarn run downlevel-dts lib ts4.0 --to=4.0 && copyfiles --up 1 ./src-4.0-types/**/*.d.ts ./ts3.4/ && copyfiles --up 1 ./src-4.0-types/**/*.d.ts ./ts4.0 && copyfiles --up 1 ./src-legacy-types/**/*.d.ts ./ts3.4/",
"build:legacy-types": "yarn run downlevel-dts lib ts3.4 && yarn run downlevel-dts lib ts4.0 --to=4.0 && yarn run downlevel-dts lib ts4.2 --to=4.2 && copyfiles --up 1 ./src-4.2-types/**/*.d.ts ./ts4.0/ && copyfiles --up 1 ./src-4.2-types/**/*.d.ts ./ts4.2 && copyfiles --up 1 ./src-4.0-types/**/*.d.ts ./ts3.4/ && copyfiles --up 1 ./src-4.0-types/**/*.d.ts ./ts4.0 && copyfiles --up 1 ./src-legacy-types/**/*.d.ts ./ts3.4/",
"dev": "yarn run build:lib -w",
"prepare": "yarn run build:lib",
"prepack": "yarn prepare",
Expand Down
217 changes: 217 additions & 0 deletions packages/endpoint/src-4.2-types/endpoint.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
// relaxed constraints on call,apply,bind *this*

/* eslint-disable @typescript-eslint/ban-types */
import type { EndpointInterface, Schema } from './interface.js';
import type {
EndpointExtraOptions,
FetchFunction,
PartialArray,
} from './types.js';

export interface EndpointOptions<
F extends FetchFunction = FetchFunction,
S extends Schema | undefined = undefined,
M extends true | undefined = undefined,
> extends EndpointExtraOptions<F> {
key?: (...args: Parameters<F>) => string;
sideEffect?: M;
schema?: S;
[k: string]: any;
}

export interface EndpointExtendOptions<
F extends FetchFunction = FetchFunction,
S extends Schema | undefined = Schema | undefined,
M extends true | undefined = true | undefined,
> extends EndpointOptions<F, S, M> {
fetch?: FetchFunction;
}

export type ParamFromFetch<F> = F extends (
params: infer P,
body?: any,
) => Promise<any>
? P
: never;

type Overwrite<T, U> = Pick<T, Exclude<keyof T, keyof U>> & U;

export type KeyofEndpointInstance = keyof EndpointInstance<FetchFunction>;

export type ExtendedEndpoint<
O extends EndpointExtendOptions<F>,
E extends EndpointInstance<
FetchFunction,
Schema | undefined,
true | undefined
>,
F extends FetchFunction,
> = EndpointInstance<
'fetch' extends keyof O ? Exclude<O['fetch'], undefined> : E['fetch'],
'schema' extends keyof O ? O['schema'] : E['schema'],
'sideEffect' extends keyof O ? O['sideEffect'] : E['sideEffect']
> &
Omit<O, KeyofEndpointInstance> &
Omit<E, KeyofEndpointInstance>;

export function Make(...args: any[]): EndpointInstance<FetchFunction>;

/**
* Defines an async data source.
* @see https://resthooks.io/docs/api/Endpoint
*/
export interface EndpointInstance<
F extends (...args: any) => Promise<any> = FetchFunction,
S extends Schema | undefined = Schema | undefined,
M extends true | undefined = true | undefined,
> extends EndpointInstanceInterface<F, S, M> {
extend<
E extends EndpointInstance<
(...args: any) => Promise<any>,
Schema | undefined,
true | undefined
>,
O extends EndpointExtendOptions<F> &
Partial<Omit<E, keyof EndpointInstance<FetchFunction>>> &
Record<string, unknown>,
>(
this: E,
options: Readonly<O>,
): ExtendedEndpoint<typeof options, E, F>;
}

/**
* Defines an async data source.
* @see https://resthooks.io/docs/api/Endpoint
*/
export interface EndpointInstanceInterface<
F extends FetchFunction = FetchFunction,
S extends Schema | undefined = Schema | undefined,
M extends true | undefined = true | undefined,
> extends EndpointInterface<F, S, M> {
constructor: EndpointConstructor;

/**
* Calls the function, substituting the specified object for the this value of the function, and the specified array for the arguments of the function.
* @param thisArg The object to be used as the this object.
* @param argArray A set of arguments to be passed to the function.
*/
apply<E extends FetchFunction>(
this: E,
thisArg: any,
argArray?: Parameters<E>,
): ReturnType<E>;

/**
* Calls a method of an object, substituting another object for the current object.
* @param thisArg The object to be used as the current object.
* @param argArray A list of arguments to be passed to the method.
*/
call<E extends FetchFunction>(
this: E,
thisArg: any,
...argArray: Parameters<E>
): ReturnType<E>;

/**
* For a given function, creates a bound function that has the same body as the original function.
* The this object of the bound function is associated with the specified object, and has the specified initial parameters.
* @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>>>(
this: E,
thisArg: any,
...args: readonly [...P]
): EndpointInstance<
(...args: readonly [...RemoveArray<Parameters<E>, P>]) => ReturnType<E>,
S,
M
> &
Omit<E, keyof EndpointInstance<FetchFunction>>;

/** Returns a string representation of a function. */
toString(): string;

prototype: any;
readonly length: number;

// Non-standard extensions
arguments: any;
caller: F;

key(...args: Parameters<F>): string;

readonly sideEffect: M;

readonly schema: S;

fetch: F;

/* utilities */
/** @see https://resthooks.io/rest/api/Endpoint#testKey */
testKey(key: string): boolean;

/** The following is for compatibility with FetchShape */
/** @deprecated */
readonly type: M extends undefined
? 'read'
: IfAny<M, any, IfTypeScriptLooseNull<'read', 'mutate'>>;

/** @deprecated */
getFetchKey(...args: OnlyFirst<Parameters<F>>): string;
/** @deprecated */
options?: EndpointExtraOptions<F>;
}

interface EndpointConstructor {
new <
F extends (
this: EndpointInstance<FetchFunction> & E,
params?: any,
body?: any,
) => Promise<any>,
S extends Schema | undefined = undefined,
M extends true | undefined = undefined,
E extends Record<string, any> = {},
>(
fetchFunction: F,
options?: EndpointOptions<F, S, M> & E,
): EndpointInstance<F, S, M> & E;
readonly prototype: Function;
}
declare let Endpoint: EndpointConstructor;

export default Endpoint;

interface ExtendableEndpointConstructor {
new <
F extends (
this: EndpointInstanceInterface<FetchFunction> & E,
params?: any,
body?: any,
) => Promise<any>,
S extends Schema | undefined = undefined,
M extends true | undefined = undefined,
E extends Record<string, any> = {},
>(
RestFetch: F,
options?: Readonly<EndpointOptions<F, S, M>> & E,
): EndpointInstanceInterface<F, S, M> & E;
readonly prototype: Function;
}
export declare let ExtendableEndpoint: ExtendableEndpointConstructor;

type IfAny<T, Y, N> = 0 extends 1 & T ? Y : N;
type IfTypeScriptLooseNull<Y, N> = 1 | undefined extends 1 ? Y : N;

type OnlyFirst<A extends unknown[]> = A extends [] ? [] : [A[0]];

type RemoveArray<Orig extends any[], Rem extends any[]> = Rem extends [
any,
...infer RestRem,
]
? Orig extends [any, ...infer RestOrig]
? RemoveArray<RestOrig, RestRem>
: never
: Orig;
7 changes: 4 additions & 3 deletions packages/endpoint/src-legacy-types/endpoint.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// had to remove all [...T], which included importing PartialArray from types
// also relaxed constraints on call,apply,bind *this*

/* eslint-disable @typescript-eslint/ban-types */
import { EndpointInterface, Schema } from './interface.js';
Expand Down Expand Up @@ -84,7 +85,7 @@ export interface EndpointInstanceInterface<
*/
apply<E extends FetchFunction>(
this: E,
thisArg: ThisParameterType<E>,
thisArg: any,
argArray?: Parameters<E>,
): ReturnType<E>;
/**
Expand All @@ -94,7 +95,7 @@ export interface EndpointInstanceInterface<
*/
call<E extends FetchFunction>(
this: E,
thisArg: ThisParameterType<E>,
thisArg: any,
...argArray: Parameters<E>
): ReturnType<E>;
/**
Expand All @@ -105,7 +106,7 @@ export interface EndpointInstanceInterface<
*/
bind<E extends FetchFunction, P extends Parameters<E>>(
this: E,
thisArg: ThisParameterType<E>,
thisArg: any,
...args: P
): EndpointInstance<() => ReturnType<E>, S, M> &
Pick<E, Exclude<keyof E, keyof EndpointInstance<FetchFunction>>>;
Expand Down
Loading

1 comment on commit 3c5b1f4

@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: 3c5b1f4 Previous: c0248d6 Ratio
normalizeLong 288 ops/sec (±0.13%) 293 ops/sec (±0.19%) 1.02
infer All 5587 ops/sec (±0.26%) 5595 ops/sec (±0.24%) 1.00
denormalizeLong 123 ops/sec (±2.66%) 136 ops/sec (±1.07%) 1.11
denormalizeLong with mixin Entity 138 ops/sec (±0.98%) 142 ops/sec (±0.82%) 1.03
denormalizeLong withCache 4085 ops/sec (±0.05%) 4845 ops/sec (±0.87%) 1.19
denormalizeLong All withCache 4931 ops/sec (±0.13%) 4786 ops/sec (±0.11%) 0.97
denormalizeLong Query-sorted withCache 5040 ops/sec (±0.17%) 4816 ops/sec (±0.50%) 0.96
getResponse 4543 ops/sec (±2.99%) 4343 ops/sec (±3.43%) 0.96
getSmallResponse 1889 ops/sec (±3.24%) 1876 ops/sec (±3.15%) 0.99
getSmallInferredResponse 1690 ops/sec (±0.26%) 1570 ops/sec (±0.09%) 0.93
getResponse Query-sorted 470 ops/sec (±1.35%) 461 ops/sec (±1.16%) 0.98
setLong 293 ops/sec (±0.21%) 295 ops/sec (±0.24%) 1.01
setLongWithMerge 124 ops/sec (±0.35%) 123 ops/sec (±0.38%) 0.99
setLongWithSimpleMerge 133 ops/sec (±0.25%) 133 ops/sec (±0.21%) 1

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

Please sign in to comment.