create new types for ember-cli-fastboot library (#58050)

* add type definitions for ember-cli-fastboot

* add comment block for services/fastboot.d.ts

* write tests

* fix CI issue around tsconfig files array

* remove tslint rules overrides

* Apply suggestions from code review

Co-authored-by: Chris Krycho <hello@chriskrycho.com>

* create actual FastBoot global type, address PR feedback

* turn on strict: true instead of individual rules

* fix FastBoot.config type to match method documentation in readme

* Apply suggestions from code review from @ckrycho

Co-authored-by: Chris Krycho <hello@chriskrycho.com>

* add v2 types

* Revert "add v2 types"

This reverts commit ad3e1c2fa1d0c3e62c54e78798a78c35c3e5b44c.

* re-trigger github checks

Co-authored-by: Henry Majoros <hmajoros@linkedin.com>
Co-authored-by: Chris Krycho <hello@chriskrycho.com>
This commit is contained in:
Hank Majoros
2022-01-19 14:31:22 -05:00
committed by GitHub
parent c6497d8455
commit dba3a2dc33
7 changed files with 160 additions and 0 deletions

View File

@@ -0,0 +1,5 @@
export interface FastBoot {
require: (id: string) => unknown;
config: (key: string) => unknown;
distPath: () => string;
}

17
types/ember-cli-fastboot/index.d.ts vendored Normal file
View File

@@ -0,0 +1,17 @@
// Type definitions for ember-cli-fastboot 2.2
// Project: https://github.com/ember-fastboot/ember-cli-fastboot
// Definitions by: Henry Majoros <https://github.com/hmajoros>
// Dan Freeman <https://github.com/dfreeman>
// Chris Krycho <https://github.com/chriskrycho>
// James C. Davis <https://github.com/jamescdavis>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 4.4
import './services/fastboot';
import { FastBoot } from './-private';
declare global {
const FastBoot: FastBoot | undefined;
}
export {};

View File

@@ -0,0 +1,83 @@
import Service from "@ember/service";
export interface FastbootRequest {
/** The cookies for the current request. */
cookies: Record<string, unknown>;
/** The headers for the current request. */
headers: Pick<Headers, "has" | "get">;
/**
* The host of the request that the current FastBoot server is responding to
* (`example.com` or `localhost:3000`).
* Retrieving host will error on 2 conditions:
* 1. you do not have a hostWhitelist defined
* 2. the Host header does not match an entry in your hostWhitelist
*/
host: string;
/** The query parameters for the current request, as a key-value pair. */
queryParams: Record<string, unknown>;
/**
* The path (`/` or `/some-path`) of the request that the current FastBoot
* server is responding to.
*/
path: string;
/**
* The protocol (`http:` or `https:`) of the request that the current
* FastBoot server is responding to.
*/
protocol: string;
}
export interface Shoebox {
put(key: string, value: unknown): void;
retrieve(key: string): unknown;
}
export default class FastBoot extends Service {
/** Allows you to check if you are running within FastBoot. */
isFastboot: boolean;
/**
* A request object which exposes details about the current request being
* handled by FastBoot.
*/
request: FastbootRequest;
/**
* You can pass application state from the FastBoot rendered application to
* the browser rendered application using a feature called the "Shoebox".
* This allows you to leverage server API calls made by the FastBoot rendered
* application on the browser rendered application. Thus preventing you from
* duplicating work that the FastBoot application is performing. This should
* result in a performance benefit for your browser application, as it does
* not need to issue server API calls whose results are available from the
* Shoebox.
*/
shoebox: Shoebox;
/**
* By default, FastBoot waits for the `beforeModel`, `model`, and
* `afterModel` hooks to resolve before sending the response back to the
* client. If you have asynchrony that runs outside of those contexts, your
* response may not reflect the state that you want.
* To solve this, the `fastboot` service has `deferRendering` method that
* accepts a promise. It will chain all promises passed to it, and the
* FastBoot server will wait until all of these promises resolve before
* sending the response to the client. These promises must be chained before
* the rendering is complete after the model hooks. For example, if a
* component that is rendered into the page makes an async call for data,
* registering a promise to be resolved in its `init` hook would allow the
* component to defer the rendering of the page.
*/
deferRendering(promise: Promise<unknown>): void;
}
declare module "@ember/service" {
interface ServiceRegistry {
fastboot: FastBoot;
}
}

View File

@@ -0,0 +1,5 @@
/** Static assertion that `value` has type `T` */
// Disable tslint here b/c the generic is used to let us do a type coercion and
// validate that coercion works for the type value "passed into" the function.
// tslint:disable-next-line:no-unnecessary-generics
export declare function assertType<T>(value: T): void;

View File

@@ -0,0 +1,23 @@
import { assertType } from './assert';
import FastBootService, { FastbootRequest, Shoebox } from 'ember-cli-fastboot/services/fastboot';
import { FastBoot as _FastBoot } from 'ember-cli-fastboot/-private';
/** type assertions for global FastBoot object */
assertType<_FastBoot | undefined>(FastBoot);
/** type assertions for fastboot service & other classes */
const instance = FastBootService.create();
assertType<FastbootRequest>(instance.request);
assertType<boolean>(instance.isFastboot);
assertType<Shoebox>(instance.shoebox);
instance.deferRendering(new Promise<'foo'>(() => 'foo')); // $ExpectType void
instance.shoebox.put('foo', 'bar'); // $ExpectType void
instance.shoebox.retrieve('foo'); // $ExpectType unknown
assertType<Record<string, unknown>>(instance.request.cookies);
assertType<Pick<Headers, 'has' | 'get'>>(instance.request.headers);
assertType<string>(instance.request.host);
assertType<Record<string, unknown>>(instance.request.queryParams);
assertType<string>(instance.request.path);
assertType<string>(instance.request.protocol);

View File

@@ -0,0 +1,24 @@
{
"compilerOptions": {
"module": "commonjs",
"lib": [
"es6",
"dom"
],
"strict": true,
"baseUrl": "../",
"typeRoots": [
"../"
],
"types": [],
"paths": {
"@ember/*": ["ember__*"]
},
"noEmit": true,
"forceConsistentCasingInFileNames": true
},
"files": [
"index.d.ts",
"test/ember-cli-fastboot-tests.ts"
]
}

View File

@@ -0,0 +1,3 @@
{
"extends": "@definitelytyped/dtslint/dt.json"
}