cloudflare / workers-types Goto Github PK
View Code? Open in Web Editor NEWTypeScript type definitions for authoring Cloudflare Workers.
License: BSD 3-Clause "New" or "Revised" License
TypeScript type definitions for authoring Cloudflare Workers.
License: BSD 3-Clause "New" or "Revised" License
The blockConcurrencyWhile
function in DurableObjectState
seems to have replaced waitUntil
according to the docs, but it is not reflected in the typings.
Thanks!
According to: https://developers.cloudflare.com/workers/runtime-apis/request#requestinitcfproperties
RequestInitCfProperties
has a polish
field.
Why is the KVNamespace declared differently than the rest of the interfaces?
Lines 443 to 444 in 6340625
Would it be better to reference the types like this?
{
"extends": "../../tsconfig-base",
"compilerOptions": {
"target": "esnext",
"lib": ["webworker", "esnext"],
"composite": false,
"types": ["@cloudflare/workers-types"]
}
}
Just thinking the instructions in the README are strange with respect to the empty import:
Usage
Just supply an empty import in one of your source files to receive the workers typesimport {} from '@cloudflare/workers-types'
Might be considered an unused import by formatters/linters.
bear with me, I'm almost clueless when it comes to Rust...
I noticed many of the Element interface methods return Element:
Line 283 in 650b496
It doesn't look like the corresponding lol-html implementation returns Element though:
https://github.com/cloudflare/lol-html/blob/1581355d998dc3cd2664e7264f9e3e6e0a7d4a85/js-api/src/element.rs#L75-L78
RequestInit
and Request
cf properties are different, this makes using patterns like return new Request(parsedUrl.toString(), request)
impossible because Request.cf
is not structurally identical to RequestInit.cf
.
I suggest we converge on a common cf
type for both Request
and RequestInit
to support the above pattern.
Incomplete typings of the HTMLRewriter:
interface ContentSettings {
html: boolean;
}
interface ElementRewritableUnit {
namespaceURI: string;
append(content: string, settings?: ContentSettings): void;
before(content: string, settings?: ContentSettings): void;
after(content: string, settings?: ContentSettings): void;
getAttribute(name: string): string | null;
setAttribute(name: string, value: string): void;
hasAttribute(name: string): boolean;
}
interface ElementContentHandlers {
element(element: ElementRewritableUnit): void;
}
declare class HTMLRewriter {
constructor();
public on(selector: string, handlers: ElementContentHandlers): HTMLRewriter;
public transform(response: Response): Response;
}
Related to #116
It would be easier for packages to support Cloudflare workers and service workers if the stream interfaces matched. Any chance you could update ReadableStream, TransformStream, etc to be generic similar to the standard/web versions?
Couple more I've encountered while migrating cfworker packages:
type BufferSource = ArrayBufferView | ArrayBuffer;
)type RequestInfo = Request | string;
)- [Symbol.iterator](): IterableIterator<([key: string, value: File | string])[]>;
+ [Symbol.iterator](): IterableIterator<[string, string | File]>;
It accepts a regular callback or an async one. The input parameter to the callback isn't defined.
Sometimes a KV namespace might be used only for a known subset of strings. It would be great to define it directly in the type of KVNamespace
to have typescript checking whether we have only used the keys of this known subset.
A developer might want to use a KV namespace to store settings which can be changed through a special route. In this case it would be great to have TypeScript checking whether the used keys are fine. Example:
// Only the keys "enabled" and "color" should be used in the KVNamespace
const settings = KVNamespace<"enabled" | "color">
// fine
settings.get("enabled")
// we would get an error here and thus we see that we have misspelled the key
settings.get("ennabled")
Usage of template literal types to define the key space:
const kvNamespace = KVNamespace<`data${number}`>
// fine
kvNamespace.get("data1")
// errors
kvNamespace.get("dataa1")
kvNamespace.get("data-1")
In new version of workers-type, I cant find WebAssembly type(which present in "dom", "webworker" libs)
Hi,
any chance of integrating audacity's jest+ts unit testing solution to official repo (this or other)? As per udacity/cloudflare-typescript-workers#19 .
Just looked up 70+ repos on github labeled 'cloudflare workers' hoping to find a decent example testing example for jest+ts with Fetch, KV & Rewriter mocking - no success... Wrangler dev will replace onedollarshaveclub's solution for integration testing, but what audacity's solution provides is still something community would love see being covered by cloudlfare team.
Maybe @signalnerve would be keen of filing this gap as he did with auth0 solution https://github.com/signalnerve/workers-auth0-example so elegantly? I'd imagine it'd require some additions to workers-types along with some dedicated example repo with 10-15 tests defined for very basic functionality....
Just an offer, just in case!
Thanks in advance!
"@cloudflare/workers-types": "^3.1.1",
const [client, server] = new WebSocketPair();
Code above to be handled the same by typescript as
const webSocketPair = new WebSocketPair();
const client = webSocketPair[0];
const server = webSocketPair[1];
This is probably because the type for WebSocketPair is
declare const WebSocketPair: { new(): { 0: WebSocket; 1: WebSocket; }; };
instead of
declare const WebSocketPair: { new(): [WebSocket, WebSocket]; };
Any plans for adding types related to websockets as seen in https://github.com/cloudflare/workers-chat-demo?
There doesn't seem to be any documentation on the the cloudflare docs so even writing it myself would be difficult. ๐ข
The suggested way of accessing env is to create a binding.d.ts
file with the following content.
declare global {
const ENV_KEY: string
}
The problem with this approach is if the env variable is not declared the script just throws at runtime.
A better way would be to extent WorkerGlobalScope
like below.
declare global {
export interface WorkerGlobalScope {
ENV_KEY: string
}
}
This way the the env vars are accessed via the self
object, thereby have flexibility for error handling and defaults.
๐
Thanks to everyone who's contributed as workers-types has evolved from one Cloudflare employee's project to a community project fully supported by the Workers team!
We will be releasing the workers-types repo under the 3-Clause BSD license ("BSD-3"), so we are asking all non-Cloudflare employees who have already contributed to workers-types to license their contributions under BSD-3. The relevant PR is #30 .
If you agree, please add a comment below stating "I hereby license all my contributions to workers-types under BSD-3."
Contributors we'd like to hear from are:
For some reason, this name changed from 2->3.
Changes like this should be documented. Please.
Having the method property of the Request class link as a string could open up issues where the user tests for lowercase methods/methods that do not exist.
Having the strangest behaviour that I can't get to the bottom of since trying v2.0.0 of this module.
Given this really simple module, worker.ts
:
export default async function handleRequest(
request: Request
): Promise<Response> {
const newRequest = new Request(request)
const defaultScore = 99
newRequest.headers.set(
'Cf-Bot-Score',
(request.cf.botManagement?.score || defaultScore).toString()
)
return fetch(newRequest)
}
And this really simple mocha test: worker.test.ts
:
import handleRequest from 'lib/worker'
describe('Worker', () => {
it('should map the bot score to a request header', async () => {
const request = {
cf: {
botManagement: {
score: 50
}
}
} as Request
const result = await handleRequest(request)
console.log(result)
})
})
And the following tsconfig
:
{
"compilerOptions": {
"types": ["@cloudflare/workers-types", "mocha"],
"module": "CommonJS",
"target": "es2020",
"lib": ["es2017", "WebWorker"],
"rootDir": "./",
"outDir": "./built",
"baseUrl": "./",
"allowJs": true,
"checkJs": true,
"alwaysStrict": true,
"noImplicitAny": false,
"noImplicitThis": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"strictPropertyInitialization": true,
"noEmitOnError": false,
"sourceMap": false
},
"include": ["lib/**/*.ts", "test/**/*.ts"],
"exclude": ["node_modules"]
}
In the GUI (vscode) all intellisense is working fine, and typescript compiles fine too.
However, when running the tests via Mocha, I get:
โฏ ./node_modules/.bin/mocha -r ts-node/register -r tsconfig-paths/register test/index.test.ts
Worker
1) should map the bot score to a request header
0 passing (9ms)
1 failing
1) Worker
should map the bot score to a request header:
ReferenceError: Request is not defined
at Object.handleRequest [as default] (lib/worker.ts:4:22)
at Context.<anonymous> (test/index.test.ts:11:39)
at processImmediate (internal/timers.js:458:21)
So specifically on the line:
const newRequest = new Request(request)
Therefore it seems fine with the interface use in the function parameters:
export default async function handleRequest(
request: Request
): Promise<Response> {
Any ideas?
I'll provide a PR as well.
We should add missing properties that are documented here: https://developers.cloudflare.com/workers/reference/apis/request/
These should be added to the CfRequestProperties
interface.
We should also update the interface to reflect that much of the geolocation information is optional, and may not be present on every request.
Missing properties:
would it be possible for this library to be updated to provide types for the image resizing available with workers?
There seem to be a few options missing in RequestInitCfPropertiesImage
.
See docs.
I tried adding this library to an existing Creact-React-App application.
I've added a hello world function, and I wrote this:
export const onRequest: PagesFunction = async (context) => {
// Contents of context object
const {
request, // same as existing Worker API
env, // same as existing Worker API
params, // if filename includes [id] or [[path]]
waitUntil, // same as ctx.waitUntil in existing Worker API
next, // used for middleware or to fetch assets
data, // arbitrary space for passing data between middlewares
} = context;
return new Response(
JSON.stringify({
country: request.cf.country,
continent: request.cf.continent,
})
);
};
However I am getting error:
Property 'cf' does not exist on type 'Request'.ts(2339)
With //@ts-ignore
it works just fine though.
What am I missing here?
Working on wiring up toucan-js
to a modules worker, and got stuck on needing a FetchEvent
. Turns out that's already been udpated, see robertcepa/toucan-js#72 (comment)
in .mjs workers, waitUntil is provided by runtime in ctx object that is passed into fetch as the third argument. Here's an example:
The problem is there's no (that I can see) definition for ctx
, or anything for the export default fetch(request, env, ctx)
function at all. Toucan provides this:
export declare type Context = {
waitUntil: (promise: Promise<any>) => void;
request?: Request;
};
So you can workaround this using:
import { Context } from 'toucan-js/dist/types'
But I don't know if that's the full type definition. What else is provided on ctx
at the moment?
DurableObjectOperator.get and DurableObjectOperator.put offer options { allowConcurrency: bool, noCache: bool } which aren't represented in the types
tl;dr: either I'm holding it wrong, or the README instructions to include ["DOM", "DOM.Iterable", "WebWorker"] // As well as "ESNext", etc. as your project requires
are wrong. I'm not sure what the answer is, but will poke around a bit.
I was working on a project with a tsconfig like this:
...
"target": "esnext",
"module": "esnext",
"lib": ["ESNext", "WebWorker"]
...
However, I ran in to an error trying to transpile code which accesses the entries()
method of a FormData
type.
templates/typescript/post_data.ts:48:32 - error TS2339: Property 'entries' does not exist on type 'FormData'.
48 for (let entry of formData.entries()) {
~~~~~~~
So I read the types and the README, and realized the iterator properties come from DOM.Iterable
, so I added that and the DOM
lib.
...
"target": "esnext",
"module": "esnext",
"lib": ["DOM", "ESNext", "DOM.Iterable", "WebWorker"]
...
Now, transpilation bonks real hard on conflicts:
> tsc --project ./templates/typescript
node_modules/typescript/lib/lib.dom.d.ts(25,1): error TS6200: Definitions of the following identifiers conflict with those in another file: EventListenerOrEventListenerObject, ImportExportKind, TableKind, ValueType, ExportValue, Exports, ImportValue, ModuleImports, Imports, HeadersInit, BodyInit, RequestInfo, BlobPart, DOMHighResTimeStamp, CanvasImageSource, OffscreenRenderingContext, MessageEventSource, ImageBitmapSource, TimerHandler, PerformanceEntryList, ReadableStreamReadResult, VibratePattern, AlgorithmIdentifier, HashAlgorithmIdentifier, BigInteger, NamedCurve, GLenum, GLboolean, GLbitfield, GLint, GLsizei, GLintptr, GLsizeiptr, GLuint, GLfloat, GLclampf, TexImageSource, Float32List, Int32List, GLint64, GLuint64, Uint32List, BufferSource, DOMTimeStamp, FormDataEntryValue, IDBValidKey, Transferable, BinaryType, CanvasDirection, CanvasFillRule, CanvasLineCap, CanvasLineJoin, CanvasTextAlign, CanvasTextBaseline, ClientTypes, EndingType, IDBCursorDirection, IDBRequestReadyState, IDBTransactionMode, ImageSmoothingQuality, KeyFormat, KeyType, KeyUsage, NotificationDirection, NotificationPermission, OffscreenRenderingContextId, PermissionName, PermissionState, PushEncryptionKeyName, PushPermissionState, ReferrerPolicy, RequestCache, RequestCredentials, RequestDestination, RequestMode, RequestRedirect, ResponseType, ServiceWorkerState, ServiceWorkerUpdateViaCache, VisibilityState, WebGLPowerPreference, WorkerType, XMLHttpRequestResponseType
node_modules/typescript/lib/lib.dom.d.ts(3719,11): error TS2430: Interface 'Comment' incorrectly extends interface 'CharacterData'.
Types of property 'after' are incompatible.
Type '(content: string, options?: ContentOptions) => Element' is not assignable to type '(...nodes: (string | Node)[]) => void'.
Types of parameters 'options' and 'nodes' are incompatible.
Type 'string | Node' is not assignable to type 'ContentOptions'.
Type 'string' is not assignable to type 'ContentOptions'.
node_modules/typescript/lib/lib.dom.d.ts(3874,5): error TS2687: All declarations of 'privateKey' must have identical modifiers.
node_modules/typescript/lib/lib.dom.d.ts(3875,5): error TS2687: All declarations of 'publicKey' must have identical modifiers.
node_modules/typescript/lib/lib.dom.d.ts(4961,101): error TS2344: Type 'HTMLElementTagNameMap[K]' does not satisfy the constraint 'Element'.
Type 'HTMLElement | HTMLCanvasElement | HTMLImageElement | HTMLVideoElement | HTMLAnchorElement | ... 66 more ... | HTMLUListElement' is not assignable to type 'Element'.
Type 'HTMLSelectElement' is not assignable to type 'Element'.
The types returned by 'remove()' are incompatible between these types.
Type 'void' is not assignable to type 'Element'.
node_modules/typescript/lib/lib.dom.d.ts(5251,11): error TS2430: Interface 'Element' incorrectly extends interface 'ChildNode'.
Types of property 'after' are incompatible.
Type '(content: string, options?: ContentOptions) => Element' is not assignable to type '(...nodes: (string | Node)[]) => void'.
Types of parameters 'options' and 'nodes' are incompatible.
Type 'string | Node' is not assignable to type 'ContentOptions'.
Type 'string' is not assignable to type 'ContentOptions'.
node_modules/typescript/lib/lib.dom.d.ts(5251,11): error TS2430: Interface 'Element' incorrectly extends interface 'ParentNode'.
Types of property 'append' are incompatible.
Type '(content: string, options?: ContentOptions) => Element' is not assignable to type '(...nodes: (string | Node)[]) => void'.
Types of parameters 'options' and 'nodes' are incompatible.
Type 'string | Node' is not assignable to type 'ContentOptions'.
Type 'string' is not assignable to type 'ContentOptions'.
node_modules/typescript/lib/lib.dom.d.ts(5277,14): error TS2687: All declarations of 'namespaceURI' must have identical modifiers.
node_modules/typescript/lib/lib.dom.d.ts(5300,14): error TS2687: All declarations of 'tagName' must have identical modifiers.
node_modules/typescript/lib/lib.dom.d.ts(5331,101): error TS2344: Type 'HTMLElementTagNameMap[K]' does not satisfy the constraint 'Element'.
Type 'HTMLElement | HTMLCanvasElement | HTMLImageElement | HTMLVideoElement | HTMLAnchorElement | ... 66 more ... | HTMLUListElement' is not assignable to type 'Element'.
Type 'HTMLSelectElement' is not assignable to type 'Element'.
node_modules/typescript/lib/lib.dom.d.ts(8414,11): error TS2430: Interface 'HTMLSelectElement' incorrectly extends interface 'HTMLElement'.
Types of property 'remove' are incompatible.
Type '{ (): void; (index: number): void; }' is not assignable to type '() => Element'.
node_modules/typescript/lib/lib.dom.d.ts(15663,11): error TS2430: Interface 'Text' incorrectly extends interface 'CharacterData'.
Types of property 'after' are incompatible.
Type '(content: string, options?: ContentOptions) => Element' is not assignable to type '(...nodes: (string | Node)[]) => void'.
Types of parameters 'options' and 'nodes' are incompatible.
Type 'string | Node' is not assignable to type 'ContentOptions'.
Type 'string' is not assignable to type 'ContentOptions'.
node_modules/typescript/lib/lib.webworker.d.ts(25,1): error TS6200: Definitions of the following identifiers conflict with those in another file: EventListenerOrEventListenerObject, ImportExportKind, TableKind, ValueType, ExportValue, Exports, ImportValue, ModuleImports, Imports, HeadersInit, BodyInit, RequestInfo, BlobPart, DOMHighResTimeStamp, CanvasImageSource, OffscreenRenderingContext, MessageEventSource, ImageBitmapSource, TimerHandler, PerformanceEntryList, ReadableStreamReadResult, VibratePattern, AlgorithmIdentifier, HashAlgorithmIdentifier, BigInteger, NamedCurve, GLenum, GLboolean, GLbitfield, GLint, GLsizei, GLintptr, GLsizeiptr, GLuint, GLfloat, GLclampf, TexImageSource, Float32List, Int32List, GLint64, GLuint64, Uint32List, BufferSource, DOMTimeStamp, FormDataEntryValue, IDBValidKey, Transferable, BinaryType, CanvasDirection, CanvasFillRule, CanvasLineCap, CanvasLineJoin, CanvasTextAlign, CanvasTextBaseline, ClientTypes, EndingType, IDBCursorDirection, IDBRequestReadyState, IDBTransactionMode, ImageSmoothingQuality, KeyFormat, KeyType, KeyUsage, NotificationDirection, NotificationPermission, OffscreenRenderingContextId, PermissionName, PermissionState, PushEncryptionKeyName, PushPermissionState, ReferrerPolicy, RequestCache, RequestCredentials, RequestDestination, RequestMode, RequestRedirect, ResponseType, ServiceWorkerState, ServiceWorkerUpdateViaCache, VisibilityState, WebGLPowerPreference, WorkerType, XMLHttpRequestResponseType
node_modules/typescript/lib/lib.webworker.d.ts(89,5): error TS2687: All declarations of 'privateKey' must have identical modifiers.
node_modules/typescript/lib/lib.webworker.d.ts(90,5): error TS2687: All declarations of 'publicKey' must have identical modifiers.
node_modules/typescript/lib/lib.webworker.d.ts(1180,13): error TS2403: Subsequent variable declarations must have the same type. Variable 'DOMMatrixReadOnly' must be of type '{ new (init?: string | number[]): DOMMatrixReadOnly; prototype: DOMMatrixReadOnly; fromFloat32Array(array32: Float32Array): DOMMatrixReadOnly; fromFloat64Array(array64: Float64Array): DOMMatrixReadOnly; fromMatrix(other?: DOMMatrixInit): DOMMatrixReadOnly; toString(): string; }', but here has type '{ new (init?: string | number[]): DOMMatrixReadOnly; prototype: DOMMatrixReadOnly; fromFloat32Array(array32: Float32Array): DOMMatrixReadOnly; fromFloat64Array(array64: Float64Array): DOMMatrixReadOnly; fromMatrix(other?: DOMMatrixInit): DOMMatrixReadOnly; }'.
node_modules/typescript/lib/lib.webworker.d.ts(1277,5): error TS2375: Duplicate number index signature.
node_modules/typescript/lib/lib.webworker.d.ts(1574,5): error TS2375: Duplicate number index signature.
node_modules/typescript/lib/lib.webworker.d.ts(1648,13): error TS2403: Subsequent variable declarations must have the same type. Variable 'FormData' must be of type '{ new (form?: HTMLFormElement): FormData; prototype: FormData; }', but here has type '{ new (): FormData; prototype: FormData; }'.
node_modules/typescript/lib/lib.webworker.d.ts(2214,14): error TS2717: Subsequent property declarations must have the same type. Property 'canvas' must be of type 'HTMLCanvasElement | OffscreenCanvas', but here has type 'OffscreenCanvas'.
node_modules/typescript/lib/lib.webworker.d.ts(2401,13): error TS2403: Subsequent variable declarations must have the same type. Variable 'Notification' must be of type '{ new (title: string, options?: NotificationOptions): Notification; prototype: Notification; readonly maxActions: number; readonly permission: NotificationPermission; requestPermission(deprecatedCallback?: NotificationPermissionCallback): Promise<...>; }', but here has type '{ new (title: string, options?: NotificationOptions): Notification; prototype: Notification; readonly maxActions: number; readonly permission: NotificationPermission; }'.
node_modules/typescript/lib/lib.webworker.d.ts(4758,14): error TS2717: Subsequent property declarations must have the same type. Property 'canvas' must be of type 'HTMLCanvasElement | OffscreenCanvas', but here has type 'OffscreenCanvas'.
node_modules/typescript/lib/lib.webworker.d.ts(5432,11): error TS2320: Interface 'WorkerGlobalScope' cannot simultaneously extend types 'WindowOrWorkerGlobalScope' and 'WorkerUtils'.
Named property 'atob' of types 'WindowOrWorkerGlobalScope' and 'WorkerUtils' are not identical.
node_modules/typescript/lib/lib.webworker.d.ts(5432,11): error TS2320: Interface 'WorkerGlobalScope' cannot simultaneously extend types 'WindowOrWorkerGlobalScope' and 'WorkerUtils'.
Named property 'btoa' of types 'WindowOrWorkerGlobalScope' and 'WorkerUtils' are not identical.
node_modules/typescript/lib/lib.webworker.d.ts(5826,13): error TS2403: Subsequent variable declarations must have the same type. Variable 'onmessage' must be of type '(this: Window, ev: MessageEvent) => any', but here has type '(this: DedicatedWorkerGlobalScope, ev: MessageEvent) => any'.
node_modules/typescript/lib/lib.webworker.d.ts(5836,13): error TS2403: Subsequent variable declarations must have the same type. Variable 'location' must be of type 'Location', but here has type 'WorkerLocation'.
node_modules/typescript/lib/lib.webworker.d.ts(5837,13): error TS2403: Subsequent variable declarations must have the same type. Variable 'onerror' must be of type 'OnErrorEventHandlerNonNull', but here has type '(this: DedicatedWorkerGlobalScope, ev: ErrorEvent) => any'.
node_modules/typescript/lib/lib.webworker.d.ts(5839,13): error TS2403: Subsequent variable declarations must have the same type. Variable 'self' must be of type 'Window & typeof globalThis', but here has type 'WorkerGlobalScope & typeof globalThis'.
node_modules/typescript/lib/lib.webworker.d.ts(5847,13): error TS2403: Subsequent variable declarations must have the same type. Variable 'navigator' must be of type 'Navigator', but here has type 'WorkerNavigator'.
templates/typescript/cache_ttl.ts(10,7): error TS2769: No overload matches this call.
Overload 1 of 2, '(input: RequestInfo, init?: RequestInit): Promise<Response>', gave the following error.
Type '{ cacheTtl: number; cacheEverything: boolean; cacheKey: string; }' is not assignable to type 'CfRequestProperties | CfRequestInit'.
Object literal may only specify known properties, and 'cacheTtl' does not exist in type 'CfRequestProperties | CfRequestInit'.
Overload 2 of 2, '(input: RequestInfo, init?: RequestInit): Promise<Response>', gave the following error.
Type '{ cacheTtl: number; cacheEverything: boolean; cacheKey: string; }' is not assignable to type 'CfRequestProperties | CfRequestInit'.
Object literal may only specify known properties, and 'cacheTtl' does not exist in type 'CfRequestProperties | CfRequestInit'.
templates/typescript/conditional_response.ts(29,7): error TS2367: This condition will always return 'false' since the types 'string' and 'number' have no overlap.
../workers-types/index.d.ts(183,3): error TS2687: All declarations of 'namespaceURI' must have identical modifiers.
../workers-types/index.d.ts(187,3): error TS2687: All declarations of 'tagName' must have identical modifiers.
../workers-types/index.d.ts(191,12): error TS2717: Subsequent property declarations must have the same type. Property 'attributes' must be of type 'NamedNodeMap', but here has type 'Iterator<{ name: string; value: string; }, any, undefined>'.
I realize a few of those errors are because I have a mis-shapen cf
object, as I've been playing around with type definitions locally. But the others seem real.
Hi,
The cron
property of ScheduledEvent
seems to be missing in the types definition. The property is documented here: https://developers.cloudflare.com/workers/runtime-apis/scheduled-event#properties
Thank you.
wondering whether cache types will be added here in future?
Do a quirk of the way we auto-generate types and changes to the runtime, we accidentally are not specifying the return type of promises. This will be fixed in the runtime but just opening this here as a tracking issue.
VSCode is giving the File '/home/myuser/Projects/worker/node_modules/@cloudflare/workers-types/index.d.ts' is not a module
error for me.
I'm working on a new project generated using yarn wrangler generate
, using the template at https://github.com/cloudflare/worker-typescript-template.
Any solution to this? ๐ค
According to the FetchEvent spec the FetchEvent
constructor accepts an optional second argument called init
. I think this worked in 2.2.1
but stopped working in 3.0.0
.
I'm using the init.request
argument in my tests like so
new FetchEvent("fetch", {
request: new CfRequest("/foo", { method: "GET" }),
})
to test the handler passed to addEventListener("fetch", (event) => {})
with a fake event
. This creation of the fetchEvent
now being marked as invalid by TypeScript.
Hey Cloudflare friends ๐
So I found a bit of a TypeScript problem with SSR React and Cloudflare. Based on workers-types, you shouldn't include the built-in DOM types on a Workers project which makes sense because workers isn't a DOM environment. The problem is that some of the code we're writing runs in the worker and some of it runs in the browser.
So I do need both types available in different parts of my file. Unfortunately AFAIK is not possible with TypeScript. So we need to have both types available for the whole file. Unfortunately, when I include DOM types with @cloudflare/workers-types
, I get a bunch of errors because the types aren't compatible.
I'm not sure what to do about this. Have y'all faced this before?
node_modules/typescript/lib/lib.dom.d.ts:25:1 - error TS6200: Definitions of the following identifiers conflict with those in another file: AbortController, AbortSignal, Blob, BodyInit, Cache, CacheStorage, CloseEvent, Crypto, CryptoKey, DOMException, Event, EventListener, EventListenerOrEventListenerObject, EventTarget, File, FormData, Headers, HeadersInit, MessageEvent, PromiseRejectionEvent, ReadableStream, ReadableStreamDefaultReader, Request, Response, StreamPipeOptions, SubtleCrypto, TextDecoder, TextEncoder, TransformStream, URL, URLSearchParams, WebSocket, WebSocketEventMap, WritableStream, WritableStreamDefaultWriter, caches, console, crypto, self
25 interface AddEventListenerOptions extends EventListenerOptions {
~~~~~~~~~
node_modules/@cloudflare/workers-types/index.d.ts:4:1
4 declare class AbortController {
~~~~~~~
Conflicts are in this file.
node_modules/typescript/lib/lib.dom.d.ts:287:5 - error TS2687: All declarations of 'privateKey' must have identical modifiers.
287 privateKey?: CryptoKey;
~~~~~~~~~~
node_modules/typescript/lib/lib.dom.d.ts:288:5 - error TS2687: All declarations of 'publicKey' must have identical modifiers.
288 publicKey?: CryptoKey;
~~~~~~~~~
node_modules/typescript/lib/lib.dom.d.ts:650:5 - error TS2687: All declarations of 'kty' must have identical modifiers.
650 kty?: string;
~~~
node_modules/typescript/lib/lib.dom.d.ts:877:5 - error TS2687: All declarations of 'data' must have identical modifiers.
877 data?: T;
~~~~
node_modules/typescript/lib/lib.dom.d.ts:1701:5 - error TS2687: All declarations of 'read' must have identical modifiers.
1701 read?: number;
~~~~
node_modules/typescript/lib/lib.dom.d.ts:1702:5 - error TS2687: All declarations of 'written' must have identical modifiers.
1702 written?: number;
~~~~~~~
node_modules/typescript/lib/lib.dom.d.ts:3568:11 - error TS2430: Interface 'Comment' incorrectly extends interface 'CharacterData'.
Types of property 'after' are incompatible.
Type '(content: Content, options?: ContentOptions | undefined) => Comment' is not assignable to type '(...nodes: (string | Node)[]) => void'.
Types of parameters 'content' and 'nodes' are incompatible.
Type 'string | Node' is not assignable to type 'Content'.
Type 'Node' is not assignable to type 'Content'.
Type 'Node' is not assignable to type 'string'.
3568 interface Comment extends CharacterData {
~~~~~~~
node_modules/typescript/lib/lib.dom.d.ts:4632:101 - error TS2344: Type 'HTMLElementTagNameMap[K]' does not satisfy the constraint 'Element'.
Type 'HTMLElement | HTMLAnchorElement | HTMLAreaElement | HTMLAudioElement | HTMLBaseElement | ... 63 more ... | HTMLFrameSetElement' is not assignable to type 'Element'.
Type 'HTMLSelectElement' is not assignable to type 'Element'.
Types of property 'remove' are incompatible.
Type '{ (): void; (index: number): void; }' is not assignable to type '() => Element'.
4632 getElementsByTagName<K extends keyof HTMLElementTagNameMap>(qualifiedName: K): HTMLCollectionOf<HTMLElementTagNameMap[K]>;
~~~~~~~~~~~~~~~~~~~~~~~~
node_modules/typescript/lib/lib.dom.d.ts:4872:11 - error TS2430: Interface 'Element' incorrectly extends interface 'ChildNode'.
Types of property 'after' are incompatible.
Type '(content: Content, options?: ContentOptions | undefined) => Element' is not assignable to type '(...nodes: (string | Node)[]) => void'.
Types of parameters 'content' and 'nodes' are incompatible.
Type 'string | Node' is not assignable to type 'Content'.
4872 interface Element extends Node, ARIAMixin, Animatable, ChildNode, InnerHTML, NonDocumentTypeChildNode, ParentNode, Slottable {
~~~~~~~
node_modules/typescript/lib/lib.dom.d.ts:4872:11 - error TS2430: Interface 'Element' incorrectly extends interface 'ParentNode'.
Types of property 'append' are incompatible.
Type '(content: Content, options?: ContentOptions | undefined) => Element' is not assignable to type '(...nodes: (string | Node)[]) => void'.
Types of parameters 'content' and 'nodes' are incompatible.
Type 'string | Node' is not assignable to type 'Content'.
4872 interface Element extends Node, ARIAMixin, Animatable, ChildNode, InnerHTML, NonDocumentTypeChildNode, ParentNode, Slottable {
~~~~~~~
node_modules/typescript/lib/lib.dom.d.ts:4922:14 - error TS2687: All declarations of 'tagName' must have identical modifiers.
4922 readonly tagName: string;
~~~~~~~
node_modules/typescript/lib/lib.dom.d.ts:4953:101 - error TS2344: Type 'HTMLElementTagNameMap[K]' does not satisfy the constraint 'Element'.
Type 'HTMLElement | HTMLAnchorElement | HTMLAreaElement | HTMLAudioElement | HTMLBaseElement | ... 63 more ... | HTMLFrameSetElement' is not assignable to type 'Element'.
4953 getElementsByTagName<K extends keyof HTMLElementTagNameMap>(qualifiedName: K): HTMLCollectionOf<HTMLElementTagNameMap[K]>;
~~~~~~~~~~~~~~~~~~~~~~~~
node_modules/typescript/lib/lib.dom.d.ts:8111:11 - error TS2430: Interface 'HTMLSelectElement' incorrectly extends interface 'HTMLElement'.
8111 interface HTMLSelectElement extends HTMLElement {
~~~~~~~~~~~~~~~~~
node_modules/typescript/lib/lib.dom.d.ts:14471:11 - error TS2430: Interface 'Text' incorrectly extends interface 'CharacterData'.
Types of property 'after' are incompatible.
Type '(content: Content, options?: ContentOptions | undefined) => Text' is not assignable to type '(...nodes: (string | Node)[]) => void'.
Types of parameters 'content' and 'nodes' are incompatible.
Type 'string | Node' is not assignable to type 'Content'.
14471 interface Text extends CharacterData, Slottable {
~~~~
node_modules/@types/react/index.d.ts:2869:78 - error TS2344: Type 'HTMLSelectElement' does not satisfy the constraint 'HTMLElement'.
The types returned by 'remove()' are incompatible between these types.
Type 'void' is not assignable to type 'Element'.
2869 select: DetailedHTMLFactory<SelectHTMLAttributes<HTMLSelectElement>, HTMLSelectElement>;
~~~~~~~~~~~~~~~~~
node_modules/@cloudflare/workers-types/index.d.ts:4:1 - error TS6200: Definitions of the following identifiers conflict with those in another file: AbortController, AbortSignal, Blob, BodyInit, Cache, CacheStorage, CloseEvent, Crypto, CryptoKey, DOMException, Event, EventListener, EventListenerOrEventListenerObject, EventTarget, File, FormData, Headers, HeadersInit, MessageEvent, PromiseRejectionEvent, ReadableStream, ReadableStreamDefaultReader, Request, Response, StreamPipeOptions, SubtleCrypto, TextDecoder, TextEncoder, TransformStream, URL, URLSearchParams, WebSocket, WebSocketEventMap, WritableStream, WritableStreamDefaultWriter, caches, console, crypto, self
4 declare class AbortController {
~~~~~~~
node_modules/typescript/lib/lib.dom.d.ts:25:1
25 interface AddEventListenerOptions extends EventListenerOptions {
~~~~~~~~~
Conflicts are in this file.
node_modules/@cloudflare/workers-types/index.d.ts:98:12 - error TS2717: Subsequent property declarations must have the same type. Property 'body' must be of type 'ReadableStream<Uint8Array> | null', but here has type 'ReadableStream<any> | null'.
98 readonly body: ReadableStream | null;
~~~~
node_modules/typescript/lib/lib.dom.d.ts:2444:14
2444 readonly body: ReadableStream<Uint8Array> | null;
~~~~
'body' was also declared here.
node_modules/@cloudflare/workers-types/index.d.ts:223:3 - error TS2687: All declarations of 'publicKey' must have identical modifiers.
223 publicKey: CryptoKey;
~~~~~~~~~
node_modules/@cloudflare/workers-types/index.d.ts:223:3 - error TS2717: Subsequent property declarations must have the same type. Property 'publicKey' must be of type 'CryptoKey | undefined', but here has type 'CryptoKey'.
223 publicKey: CryptoKey;
~~~~~~~~~
node_modules/typescript/lib/lib.dom.d.ts:288:5
288 publicKey?: CryptoKey;
~~~~~~~~~
'publicKey' was also declared here.
node_modules/@cloudflare/workers-types/index.d.ts:224:3 - error TS2687: All declarations of 'privateKey' must have identical modifiers.
224 privateKey: CryptoKey;
~~~~~~~~~~
node_modules/@cloudflare/workers-types/index.d.ts:224:3 - error TS2717: Subsequent property declarations must have the same type. Property 'privateKey' must be of type 'CryptoKey | undefined', but here has type 'CryptoKey'.
224 privateKey: CryptoKey;
~~~~~~~~~~
node_modules/typescript/lib/lib.dom.d.ts:287:5
287 privateKey?: CryptoKey;
~~~~~~~~~~
'privateKey' was also declared here.
node_modules/@cloudflare/workers-types/index.d.ts:376:3 - error TS2687: All declarations of 'tagName' must have identical modifiers.
376 tagName: string;
~~~~~~~
node_modules/@cloudflare/workers-types/index.d.ts:377:12 - error TS2717: Subsequent property declarations must have the same type. Property 'attributes' must be of type 'NamedNodeMap', but here has type 'IterableIterator<string[]>'.
377 readonly attributes: IterableIterator<string[]>;
~~~~~~~~~~
node_modules/typescript/lib/lib.dom.d.ts:4873:14
4873 readonly attributes: NamedNodeMap;
~~~~~~~~~~
'attributes' was also declared here.
node_modules/@cloudflare/workers-types/index.d.ts:379:12 - error TS2717: Subsequent property declarations must have the same type. Property 'namespaceURI' must be of type 'string | null', but here has type 'string'.
379 readonly namespaceURI: string;
~~~~~~~~~~~~
node_modules/typescript/lib/lib.dom.d.ts:4897:14
4897 readonly namespaceURI: string | null;
~~~~~~~~~~~~
'namespaceURI' was also declared here.
node_modules/@cloudflare/workers-types/index.d.ts:430:84 - error TS2315: Type 'EventListener' is not generic.
430 declare type EventListenerOrEventListenerObject<EventType extends Event = Event> = EventListener<EventType> | EventListenerObject<EventType>;
~~~~~~~~~~~~~~~~~~~~~~~~
node_modules/@cloudflare/workers-types/index.d.ts:434:70 - error TS2315: Type 'EventListenerOrEventListenerObject' is not generic.
434 addEventListener<Type extends keyof EventMap>(type: Type, handler: EventListenerOrEventListenerObject<EventMap[Type]>, options?: EventTargetAddEventListenerOptions | boolean): void;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
node_modules/@cloudflare/workers-types/index.d.ts:435:73 - error TS2315: Type 'EventListenerOrEventListenerObject' is not generic.
435 removeEventListener<Type extends keyof EventMap>(type: Type, handler: EventListenerOrEventListenerObject<EventMap[Type]>, options?: EventTargetEventListenerOptions | boolean): void;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
node_modules/@cloudflare/workers-types/index.d.ts:641:3 - error TS2687: All declarations of 'kty' must have identical modifiers.
641 kty: string;
~~~
node_modules/@cloudflare/workers-types/index.d.ts:641:3 - error TS2717: Subsequent property declarations must have the same type. Property 'kty' must be of type 'string | undefined', but here has type 'string'.
641 kty: string;
~~~
node_modules/typescript/lib/lib.dom.d.ts:650:5
650 kty?: string;
~~~
'kty' was also declared here.
node_modules/@cloudflare/workers-types/index.d.ts:737:3 - error TS2687: All declarations of 'data' must have identical modifiers.
737 data: ArrayBuffer | string;
~~~~
node_modules/@cloudflare/workers-types/index.d.ts:737:3 - error TS2717: Subsequent property declarations must have the same type. Property 'data' must be of type 'T | undefined', but here has type 'string | ArrayBuffer'.
737 data: ArrayBuffer | string;
~~~~
node_modules/typescript/lib/lib.dom.d.ts:877:5
877 data?: T;
~~~~
'data' was also declared here.
node_modules/@cloudflare/workers-types/index.d.ts:838:3 - error TS2717: Subsequent property declarations must have the same type. Property 'redirect' must be of type 'RequestRedirect | undefined', but here has type 'string | undefined'.
838 redirect?: string;
~~~~~~~~
node_modules/typescript/lib/lib.dom.d.ts:1513:5
1513 redirect?: RequestRedirect;
~~~~~~~~
'redirect' was also declared here.
node_modules/@cloudflare/workers-types/index.d.ts:1183:3 - error TS2687: All declarations of 'read' must have identical modifiers.
1183 read: number;
~~~~
node_modules/@cloudflare/workers-types/index.d.ts:1183:3 - error TS2717: Subsequent property declarations must have the same type. Property 'read' must be of type 'number | undefined', but here has type 'number'.
1183 read: number;
~~~~
node_modules/typescript/lib/lib.dom.d.ts:1701:5
1701 read?: number;
~~~~
'read' was also declared here.
node_modules/@cloudflare/workers-types/index.d.ts:1184:3 - error TS2687: All declarations of 'written' must have identical modifiers.
1184 written: number;
~~~~~~~
node_modules/@cloudflare/workers-types/index.d.ts:1184:3 - error TS2717: Subsequent property declarations must have the same type. Property 'written' must be of type 'number | undefined', but here has type 'number'.
1184 written: number;
~~~~~~~
node_modules/typescript/lib/lib.dom.d.ts:1702:5
1702 written?: number;
~~~~~~~
'written' was also declared here.
node_modules/@cloudflare/workers-types/index.d.ts:1238:42 - error TS2508: No base constructor has the specified number of type arguments.
1238 declare abstract class WebSocket extends EventTarget<WebSocketEventMap> {
~~~~~~~~~~~
node_modules/@cloudflare/workers-types/index.d.ts:1248:50 - error TS2508: No base constructor has the specified number of type arguments.
1248 declare abstract class WorkerGlobalScope extends EventTarget<WorkerGlobalScopeEventMap> {
~~~~~~~~~~~
node_modules/@cloudflare/workers-types/index.d.ts:1278:102 - error TS2315: Type 'EventListenerOrEventListenerObject' is not generic.
1278 declare function addEventListener<Type extends keyof WorkerGlobalScopeEventMap>(type: Type, handler: EventListenerOrEventListenerObject<WorkerGlobalScopeEventMap[Type]>, options?: EventTargetAddEventListenerOptions | boolean): void;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
node_modules/@cloudflare/workers-types/index.d.ts:1300:105 - error TS2315: Type 'EventListenerOrEventListenerObject' is not generic.
1300 declare function removeEventListener<Type extends keyof WorkerGlobalScopeEventMap>(type: Type, handler: EventListenerOrEventListenerObject<WorkerGlobalScopeEventMap[Type]>, options?: EventTargetEventListenerOptions | boolean): void;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Found 41 errors.
Maybe something like this:
declare interface CFWorker<Environment = Record<string, unknown>> {
fetch(request: Request, env: Environment): Promise<Response>
}
Which would let a user:
declare type Environment = {
MYKV: KVNamespace
}
export default {
async fetch(request, env): Promise<Response> {
await env.MYKV.put('key', 'value')
return new Response('Hello, world!')
},
} as CFWorker<Environment>
Thank you for maintaining this package--it makes writing worker code so much easier.
I noticed there is a new method for KVNamespace: getWithMetadata()
. It is not in the type definitions, however, so I've had to patch it in myself:
declare global {
export interface KVNamespace {
getWithMetadata(key: string): KVValue<{ value: string; metadata: any }>
}
}
I'm sure that is not quite the best way to type the function. If you could add the proper type definition, I will give my cat an extra treat.
I may attempt to add the proper type definition and submit a PR.
The docs describe the properties that can be set on an outbound request, below the line "Cloudflare features all plans can set on outbound requests": https://developers.cloudflare.com/workers/reference/apis/request/
Some of these are missing from the CfRequestInit
type; we should add them:
Hey folks! Just a friendly bump if someone has npm publish access. There have been quite a number of changes since the last release. We've just been copy-pasting the source here into our own definition file, so we're not blocked per-say. Thanks ๐
looking at...
Lines 656 to 658 in ebb2043
should the txn
argument for the closure perhaps be of type DurableObjectTransaction
?
Some of the JS Fetch API is not implemented in Cloudflare Workers. One example of this is Body.blob()
on a Request
object, which is implemented in the JS Fetch API, but calling this function in a Cloudflare Worker will result in an error:
Failed to execute 'blob' on 'Body': the method is not implemented.
The Cloudflare Workers reference appears to agree (by omission) that Body.blob
is not implemented:
https://developers.cloudflare.com/workers/reference/apis/request/
However, when using the Request
type provided by the @cloudflare/worker-types
repo, using Body.blob
does not cause a type error and instead appears to be implemented:
Inspecting the types in this repo, it seems that the definition of Request
is purely additive (adding the cf
property) and does nothing to prohibit unimplemented properties:
interface Request {
cf: IncomingRequestCfProperties;
}
Before discovering the official types repo for Cloudflare Workers, I implemented TypeScript types for my Workers from scratch. In order to make the types for Cloudflare's Fetch API omit properties from the JS Fetch API, I defined custom types prefixed with Cf
, for example:
export default interface CfRequest {
readonly clone: () => CfRequest;
readonly cf: CfObject;
readonly bodyUsed: boolean;
readonly headers: Headers;
readonly method: RequestMethod;
readonly redirect: RequestRedirect;
readonly text: () => Promise<string>;
readonly url: string;
}
By generating a custom type that inherits nothing from the official Fetch API types, unimplemented properties like Body.blob
can be omitted.
Consider referencing https://github.com/cloudflare/kv-asset-handler/blob/master/RELEASE_CHECKLIST.md
It doesn't exist in the NPM registry. Did you forget to publish it?
npm ERR! code E404
npm ERR! 404 Not Found - GET https://registry.npmjs.org/@cloudflare%2fworkers-types - Not found
npm ERR! 404
npm ERR! 404 '@cloudflare/workers-types@^2.0.0' is not in the npm registry.
npm ERR! 404 You should bug the author to publish it (or use the name yourself!)
npm ERR! 404 It was specified as a dependency of 'url-shortener'
npm ERR! 404
npm ERR! 404 Note that you can also install from a
npm ERR! 404 tarball, folder, http url, or git url.
As per the docs, there is an asOrganization
property on the IncomingRequestCfProperties
object, which is currently missing from the type definition.
I'm having a problem while running tests using npm test
package.json
{
"name": "mypackage",
...
"main": "./lib/index.js",
"types": "./lib/index.d.ts",
"directories": {
"lib": "lib",
"test": "__tests__"
},
"files": [
"lib"
],
"publishConfig": {
"access": "public"
},
"scripts": {
"test": "jest",
"start": "tsc -w --preserveWatchOutput"
},
"devDependencies": {
"@cloudflare/workers-types": "^2.1.0",
"@testing-library/jest-dom": "^5.11.6",
"@types/jest": "^26.0.16",
"jest": "^26.6.3",
"ts-jest": "^26.4.4",
"typescript": "^4.1.2"
}
}
tsconfig.json
{
"compilerOptions": {
"target": "ES2020",
"module": "CommonJS",
"lib": ["ES2020", "WebWorker"],
"types": ["@cloudflare/workers-types", "jest"]
}
}
jest.config.js
module.exports = {
clearMocks: true,
coverageDirectory: "coverage",
coverageProvider: "v8",
preset: "ts-jest",
testEnvironment: "jsdom",
};
the code that breaks is the following
token.test.js
import * as token from './token';
describe("Token package", ()=> {
it("Can generate a token of specific length", ()=>{
for(var i=0; i< 10; i++) {
const expectedLength = 1 + Math.floor(Math.random()*64);
expect(token.generateRandomValue(expectedLength)).toBe(expect.stringMatching(/[a-z0-9]+/));
}
})
})
token.ts
export const generateRandomValue = (length:number) =>
crypto
.getRandomValues(new Uint16Array(45))
.reduce(
(acc, curr, i) =>
acc +
((curr + i) % 3 == 0
? curr.toString(36).toUpperCase()
: curr.toString(36)),
""
)
.substring(0, length);
I tried also to declare crypto in a setupTest.ts
file following https://stackoverflow.com/questions/52612122/how-to-use-jest-to-test-functions-using-crypto-or-window-mscrypto, but jest complains that I'm trying to re-declare crypto
.
Any ideas? I tried to play with the configuration but I haven't had any luck. Thank you.
DO states from DO that was generated with name are not being hinted at by the editor properly.
constructor(protected state: DurableObjectState, protected env) {
let string = state.id.name; // type hints as error?
}
It should be defined as name?: string;
get<T = unknown>(key: string): Promise<T>
should really be: `get<T = unknown>(key: string): Promise<T | undefined>;
The unioned type introduced by PR #18 does not allow re-assignment of properties. Consider the following snippet:
// this assignment works just fine
let init: RequestInit = {
cf: {
cacheKey: 'foo',
},
}
if (init.cf) {
// but re-writing properties is prevented by the type checker
init.cf.cacheKey = 'bar'
}
This produces the following type error:
The ideal outcome (if possible) would be to extend the RequestInit
that fetch
uses without obstructing the use case above while still supporting the example identified in issue #15.
Still trying to work out how to do this or if it's possible, but wanted to start a discussion around it :)
First, I know this is not the right place for this question. But I can't find the official worker runtime. Maybe it is an internal project?
I had an idea for a small extension to the runtime, but I don't know where to ask the question. That's why I have landed here and I thank you for your patience ๐ .
My desired extension would be to simplify listing of keys, by using "for await...of".
The current API allows for queries by prefix, but only up to a single 'limit' worth of items. Iterating for more items can be a bit awkward:
const value = await NAMESPACE.list({"prefix": "user:1:"})
let list_complete = value.list_complete
while (!list_complete) {
const cursor = value.cursor
const next_value = await NAMESPACE.list({"cursor": cursor})
list_complete = next_value.list_complete
// use values
}
This can be improved by supporting the "Symbol.asyncIterator" API. With that extension, iterating values could be as easy as:
for await (const value of NAMESPACE.list({"prefix": "user:1:"})) {
// use values
}
I hope that this proposal may be passed along, or you can point me in the right direction of where to take this feedback. But I also know that this may have been intentionally omitted. So either way, thanks for reading this ๐
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.