mirror of
https://github.com/gosticks/DefinitelyTyped.git
synced 2025-10-16 12:05:41 +00:00
Update Ember, RSVP, and Ember testing helpers. (#20301)
* Update RSVP to 4.0, to implement PromiseLike<T>. - RSVP Promises can now be used with `async` and `await`. - RSVP types now match what is in RSVP 4.0. * Update ember-testing-helpers for fixed RSVP. * Ember.js: correctly represent most of the framework. - Capture the actual behavior of most of the framework, including computed properties, custom getters and setters and the custom Object model more generally, prototype extension via `.extend`, and the mixin pattern. - Support the new modules API alongside the global API. - Add extensive tests. - Update inline documentation. - Use the new, async/await compatible RSVP definitions. * Ember/RSVP: drop .prettierrc files. * Drop types/rsvp/assert.ts -- stick to just rsvp-test.ts. * Fix ember-testing-helpers-tests on top of module itself. * Fix RSVP import in ember-testing-helpers. * Fix 'typeRoots', set ember-testing-helpers to use TS 2.4. * Fix missing 'types' compiler option. * Fix errors caught by dtslint. * A few more tslint tweaks. * Fix account link in ember-testing-helpers authorship. * Disable strictFunctionTypes for Ember, RSVP. * fix array.reduce signature conflict in ts@next
This commit is contained in:
parent
e176bdbdff
commit
dfa4555106
@ -1,12 +1,12 @@
|
||||
import RSVP = require('rsvp');
|
||||
import RSVP from 'rsvp';
|
||||
|
||||
function testAndThen() {
|
||||
const result: RSVP.Promise<string, never> = andThen(() => 'some string');
|
||||
const result: RSVP.Promise<string> = andThen(() => 'some string');
|
||||
result.then(s => s.length);
|
||||
}
|
||||
|
||||
function testClick() {
|
||||
const result: RSVP.Promise<void, never> = click('someString');
|
||||
const result: RSVP.Promise<void> = click('someString');
|
||||
result.then(() => {});
|
||||
}
|
||||
|
||||
@ -29,7 +29,7 @@ function testFillIn() {
|
||||
const textResult = fillIn('.foo', 'waffles');
|
||||
textResult.then(() => true);
|
||||
const contextResult = fillIn('.bar', {}, 'pancakes');
|
||||
contextResult.catch(reason => false);
|
||||
contextResult.catch((reason: any) => false);
|
||||
}
|
||||
|
||||
function testFind() {
|
||||
|
||||
12
types/ember-testing-helpers/index.d.ts
vendored
12
types/ember-testing-helpers/index.d.ts
vendored
@ -1,8 +1,8 @@
|
||||
// Type definitions for ember-testing/lib/helpers
|
||||
// Project: https://github.com/emberjs/ember.js/tree/master/packages/ember-testing/lib/helpers
|
||||
// Definitions by: Chris Krycho <github.com/chriskrycho>
|
||||
// Definitions by: Chris Krycho <https://github.com/chriskrycho>
|
||||
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
|
||||
// TypeScript Version: 2.3
|
||||
// TypeScript Version: 2.4
|
||||
|
||||
// Note that these are distributed separately because they represent a discrete
|
||||
// set of functionality, and as globally-injected items (as of Ember 2.13), are
|
||||
@ -10,14 +10,14 @@
|
||||
|
||||
/// <reference types="jquery" />
|
||||
|
||||
import RSVP = require('rsvp');
|
||||
import RSVP from 'rsvp';
|
||||
|
||||
type KeyEventType = 'keydown' | 'keyup' | 'keypress';
|
||||
type WaitResult<T> = RSVP.Promise<T, never>;
|
||||
type WaitResult<T> = RSVP.Promise<T>;
|
||||
|
||||
declare global {
|
||||
// https://github.com/emberjs/ember.js/blob/master/packages/ember-testing/lib/helpers/and_then.js
|
||||
function andThen<T>(callback: (...args: any[]) => T): RSVP.Promise<T, never>;
|
||||
function andThen<T>(callback: (...args: any[]) => T): RSVP.Promise<T>;
|
||||
|
||||
// https://github.com/emberjs/ember.js/blob/master/packages/ember-testing/lib/helpers/click.js
|
||||
function click(selector: string, context?: Object): WaitResult<void>;
|
||||
@ -45,7 +45,7 @@ declare global {
|
||||
function keyEvent(selector: string, type: KeyEventType, keyCode: number): WaitResult<void>;
|
||||
|
||||
// https://github.com/emberjs/ember.js/blob/master/packages/ember-testing/lib/helpers/pause_test.js
|
||||
function pauseTest(): RSVP.Promise<{}, never>;
|
||||
function pauseTest(): RSVP.Promise<{}>;
|
||||
function resumeTest(): void;
|
||||
|
||||
// https://github.com/emberjs/ember.js/blob/master/packages/ember-testing/lib/helpers/trigger_event.js
|
||||
|
||||
@ -10,9 +10,7 @@
|
||||
"strictNullChecks": true,
|
||||
"strictFunctionTypes": true,
|
||||
"baseUrl": "../",
|
||||
"typeRoots": [
|
||||
"../"
|
||||
],
|
||||
"typeRoots": ["../"],
|
||||
"types": [],
|
||||
"noEmit": true,
|
||||
"forceConsistentCasingInFileNames": true
|
||||
|
||||
6151
types/ember/index.d.ts
vendored
Normal file → Executable file
6151
types/ember/index.d.ts
vendored
Normal file → Executable file
File diff suppressed because it is too large
Load Diff
15
types/ember/test/application.ts
Executable file
15
types/ember/test/application.ts
Executable file
@ -0,0 +1,15 @@
|
||||
import Ember from 'ember';
|
||||
import { assertType } from "./lib/assert";
|
||||
|
||||
let App = Ember.Application.create({
|
||||
customEvents: {
|
||||
paste: 'paste'
|
||||
}
|
||||
});
|
||||
|
||||
let App2 = Ember.Application.create({
|
||||
customEvents: {
|
||||
mouseenter: null,
|
||||
mouseleave: null
|
||||
}
|
||||
});
|
||||
18
types/ember/test/array-ext.ts
Executable file
18
types/ember/test/array-ext.ts
Executable file
@ -0,0 +1,18 @@
|
||||
import Ember from 'ember';
|
||||
import { assertType } from './lib/assert';
|
||||
|
||||
declare global {
|
||||
interface Array<T> extends Ember.ArrayPrototypeExtensions<T> {}
|
||||
}
|
||||
|
||||
class Person extends Ember.Object {
|
||||
name: string;
|
||||
}
|
||||
|
||||
const person = Person.create({ name: 'Joe' });
|
||||
const array = [person];
|
||||
|
||||
assertType<number>(array.get('length'));
|
||||
assertType<Person | undefined>(array.get('firstObject'));
|
||||
assertType<string[]>(array.mapBy('name'));
|
||||
assertType<string[]>(array.map(p => p.get('name')));
|
||||
26
types/ember/test/array-proxy.ts
Executable file
26
types/ember/test/array-proxy.ts
Executable file
@ -0,0 +1,26 @@
|
||||
import Ember from 'ember';
|
||||
import { assertType } from './lib/assert';
|
||||
|
||||
const pets = ['dog', 'cat', 'fish'];
|
||||
const proxy = Ember.ArrayProxy.create({ content: Ember.A(pets) });
|
||||
|
||||
proxy.get('firstObject'); // 'dog'
|
||||
proxy.set('content', Ember.A(['amoeba', 'paramecium']));
|
||||
proxy.get('firstObject'); // 'amoeba'
|
||||
|
||||
const overridden = Ember.ArrayProxy.create({
|
||||
content: Ember.A(pets),
|
||||
objectAtContent(idx: number): string {
|
||||
return this.get('content').objectAt(idx)!.toUpperCase();
|
||||
}
|
||||
});
|
||||
|
||||
overridden.get('firstObject'); // 'DOG'
|
||||
|
||||
class MyNewProxy<T> extends Ember.ArrayProxy<T> {
|
||||
isNew = true;
|
||||
}
|
||||
|
||||
let x: MyNewProxy<number> = MyNewProxy.create({ content: Ember.A([1, 2, 3]) });
|
||||
assertType<number | undefined>(x.get('firstObject'));
|
||||
assertType<boolean>(x.isNew);
|
||||
46
types/ember/test/array.ts
Executable file
46
types/ember/test/array.ts
Executable file
@ -0,0 +1,46 @@
|
||||
import Ember from 'ember';
|
||||
import { assertType } from './lib/assert';
|
||||
|
||||
type Person = typeof Person.prototype;
|
||||
const Person = Ember.Object.extend({
|
||||
name: '',
|
||||
isHappy: false
|
||||
});
|
||||
|
||||
const people = Ember.A([
|
||||
Person.create({ name: 'Yehuda', isHappy: true }),
|
||||
Person.create({ name: 'Majd', isHappy: false }),
|
||||
]);
|
||||
|
||||
assertType<number>(people.get('length'));
|
||||
assertType<Person>(people.get('lastObject'));
|
||||
assertType<boolean>(people.isAny('isHappy'));
|
||||
assertType<boolean>(people.isAny('isHappy', false));
|
||||
assertType<Person[]>(people.filterBy('isHappy'));
|
||||
assertType<typeof people>(people.get('[]'));
|
||||
assertType<Person>(people.get('[]').get('firstObject'));
|
||||
|
||||
assertType<Ember.Array<boolean>>(people.mapBy('isHappy'));
|
||||
assertType<any[]>(people.mapBy('name.length'));
|
||||
|
||||
const last = people.get('lastObject');
|
||||
if (last) {
|
||||
assertType<string>(last.get('name'));
|
||||
}
|
||||
|
||||
const first = people.get('lastObject');
|
||||
if (first) {
|
||||
assertType<boolean>(first.get('isHappy'));
|
||||
}
|
||||
|
||||
const letters: Ember.Enumerable<string> = Ember.A(['a', 'b', 'c']);
|
||||
const codes: number[] = letters.map((item, index, enumerable) => {
|
||||
assertType<string>(item);
|
||||
assertType<number>(index);
|
||||
return item.charCodeAt(0);
|
||||
});
|
||||
|
||||
let value = '1,2,3';
|
||||
let filters = Ember.A(value.split(','));
|
||||
filters.push('4');
|
||||
filters.sort();
|
||||
124
types/ember/test/component.ts
Executable file
124
types/ember/test/component.ts
Executable file
@ -0,0 +1,124 @@
|
||||
import Ember from 'ember';
|
||||
import Component from '@ember/component';
|
||||
import Object, { computed } from '@ember/object';
|
||||
import hbs from 'htmlbars-inline-precompile';
|
||||
import { assertType } from "./lib/assert";
|
||||
|
||||
Component.extend({
|
||||
layout: hbs`
|
||||
<div>
|
||||
{{yield}}
|
||||
</div>
|
||||
`,
|
||||
});
|
||||
|
||||
Component.extend({
|
||||
layout: 'my-layout',
|
||||
});
|
||||
|
||||
const MyComponent = Component.extend();
|
||||
assertType<string | string[]>(Ember.get(MyComponent, 'positionalParams'));
|
||||
|
||||
const component1 = Component.extend({
|
||||
actions: {
|
||||
hello(name: string) {
|
||||
console.log('Hello', name);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
Component.extend({
|
||||
name: '',
|
||||
hello(name: string) {
|
||||
this.set('name', name);
|
||||
},
|
||||
});
|
||||
|
||||
Component.extend({
|
||||
tagName: 'em',
|
||||
});
|
||||
|
||||
Component.extend({
|
||||
classNames: ['my-class', 'my-other-class'],
|
||||
});
|
||||
|
||||
Component.extend({
|
||||
classNameBindings: ['propertyA', 'propertyB'],
|
||||
propertyA: 'from-a',
|
||||
propertyB: computed(function() {
|
||||
if (!this.get('propertyA')) {
|
||||
return 'from-b';
|
||||
}
|
||||
}),
|
||||
});
|
||||
|
||||
Component.extend({
|
||||
classNameBindings: ['hovered'],
|
||||
hovered: true,
|
||||
});
|
||||
|
||||
Component.extend({
|
||||
classNameBindings: ['messages.empty'],
|
||||
messages: Object.create({
|
||||
empty: true,
|
||||
}),
|
||||
});
|
||||
|
||||
Component.extend({
|
||||
classNameBindings: ['isEnabled:enabled:disabled'],
|
||||
isEnabled: true,
|
||||
});
|
||||
|
||||
Component.extend({
|
||||
classNameBindings: ['isEnabled::disabled'],
|
||||
isEnabled: true,
|
||||
});
|
||||
|
||||
Component.extend({
|
||||
tagName: 'a',
|
||||
attributeBindings: ['href'],
|
||||
href: 'http://google.com',
|
||||
});
|
||||
|
||||
Component.extend({
|
||||
tagName: 'a',
|
||||
attributeBindings: ['url:href'],
|
||||
url: 'http://google.com',
|
||||
});
|
||||
|
||||
Component.extend({
|
||||
tagName: 'use',
|
||||
attributeBindings: ['xlinkHref:xlink:href'],
|
||||
xlinkHref: '#triangle',
|
||||
});
|
||||
|
||||
Component.extend({
|
||||
tagName: 'input',
|
||||
attributeBindings: ['disabled'],
|
||||
disabled: false,
|
||||
});
|
||||
|
||||
Component.extend({
|
||||
tagName: 'input',
|
||||
attributeBindings: ['disabled'],
|
||||
disabled: computed(() => {
|
||||
if ('someLogic') {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}),
|
||||
});
|
||||
|
||||
Component.extend({
|
||||
tagName: 'form',
|
||||
attributeBindings: ['novalidate'],
|
||||
novalidate: null,
|
||||
});
|
||||
|
||||
Component.extend({
|
||||
click(event: object) {
|
||||
// will be called when an instance's
|
||||
// rendered element is clicked
|
||||
},
|
||||
});
|
||||
160
types/ember/test/computed.ts
Executable file
160
types/ember/test/computed.ts
Executable file
@ -0,0 +1,160 @@
|
||||
import Ember from 'ember';
|
||||
import Component from '@ember/component';
|
||||
import { or } from '@ember/object/computed';
|
||||
import { assertType } from './lib/assert';
|
||||
|
||||
const Person = Ember.Object.extend({
|
||||
firstName: '',
|
||||
lastName: '',
|
||||
age: 0,
|
||||
|
||||
noArgs: Ember.computed<string>(() => 'test'),
|
||||
|
||||
fullName: Ember.computed<string>('firstName', 'lastName', function() {
|
||||
return `${this.get('firstName')} ${this.get('lastName')}`;
|
||||
}),
|
||||
|
||||
fullNameReadonly: Ember.computed<string>('fullName', function() {
|
||||
return this.get('fullName');
|
||||
}).readOnly(),
|
||||
|
||||
fullNameWritable: Ember.computed<string>('firstName', 'lastName', {
|
||||
get() {
|
||||
return this.get('fullName');
|
||||
},
|
||||
set(key, value) {
|
||||
let [first, last] = value.split(' ');
|
||||
this.set('firstName', first);
|
||||
this.set('lastName', last);
|
||||
return value;
|
||||
}
|
||||
}),
|
||||
|
||||
fullNameGetOnly: Ember.computed<string>('fullName', {
|
||||
get() {
|
||||
return this.get('fullName');
|
||||
}
|
||||
}),
|
||||
|
||||
fullNameSetOnly: Ember.computed<string>('firstName', 'lastName', {
|
||||
set(key, value) {
|
||||
let [first, last] = value.split(' ');
|
||||
this.set('firstName', first);
|
||||
this.set('lastName', last);
|
||||
return value;
|
||||
}
|
||||
}),
|
||||
|
||||
combinators: Ember.computed<string>(function() {
|
||||
return this.get('firstName');
|
||||
}).property('firstName')
|
||||
.meta({ foo: 'bar' })
|
||||
.volatile()
|
||||
.readOnly()
|
||||
});
|
||||
|
||||
const person = Person.create({
|
||||
firstName: 'Fred',
|
||||
lastName: 'Smith',
|
||||
age: 29,
|
||||
});
|
||||
|
||||
assertType<string>(person.firstName);
|
||||
assertType<number>(person.age);
|
||||
assertType<Ember.ComputedProperty<string>>(person.noArgs);
|
||||
assertType<Ember.ComputedProperty<string>>(person.fullName);
|
||||
assertType<Ember.ComputedProperty<string>>(person.fullNameReadonly);
|
||||
assertType<Ember.ComputedProperty<string>>(person.fullNameWritable);
|
||||
assertType<Ember.ComputedProperty<string>>(person.fullNameGetOnly);
|
||||
assertType<Ember.ComputedProperty<string>>(person.fullNameSetOnly);
|
||||
assertType<Ember.ComputedProperty<string>>(person.combinators);
|
||||
|
||||
assertType<string>(person.get('firstName'));
|
||||
assertType<number>(person.get('age'));
|
||||
assertType<string>(person.get('noArgs'));
|
||||
assertType<string>(person.get('fullName'));
|
||||
assertType<string>(person.get('fullNameReadonly'));
|
||||
assertType<string>(person.get('fullNameWritable'));
|
||||
assertType<string>(person.get('fullNameGetOnly'));
|
||||
assertType<string>(person.get('fullNameSetOnly'));
|
||||
assertType<string>(person.get('combinators'));
|
||||
|
||||
assertType<{ firstName: string, fullName: string, age: number }>(person.getProperties('firstName', 'fullName', 'age'));
|
||||
|
||||
const person2 = Person.create({
|
||||
fullName: 'Fred Smith'
|
||||
});
|
||||
|
||||
assertType<string>(person2.get('firstName'));
|
||||
assertType<string>(person2.get('fullName'));
|
||||
|
||||
const person3 = Person.extend({
|
||||
firstName: 'Fred',
|
||||
fullName: 'Fred Smith'
|
||||
}).create();
|
||||
|
||||
assertType<string>(person3.get('firstName'));
|
||||
assertType<string>(person3.get('fullName'));
|
||||
|
||||
const person4 = Person.extend({
|
||||
firstName: Ember.computed(() => 'Fred'),
|
||||
fullName: Ember.computed(() => 'Fred Smith')
|
||||
}).create();
|
||||
|
||||
assertType<string>(person4.get('firstName'));
|
||||
assertType<string>(person4.get('fullName'));
|
||||
|
||||
// computed property macros
|
||||
const objectWithComputedProperties = Ember.Object.extend({
|
||||
alias: Ember.computed.alias('foo'),
|
||||
and: Ember.computed.and('foo', 'bar', 'baz', 'qux'),
|
||||
bool: Ember.computed.bool('foo'),
|
||||
collect: Ember.computed.collect('foo', 'bar', 'baz', 'qux'),
|
||||
deprecatingAlias: Ember.computed.deprecatingAlias('foo', {
|
||||
id: 'hamster.deprecate-banana',
|
||||
until: '3.0.0'
|
||||
}),
|
||||
empty: Ember.computed.empty('foo'),
|
||||
equalNumber: Ember.computed.equal('foo', 1),
|
||||
equalString: Ember.computed.equal('foo', 'bar'),
|
||||
equalObject: Ember.computed.equal('foo', {}),
|
||||
filter: Ember.computed.filter('foo', (item) => item === 'bar'),
|
||||
filterBy1: Ember.computed.filterBy('foo', 'bar'),
|
||||
filterBy2: Ember.computed.filterBy('foo', 'bar', false),
|
||||
gt: Ember.computed.gt('foo', 3),
|
||||
gte: Ember.computed.gte('foo', 3),
|
||||
intersect: Ember.computed.intersect('foo', 'bar', 'baz', 'qux'),
|
||||
lt: Ember.computed.lt('foo', 3),
|
||||
lte: Ember.computed.lte('foo', 3),
|
||||
map: Ember.computed.map('foo', (item, index) => item.bar),
|
||||
mapBy: Ember.computed.mapBy('foo', 'bar'),
|
||||
match: Ember.computed.match('foo', /^tom.ter$/),
|
||||
max: Ember.computed.max('foo'),
|
||||
min: Ember.computed.min('foo'),
|
||||
none: Ember.computed.none('foo'),
|
||||
not: Ember.computed.not('foo'),
|
||||
notEmpty: Ember.computed.notEmpty('foo'),
|
||||
oneWay: Ember.computed.oneWay('foo'),
|
||||
or: Ember.computed.or('foo', 'bar', 'baz', 'qux'),
|
||||
readOnly: Ember.computed.readOnly('foo'),
|
||||
reads: Ember.computed.reads('foo'),
|
||||
setDiff: Ember.computed.setDiff('foo', 'bar'),
|
||||
sort1: Ember.computed.sort('foo', 'bar'),
|
||||
sort2: Ember.computed.sort('foo', (itemA, itemB) => {
|
||||
if (itemA < itemB) {
|
||||
return -1;
|
||||
} else if (itemA > itemB) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}),
|
||||
sum: Ember.computed.sum('foo'),
|
||||
union: Ember.computed.union('foo', 'bar', 'baz', 'qux'),
|
||||
uniq: Ember.computed.uniq('foo'),
|
||||
uniqBy: Ember.computed.uniqBy('foo', 'bar')
|
||||
});
|
||||
|
||||
const component2 = Component.extend({
|
||||
isAnimal: or('isDog', 'isCat')
|
||||
});
|
||||
11
types/ember/test/controller.ts
Executable file
11
types/ember/test/controller.ts
Executable file
@ -0,0 +1,11 @@
|
||||
import Controller from '@ember/controller';
|
||||
|
||||
Controller.extend ({
|
||||
queryParams: ['category'],
|
||||
category: null,
|
||||
isExpanded: false,
|
||||
|
||||
toggleBody() {
|
||||
this.toggleProperty('isExpanded');
|
||||
}
|
||||
});
|
||||
7
types/ember/test/create.ts
Executable file
7
types/ember/test/create.ts
Executable file
@ -0,0 +1,7 @@
|
||||
import Ember from 'ember';
|
||||
import { assertType } from './lib/assert';
|
||||
|
||||
const obj = Ember.Object.create({ a: 1 }, { b: 2 }, { c: 3 });
|
||||
assertType<number>(obj.a);
|
||||
assertType<number>(obj.b);
|
||||
assertType<number>(obj.c);
|
||||
20
types/ember/test/detect-instance.ts
Executable file
20
types/ember/test/detect-instance.ts
Executable file
@ -0,0 +1,20 @@
|
||||
import Ember from 'ember';
|
||||
import { assertType } from './lib/assert';
|
||||
|
||||
const ExtendClass = Ember.Object.extend({
|
||||
foo: 'hello'
|
||||
});
|
||||
|
||||
class ES6Class extends Ember.Object {
|
||||
bar: string;
|
||||
}
|
||||
|
||||
let testObject = null;
|
||||
|
||||
if (ExtendClass.detectInstance(testObject)) {
|
||||
assertType<string>(testObject.foo);
|
||||
}
|
||||
|
||||
if (ES6Class.detectInstance(testObject)) {
|
||||
assertType<string>(testObject.bar);
|
||||
}
|
||||
20
types/ember/test/detect.ts
Executable file
20
types/ember/test/detect.ts
Executable file
@ -0,0 +1,20 @@
|
||||
import Ember from 'ember';
|
||||
import { assertType } from './lib/assert';
|
||||
|
||||
const ExtendClass = Ember.Object.extend({
|
||||
foo: 'hello'
|
||||
});
|
||||
|
||||
class ES6Class extends Ember.Object {
|
||||
bar: string;
|
||||
}
|
||||
|
||||
let TestClass = Ember.Object;
|
||||
|
||||
if (ExtendClass.detect(TestClass)) {
|
||||
assertType<string>(TestClass.create().foo);
|
||||
}
|
||||
|
||||
if (ES6Class.detect(TestClass)) {
|
||||
assertType<string>(TestClass.create().bar);
|
||||
}
|
||||
81
types/ember/ember-tests.ts → types/ember/test/ember-tests.ts
Normal file → Executable file
81
types/ember/ember-tests.ts → types/ember/test/ember-tests.ts
Normal file → Executable file
@ -2,8 +2,7 @@ import Ember from 'ember';
|
||||
|
||||
let App: any;
|
||||
|
||||
App = Ember.Application.create<Ember.Application>();
|
||||
|
||||
App = Ember.Application.create();
|
||||
App.president = Ember.Object.create({
|
||||
name: 'Barack Obama',
|
||||
});
|
||||
@ -23,8 +22,9 @@ App.president.get('fullName');
|
||||
declare class MyPerson extends Ember.Object {
|
||||
static createMan(): MyPerson;
|
||||
}
|
||||
MyPerson.createMan();
|
||||
|
||||
const Person1 = Ember.Object.extend<typeof MyPerson>({
|
||||
const Person1 = Ember.Object.extend({
|
||||
say: (thing: string) => {
|
||||
alert(thing);
|
||||
},
|
||||
@ -33,7 +33,9 @@ const Person1 = Ember.Object.extend<typeof MyPerson>({
|
||||
declare class MyPerson2 extends Ember.Object {
|
||||
helloWorld(): void;
|
||||
}
|
||||
const tom = Person1.create<MyPerson2>({
|
||||
MyPerson2.create().helloWorld();
|
||||
|
||||
const tom = Person1.create({
|
||||
name: 'Tom Dale',
|
||||
helloWorld() {
|
||||
this.say('Hi my name is ' + this.get('name'));
|
||||
@ -41,23 +43,8 @@ const tom = Person1.create<MyPerson2>({
|
||||
});
|
||||
tom.helloWorld();
|
||||
|
||||
Person1.reopen({ isPerson: true });
|
||||
Person1.create<Ember.Object>().get('isPerson');
|
||||
|
||||
Person1.reopenClass({
|
||||
createMan: () => {
|
||||
return Person1.create({ isMan: true });
|
||||
},
|
||||
});
|
||||
// ReSharper disable once DuplicatingLocalDeclaration
|
||||
Person1.createMan().get('isMan');
|
||||
|
||||
const person = Person1.create<Ember.Object>({
|
||||
firstName: 'Yehuda',
|
||||
lastName: 'Katz',
|
||||
});
|
||||
person.addObserver('fullName', null, () => {});
|
||||
person.set('firstName', 'Brohuda');
|
||||
const PersonReopened = Person1.reopen({ isPerson: true });
|
||||
PersonReopened.create().get('isPerson');
|
||||
|
||||
App.todosController = Ember.Object.create({
|
||||
todos: [Ember.Object.create({ isDone: false })],
|
||||
@ -105,17 +92,6 @@ App.userController = Ember.Object.create({
|
||||
}),
|
||||
});
|
||||
|
||||
Ember.Helper.helper(params => {
|
||||
const cents = params[0];
|
||||
return `${cents * 0.01}`;
|
||||
});
|
||||
|
||||
Ember.Helper.helper((params, hash) => {
|
||||
const cents = params[0];
|
||||
const currency = hash.currency;
|
||||
return `${currency}${cents * 0.01}`;
|
||||
});
|
||||
|
||||
Handlebars.registerHelper(
|
||||
'highlight',
|
||||
(property: string, options: any) =>
|
||||
@ -124,7 +100,8 @@ Handlebars.registerHelper(
|
||||
|
||||
const coolView = App.CoolView.create();
|
||||
|
||||
const Person2 = Ember.Object.extend<typeof Ember.Object>({
|
||||
const Person2 = Ember.Object.extend({
|
||||
name: '',
|
||||
sayHello() {
|
||||
console.log('Hello from ' + this.get('name'));
|
||||
},
|
||||
@ -140,24 +117,25 @@ const arr = Ember.A([Ember.Object.create(), Ember.Object.create()]);
|
||||
arr.setEach('name', 'unknown');
|
||||
arr.getEach('name');
|
||||
|
||||
const Person3 = Ember.Object.extend<typeof Ember.Object>({
|
||||
name: null,
|
||||
const Person3 = Ember.Object.extend({
|
||||
name: '',
|
||||
isHappy: false,
|
||||
});
|
||||
const people2 = Ember.A([
|
||||
Person3.create({ name: 'Yehuda', isHappy: true }),
|
||||
Person3.create({ name: 'Majd', isHappy: false }),
|
||||
]);
|
||||
const isHappy = (person: Ember.Object): Boolean => {
|
||||
const isHappy = (person: typeof Person3.prototype): boolean => {
|
||||
return !!person.get('isHappy');
|
||||
};
|
||||
people2.every(isHappy);
|
||||
people2.any(isHappy);
|
||||
people2.everyProperty('isHappy', true);
|
||||
people2.someProperty('isHappy', true);
|
||||
people2.isEvery('isHappy', true);
|
||||
people2.isAny('isHappy', true);
|
||||
people2.isAny('isHappy');
|
||||
|
||||
// Examples taken from http://emberjs.com/api/classes/Em.RSVP.Promise.html
|
||||
const promise = new Ember.RSVP.Promise<string, string>((resolve: Function, reject: Function) => {
|
||||
const promise = new Ember.RSVP.Promise<string>((resolve: Function, reject: Function) => {
|
||||
// on success
|
||||
resolve('ok!');
|
||||
|
||||
@ -174,6 +152,9 @@ promise.then(
|
||||
}
|
||||
);
|
||||
|
||||
// make sure Ember.RSVP.Promise can be reference as a type
|
||||
declare function promiseReturningFunction(urn: string): Ember.RSVP.Promise<string>;
|
||||
|
||||
const mix1 = Ember.Mixin.create({
|
||||
foo: 1,
|
||||
});
|
||||
@ -182,27 +163,7 @@ const mix2 = Ember.Mixin.create({
|
||||
bar: 2,
|
||||
});
|
||||
|
||||
const mix3 = Ember.Mixin.create({
|
||||
foo: 3,
|
||||
});
|
||||
|
||||
const mix4 = Ember.Mixin.create({
|
||||
bar: 4,
|
||||
});
|
||||
|
||||
const mix5 = Ember.Mixin.create({
|
||||
foo: 5,
|
||||
});
|
||||
|
||||
const mix6 = Ember.Mixin.create({
|
||||
bar: 6,
|
||||
});
|
||||
|
||||
const mix7 = Ember.Mixin.create({
|
||||
foo: 7,
|
||||
});
|
||||
|
||||
const component1 = Ember.Component.extend(mix1, mix2, mix3, mix4, mix5, mix6, mix7, {
|
||||
const component1 = Ember.Component.extend(mix1, mix2, {
|
||||
lyft: Ember.inject.service(),
|
||||
cars: Ember.computed.readOnly('lyft.cars'),
|
||||
});
|
||||
58
types/ember/test/event.ts
Executable file
58
types/ember/test/event.ts
Executable file
@ -0,0 +1,58 @@
|
||||
import Ember from 'ember';
|
||||
|
||||
function testOn() {
|
||||
let Job = Ember.Object.extend({
|
||||
logCompleted: Ember.on('completed', function() {
|
||||
console.log('Job completed!');
|
||||
})
|
||||
});
|
||||
|
||||
let job = Job.create();
|
||||
|
||||
Ember.sendEvent(job, 'completed'); // Logs 'Job completed!'
|
||||
}
|
||||
|
||||
function testEvented() {
|
||||
let Person = Ember.Object.extend(Ember.Evented, {
|
||||
greet() {
|
||||
this.trigger('greet');
|
||||
}
|
||||
});
|
||||
|
||||
let person = Person.create();
|
||||
|
||||
person.on('greet', function() {
|
||||
console.log('Our person has greeted');
|
||||
});
|
||||
|
||||
person.on('greet', function() {
|
||||
console.log('Our person has greeted');
|
||||
}).one('greet', function() {
|
||||
console.log('Offer one-time special');
|
||||
}).off('event', {}, function() {});
|
||||
|
||||
person.greet();
|
||||
}
|
||||
|
||||
function testObserver() {
|
||||
Ember.Object.extend({
|
||||
valueObserver: Ember.observer('value', function() {
|
||||
// Executes whenever the "value" property changes
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
function testListener() {
|
||||
Ember.Component.extend({
|
||||
init() {
|
||||
Ember.addListener(this, 'willDestroyElement', this, 'willDestroyListener');
|
||||
Ember.addListener(this, 'willDestroyElement', this, 'willDestroyListener', true);
|
||||
Ember.addListener(this, 'willDestroyElement', this, this.willDestroyListener);
|
||||
Ember.addListener(this, 'willDestroyElement', this, this.willDestroyListener, true);
|
||||
Ember.removeListener(this, 'willDestroyElement', this, 'willDestroyListener');
|
||||
Ember.removeListener(this, 'willDestroyElement', this, this.willDestroyListener);
|
||||
},
|
||||
willDestroyListener() {
|
||||
}
|
||||
});
|
||||
}
|
||||
61
types/ember/test/extend.ts
Executable file
61
types/ember/test/extend.ts
Executable file
@ -0,0 +1,61 @@
|
||||
import Ember from 'ember';
|
||||
import { assertType } from './lib/assert';
|
||||
|
||||
const Person = Ember.Object.extend({
|
||||
firstName: '',
|
||||
lastName: '',
|
||||
|
||||
getFullName() {
|
||||
return `${this.firstName} ${this.lastName}`;
|
||||
},
|
||||
getFullName2(): string {
|
||||
return `${this.get('firstName')} ${this.get('lastName')}`;
|
||||
}
|
||||
});
|
||||
|
||||
assertType<string>(Person.prototype.firstName);
|
||||
assertType<() => string>(Person.prototype.getFullName);
|
||||
|
||||
const person = Person.create({
|
||||
firstName: 'Joe',
|
||||
lastName: 'Blow',
|
||||
extra: 42
|
||||
});
|
||||
|
||||
assertType<string>(person.getFullName());
|
||||
assertType<number>(person.extra);
|
||||
|
||||
class ES6Person extends Ember.Object {
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
|
||||
get fullName() {
|
||||
return `${this.firstName} ${this.lastName}`;
|
||||
}
|
||||
get fullName2(): string {
|
||||
return `${this.get('firstName')} ${this.get('lastName')}`;
|
||||
}
|
||||
}
|
||||
|
||||
assertType<string>(ES6Person.prototype.firstName);
|
||||
assertType<string>(ES6Person.prototype.fullName);
|
||||
|
||||
const es6Person = ES6Person.create({
|
||||
firstName: 'Joe',
|
||||
lastName: 'Blow',
|
||||
extra: 42
|
||||
});
|
||||
|
||||
assertType<string>(es6Person.fullName);
|
||||
assertType<number>(es6Person.extra);
|
||||
|
||||
class PersonWithStatics extends Ember.Object {
|
||||
static isPerson = true;
|
||||
}
|
||||
const PersonWithStatics2 = PersonWithStatics.extend({});
|
||||
class PersonWithStatics3 extends PersonWithStatics {}
|
||||
class PersonWithStatics4 extends PersonWithStatics2 {}
|
||||
assertType<boolean>(PersonWithStatics.isPerson);
|
||||
assertType<boolean>(PersonWithStatics2.isPerson);
|
||||
assertType<boolean>(PersonWithStatics3.isPerson);
|
||||
assertType<boolean>(PersonWithStatics4.isPerson);
|
||||
21
types/ember/test/function-ext.ts
Executable file
21
types/ember/test/function-ext.ts
Executable file
@ -0,0 +1,21 @@
|
||||
import Ember from 'ember';
|
||||
|
||||
declare global {
|
||||
interface Function extends Ember.FunctionPrototypeExtensions {}
|
||||
}
|
||||
|
||||
Ember.Object.extend({
|
||||
foo: '',
|
||||
|
||||
arr: function() {
|
||||
return [];
|
||||
}.property(),
|
||||
|
||||
alias: function(this: any) {
|
||||
return this.get('foo');
|
||||
}.property('foo', 'bar.@each.baz'),
|
||||
|
||||
observer: function() {}.observes('foo', 'bar'),
|
||||
|
||||
on: function() {}.on('foo', 'bar'),
|
||||
});
|
||||
27
types/ember/test/helper.ts
Executable file
27
types/ember/test/helper.ts
Executable file
@ -0,0 +1,27 @@
|
||||
import Ember from 'ember';
|
||||
|
||||
const FormatCurrencyHelper = Ember.Helper.helper(function(params, hash: { currency: string }) {
|
||||
let cents = params[0];
|
||||
let currency = hash.currency;
|
||||
return `${currency}${cents * 0.01}`;
|
||||
});
|
||||
|
||||
class User extends Ember.Object {
|
||||
email: string;
|
||||
}
|
||||
|
||||
class SessionService extends Ember.Service {
|
||||
currentUser: User;
|
||||
}
|
||||
|
||||
const CurrentUserEmailHelper = Ember.Helper.extend({
|
||||
session: Ember.inject.service() as Ember.ComputedProperty<SessionService>,
|
||||
onNewUser: Ember.observer('session.currentUser', function(this: Ember.Helper) {
|
||||
this.recompute();
|
||||
}),
|
||||
compute(): string {
|
||||
return this.get('session')
|
||||
.get('currentUser')
|
||||
.get('email');
|
||||
},
|
||||
});
|
||||
20
types/ember/test/inject.ts
Executable file
20
types/ember/test/inject.ts
Executable file
@ -0,0 +1,20 @@
|
||||
import Ember from 'ember';
|
||||
|
||||
class AuthService extends Ember.Service {
|
||||
isAuthenticated: boolean;
|
||||
}
|
||||
|
||||
class ApplicationController extends Ember.Controller {
|
||||
transitionToLogin() {}
|
||||
}
|
||||
|
||||
class LoginRoute extends Ember.Route {
|
||||
auth = Ember.inject.service('authentication') as Ember.ComputedProperty<AuthService>;
|
||||
application = Ember.inject.controller() as Ember.ComputedProperty<ApplicationController>;
|
||||
|
||||
didTransition() {
|
||||
if (!this.get('auth').get('isAuthenticated')) {
|
||||
this.get('application').transitionToLogin();
|
||||
}
|
||||
}
|
||||
}
|
||||
5
types/ember/test/lib/assert.ts
Executable file
5
types/ember/test/lib/assert.ts
Executable 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;
|
||||
46
types/ember/test/mixin.ts
Executable file
46
types/ember/test/mixin.ts
Executable file
@ -0,0 +1,46 @@
|
||||
import Ember from 'ember';
|
||||
import { assertType } from "./lib/assert";
|
||||
|
||||
interface EditableMixin {
|
||||
edit(): void;
|
||||
isEditing: boolean;
|
||||
}
|
||||
|
||||
const EditableMixin: Ember.Mixin<EditableMixin, Ember.Route> = Ember.Mixin.create({
|
||||
edit() {
|
||||
this.get('controller');
|
||||
console.log('starting to edit');
|
||||
this.set('isEditing', true);
|
||||
},
|
||||
isEditing: false
|
||||
});
|
||||
|
||||
const EditableComment = Ember.Route.extend(EditableMixin, {
|
||||
postId: 0,
|
||||
|
||||
canEdit() {
|
||||
return !this.isEditing;
|
||||
},
|
||||
|
||||
tryEdit() {
|
||||
if (this.canEdit()) {
|
||||
this.edit();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const comment = EditableComment.create({
|
||||
postId: 42
|
||||
});
|
||||
|
||||
comment.edit();
|
||||
comment.canEdit();
|
||||
comment.tryEdit();
|
||||
assertType<boolean>(comment.isEditing);
|
||||
assertType<number>(comment.postId);
|
||||
|
||||
const LiteralMixins = Ember.Object.extend({ a: 1 }, { b: 2 }, { c: 3 });
|
||||
const obj = LiteralMixins.create();
|
||||
assertType<number>(obj.a);
|
||||
assertType<number>(obj.b);
|
||||
assertType<number>(obj.c);
|
||||
15
types/ember/test/object.ts
Executable file
15
types/ember/test/object.ts
Executable file
@ -0,0 +1,15 @@
|
||||
import Ember from 'ember';
|
||||
|
||||
const LifetimeHooks = Ember.Object.extend({
|
||||
resource: null as {} | null,
|
||||
|
||||
init() {
|
||||
this._super();
|
||||
this.resource = {};
|
||||
},
|
||||
|
||||
willDestroy() {
|
||||
delete this.resource;
|
||||
this._super();
|
||||
}
|
||||
});
|
||||
88
types/ember/test/observable.ts
Executable file
88
types/ember/test/observable.ts
Executable file
@ -0,0 +1,88 @@
|
||||
import Ember from 'ember';
|
||||
import { assertType } from './lib/assert';
|
||||
|
||||
class MyComponent extends Ember.Component {
|
||||
foo = 'bar';
|
||||
|
||||
init() {
|
||||
this._super.apply(this, arguments);
|
||||
this.addObserver('foo', this, 'fooDidChange');
|
||||
this.addObserver('foo', this, this.fooDidChange);
|
||||
Ember.addObserver(this, 'foo', this, 'fooDidChange');
|
||||
Ember.addObserver(this, 'foo', this, this.fooDidChange);
|
||||
this.removeObserver('foo', this, 'fooDidChange');
|
||||
this.removeObserver('foo', this, this.fooDidChange);
|
||||
Ember.removeObserver(this, 'foo', this, 'fooDidChange');
|
||||
Ember.removeObserver(this, 'foo', this, this.fooDidChange);
|
||||
}
|
||||
|
||||
fooDidChange(sender: MyComponent, key: 'foo') {
|
||||
// your code
|
||||
}
|
||||
}
|
||||
|
||||
const myComponent = MyComponent.create();
|
||||
myComponent.addObserver('foo', null, () => {});
|
||||
myComponent.set('foo', 'baz');
|
||||
|
||||
const person = Ember.Object.create({
|
||||
name: 'Fred',
|
||||
age: 29,
|
||||
capitalized: Ember.computed<string>(function() {
|
||||
return this.get('name').toUpperCase();
|
||||
})
|
||||
});
|
||||
|
||||
const pojo = { name: 'Fred', age: 29 };
|
||||
|
||||
function testGet() {
|
||||
assertType<string>(Ember.get(person, 'name'));
|
||||
assertType<number>(Ember.get(person, 'age'));
|
||||
assertType<string>(Ember.get(person, 'capitalized'));
|
||||
assertType<string>(person.get('name'));
|
||||
assertType<number>(person.get('age'));
|
||||
assertType<string>(person.get('capitalized'));
|
||||
assertType<string>(Ember.get(pojo, 'name'));
|
||||
}
|
||||
|
||||
function testGetProperties() {
|
||||
assertType<{ name: string }>(Ember.getProperties(person, 'name'));
|
||||
assertType<{ name: string, age: number }>(Ember.getProperties(person, 'name', 'age'));
|
||||
assertType<{ name: string, age: number }>(Ember.getProperties(person, [ 'name', 'age' ]));
|
||||
assertType<{ name: string, age: number, capitalized: string }>(Ember.getProperties(person, 'name', 'age', 'capitalized'));
|
||||
assertType<{ name: string }>(person.getProperties('name'));
|
||||
assertType<{ name: string, age: number }>(person.getProperties('name', 'age'));
|
||||
assertType<{ name: string, age: number }>(person.getProperties([ 'name', 'age' ]));
|
||||
assertType<{ name: string, age: number, capitalized: string }>(person.getProperties('name', 'age', 'capitalized'));
|
||||
assertType<{ name: string, age: number }>(Ember.getProperties(pojo, 'name', 'age'));
|
||||
}
|
||||
|
||||
function testGetWithDefault() {
|
||||
assertType<string>(Ember.getWithDefault(person, 'name', 'Joe'));
|
||||
assertType<number>(Ember.getWithDefault(person, 'age', 20));
|
||||
assertType<string>(Ember.getWithDefault(person, 'capitalized', 'JOE'));
|
||||
assertType<string>(person.getWithDefault('name', 'Joe'));
|
||||
assertType<number>(person.getWithDefault('age', 20));
|
||||
assertType<string>(person.getWithDefault('capitalized', 'JOE'));
|
||||
assertType<string>(Ember.getWithDefault(pojo, 'name', 'JOE'));
|
||||
}
|
||||
|
||||
function testSet() {
|
||||
assertType<string>(Ember.set(person, 'name', 'Joe'));
|
||||
assertType<number>(Ember.set(person, 'age', 35));
|
||||
assertType<string>(Ember.set(person, 'capitalized', 'JOE'));
|
||||
assertType<string>(person.set('name', 'Joe'));
|
||||
assertType<number>(person.set('age', 35));
|
||||
assertType<string>(person.set('capitalized', 'JOE'));
|
||||
assertType<string>(Ember.set(pojo, 'name', 'Joe'));
|
||||
}
|
||||
|
||||
function testSetProperties() {
|
||||
assertType<{ name: string }>(Ember.setProperties(person, { name: 'Joe' }));
|
||||
assertType<{ name: string, age: number }>(Ember.setProperties(person, { name: 'Joe', age: 35 }));
|
||||
assertType<{ name: string, capitalized: string }>(Ember.setProperties(person, { name: 'Joe', capitalized: 'JOE' }));
|
||||
assertType<{ name: string }>(person.setProperties({ name: 'Joe' }));
|
||||
assertType<{ name: string, age: number }>(person.setProperties({ name: 'Joe', age: 35 }));
|
||||
assertType<{ name: string, capitalized: string }>(person.setProperties({ name: 'Joe', capitalized: 'JOE' }));
|
||||
assertType<{ name: string, age: number }>(Ember.setProperties(pojo, { name: 'Joe', age: 35 }));
|
||||
}
|
||||
65
types/ember/test/reopen.ts
Executable file
65
types/ember/test/reopen.ts
Executable file
@ -0,0 +1,65 @@
|
||||
import Ember from 'ember';
|
||||
import { assertType } from "./lib/assert";
|
||||
|
||||
type Person = typeof Person.prototype;
|
||||
const Person = Ember.Object.extend({
|
||||
name: '',
|
||||
sayHello() {
|
||||
alert(`Hello. My name is ${this.get('name')}`);
|
||||
}
|
||||
});
|
||||
|
||||
assertType<Person>(Person.reopen());
|
||||
|
||||
assertType<string>(Person.create().name);
|
||||
assertType<void>(Person.create().sayHello());
|
||||
|
||||
const Person2 = Person.reopenClass({
|
||||
species: 'Homo sapiens',
|
||||
|
||||
createPerson(name: string): Person {
|
||||
return Person.create({ name });
|
||||
}
|
||||
});
|
||||
|
||||
assertType<string>(Person2.create().name);
|
||||
assertType<void>(Person2.create().sayHello());
|
||||
assertType<string>(Person2.species);
|
||||
|
||||
let tom = Person2.create({
|
||||
name: 'Tom Dale'
|
||||
});
|
||||
let yehuda = Person2.createPerson('Yehuda Katz');
|
||||
|
||||
tom.sayHello(); // "Hello. My name is Tom Dale"
|
||||
yehuda.sayHello(); // "Hello. My name is Yehuda Katz"
|
||||
alert(Person2.species); // "Homo sapiens"
|
||||
|
||||
const Person3 = Person2.reopen({
|
||||
goodbyeMessage: 'goodbye',
|
||||
|
||||
sayGoodbye() {
|
||||
alert(`${this.get('goodbyeMessage')}, ${this.get('name')}`);
|
||||
}
|
||||
});
|
||||
|
||||
const person3 = Person3.create();
|
||||
person3.get('name');
|
||||
person3.get('goodbyeMessage');
|
||||
person3.sayHello();
|
||||
person3.sayGoodbye();
|
||||
|
||||
interface AutoResizeMixin { resizable: true; }
|
||||
declare const AutoResizeMixin: Ember.Mixin<AutoResizeMixin>;
|
||||
|
||||
const ResizableTextArea = Ember.TextArea.reopen(AutoResizeMixin, {
|
||||
scaling: 1.0
|
||||
});
|
||||
const text = ResizableTextArea.create();
|
||||
assertType<boolean>(text.resizable);
|
||||
assertType<number>(text.scaling);
|
||||
|
||||
const Reopened = Ember.Object.reopenClass({ a: 1 }, { b: 2 }, { c: 3 });
|
||||
assertType<number>(Reopened.a);
|
||||
assertType<number>(Reopened.b);
|
||||
assertType<number>(Reopened.c);
|
||||
87
types/ember/test/route.ts
Executable file
87
types/ember/test/route.ts
Executable file
@ -0,0 +1,87 @@
|
||||
import Route from '@ember/routing/route';
|
||||
import Object from '@ember/object';
|
||||
import Array from '@ember/array';
|
||||
import Ember from 'ember'; // currently needed for Transition
|
||||
|
||||
interface Post extends Ember.Object {}
|
||||
|
||||
interface Posts extends Array<Post> {}
|
||||
|
||||
Route.extend({
|
||||
beforeModel(transition: Ember.Transition) {
|
||||
this.transitionTo('someOtherRoute');
|
||||
},
|
||||
});
|
||||
|
||||
Route.extend({
|
||||
afterModel(posts: Posts, transition: Ember.Transition) {
|
||||
if (posts.length === 1) {
|
||||
this.transitionTo('post.show', posts.firstObject);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
Route.extend({
|
||||
actions: {
|
||||
showModal(evt: { modalName: string }) {
|
||||
this.render(evt.modalName, {
|
||||
outlet: 'modal',
|
||||
into: 'application',
|
||||
});
|
||||
},
|
||||
hideModal(evt: { modalName: string }) {
|
||||
this.disconnectOutlet({
|
||||
outlet: 'modal',
|
||||
parentView: 'application',
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
Ember.Route.extend({
|
||||
model() {
|
||||
return this.modelFor('post');
|
||||
},
|
||||
});
|
||||
|
||||
Route.extend({
|
||||
queryParams: {
|
||||
memberQp: { refreshModel: true },
|
||||
},
|
||||
});
|
||||
|
||||
Route.extend({
|
||||
renderTemplate() {
|
||||
this.render('photos', {
|
||||
into: 'application',
|
||||
outlet: 'anOutletName',
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
Route.extend({
|
||||
renderTemplate(controller: Ember.Controller, model: {}) {
|
||||
this.render('posts', {
|
||||
view: 'someView', // the template to render, referenced by name
|
||||
into: 'application', // the template to render into, referenced by name
|
||||
outlet: 'anOutletName', // the outlet inside `options.into` to render into.
|
||||
controller: 'someControllerName', // the controller to use for this template, referenced by name
|
||||
model, // the model to set on `options.controller`.
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
Route.extend({
|
||||
resetController(controller: Ember.Controller, isExiting: boolean, transition: boolean) {
|
||||
if (isExiting) {
|
||||
// controller.set('page', 1);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
Route.extend({
|
||||
setupController(controller: Ember.Controller, model: {}) {
|
||||
this._super(controller, model);
|
||||
this.controllerFor('application').set('model', model);
|
||||
},
|
||||
});
|
||||
23
types/ember/test/router.ts
Executable file
23
types/ember/test/router.ts
Executable file
@ -0,0 +1,23 @@
|
||||
import Ember from 'ember';
|
||||
|
||||
const AppRouter = Ember.Router.extend({
|
||||
});
|
||||
|
||||
AppRouter.map(function() {
|
||||
this.route('index', { path: '/' });
|
||||
this.route('about');
|
||||
this.route('favorites', { path: '/favs' });
|
||||
this.route('posts', function() {
|
||||
this.route('index', { path: '/' });
|
||||
this.route('new');
|
||||
this.route('post', { path: '/post/:post_id', resetNamespace: true });
|
||||
this.route('comments', { resetNamespace: true }, function() {
|
||||
this.route('new');
|
||||
});
|
||||
});
|
||||
this.route('photo', { path: '/photo/:id' }, function() {
|
||||
this.route('comment', { path: '/comment/:id' });
|
||||
});
|
||||
this.route('not-found', { path: '/*path' });
|
||||
this.mount('my-engine');
|
||||
});
|
||||
204
types/ember/test/run.ts
Executable file
204
types/ember/test/run.ts
Executable file
@ -0,0 +1,204 @@
|
||||
import Ember from 'ember';
|
||||
import RSVP from 'rsvp';
|
||||
import { run } from '@ember/runloop';
|
||||
import { assertType } from "./lib/assert";
|
||||
|
||||
assertType<string[]>(Ember.run.queues);
|
||||
|
||||
function testRun() {
|
||||
let r = run(function() {
|
||||
// code to be executed within a RunLoop
|
||||
return 123;
|
||||
});
|
||||
assertType<number>(r);
|
||||
|
||||
function destroyApp(application: Ember.Application) {
|
||||
Ember.run(application, 'destroy');
|
||||
run(application, function() {
|
||||
this.destroy();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function testBind() {
|
||||
Ember.Component.extend({
|
||||
init() {
|
||||
const bound = Ember.run.bind(this, this.setupEditor);
|
||||
bound();
|
||||
},
|
||||
|
||||
editor: null as string | null,
|
||||
|
||||
setupEditor(editor: string) {
|
||||
this.set('editor', editor);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function testCancel() {
|
||||
const myContext = {};
|
||||
|
||||
let runNext = run.next(myContext, function() {
|
||||
// will not be executed
|
||||
});
|
||||
|
||||
run.cancel(runNext);
|
||||
|
||||
let runLater = run.later(myContext, function() {
|
||||
// will not be executed
|
||||
}, 500);
|
||||
|
||||
run.cancel(runLater);
|
||||
|
||||
let runScheduleOnce = run.scheduleOnce('afterRender', myContext, function() {
|
||||
// will not be executed
|
||||
});
|
||||
|
||||
run.cancel(runScheduleOnce);
|
||||
|
||||
let runOnce = run.once(myContext, function() {
|
||||
// will not be executed
|
||||
});
|
||||
|
||||
run.cancel(runOnce);
|
||||
|
||||
let throttle = run.throttle(myContext, function() {
|
||||
// will not be executed
|
||||
}, 1, false);
|
||||
|
||||
run.cancel(throttle);
|
||||
|
||||
let debounce = run.debounce(myContext, function() {
|
||||
// will not be executed
|
||||
}, 1);
|
||||
|
||||
run.cancel(debounce);
|
||||
|
||||
let debounceImmediate = run.debounce(myContext, function() {
|
||||
// will be executed since we passed in true (immediate)
|
||||
}, 100, true);
|
||||
|
||||
// the 100ms delay until this method can be called again will be canceled
|
||||
run.cancel(debounceImmediate);
|
||||
}
|
||||
|
||||
function testDebounce() {
|
||||
function runIt() {
|
||||
}
|
||||
|
||||
let myContext = { name: 'debounce' };
|
||||
|
||||
run.debounce(runIt, 150);
|
||||
run.debounce(myContext, runIt, 150);
|
||||
run.debounce(myContext, runIt, 150, true);
|
||||
|
||||
Ember.Component.extend({
|
||||
searchValue: 'test',
|
||||
fetchResults(value: string) {},
|
||||
|
||||
actions: {
|
||||
handleTyping() {
|
||||
// the fetchResults function is passed into the component from its parent
|
||||
Ember.run.debounce(this, this.get('fetchResults'), this.get('searchValue'), 250);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function testBegin() {
|
||||
run.begin();
|
||||
// code to be executed within a RunLoop
|
||||
run.end();
|
||||
}
|
||||
|
||||
function testJoin() {
|
||||
run.join(function() {
|
||||
// creates a new run-loop
|
||||
});
|
||||
|
||||
run(function() {
|
||||
// creates a new run-loop
|
||||
run.join(function() {
|
||||
// joins with the existing run-loop, and queues for invocation on
|
||||
// the existing run-loops action queue.
|
||||
});
|
||||
});
|
||||
|
||||
new RSVP.Promise(function(resolve) {
|
||||
Ember.run.later(function() {
|
||||
resolve({ msg: 'Hold Your Horses' });
|
||||
}, 3000);
|
||||
});
|
||||
}
|
||||
|
||||
function testLater() {
|
||||
const myContext = {};
|
||||
run.later(myContext, function() {
|
||||
// code here will execute within a RunLoop in about 500ms with this == myContext
|
||||
}, 500);
|
||||
}
|
||||
|
||||
function testNext() {
|
||||
const myContext = {};
|
||||
run.next(myContext, function() {
|
||||
// code to be executed in the next run loop,
|
||||
// which will be scheduled after the current one
|
||||
});
|
||||
}
|
||||
|
||||
function testOnce() {
|
||||
Ember.Component.extend({
|
||||
init() {
|
||||
Ember.run.once(this, 'processFullName');
|
||||
},
|
||||
|
||||
processFullName() {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function testSchedule() {
|
||||
Ember.Component.extend({
|
||||
init() {
|
||||
run.schedule('sync', this, function() {
|
||||
// this will be executed in the first RunLoop queue, when bindings are synced
|
||||
console.log('scheduled on sync queue');
|
||||
});
|
||||
|
||||
run.schedule('actions', this, function() {
|
||||
// this will be executed in the 'actions' queue, after bindings have synced.
|
||||
console.log('scheduled on actions queue');
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Ember.run.schedule('actions', () => {
|
||||
// Do more things
|
||||
});
|
||||
}
|
||||
|
||||
function testScheduleOnce() {
|
||||
function sayHi() {
|
||||
console.log('hi');
|
||||
}
|
||||
|
||||
const myContext = {};
|
||||
run(function() {
|
||||
run.scheduleOnce('afterRender', myContext, sayHi);
|
||||
run.scheduleOnce('afterRender', myContext, sayHi);
|
||||
// sayHi will only be executed once, in the afterRender queue of the RunLoop
|
||||
});
|
||||
run.scheduleOnce('actions', myContext, function() {
|
||||
console.log('Closure');
|
||||
});
|
||||
}
|
||||
|
||||
function testThrottle() {
|
||||
function runIt() {
|
||||
}
|
||||
|
||||
let myContext = { name: 'throttle' };
|
||||
|
||||
run.throttle(runIt, 150);
|
||||
run.throttle(myContext, runIt, 150);
|
||||
}
|
||||
32
types/ember/test/test.ts
Executable file
32
types/ember/test/test.ts
Executable file
@ -0,0 +1,32 @@
|
||||
import Ember from 'ember';
|
||||
|
||||
let pending = 0;
|
||||
Ember.Test.registerWaiter(() => pending !== 0);
|
||||
|
||||
declare const MyDb: {
|
||||
hasPendingTransactions(): boolean;
|
||||
};
|
||||
Ember.Test.registerWaiter(MyDb, MyDb.hasPendingTransactions);
|
||||
|
||||
Ember.Test.promise(function(resolve) {
|
||||
window.setTimeout(resolve, 500);
|
||||
});
|
||||
|
||||
Ember.Test.registerHelper('boot', function(app) {
|
||||
Ember.run(app, app.advanceReadiness);
|
||||
});
|
||||
|
||||
Ember.Test.registerAsyncHelper('boot', function(app) {
|
||||
Ember.run(app, app.advanceReadiness);
|
||||
});
|
||||
|
||||
Ember.Test.registerAsyncHelper('waitForPromise', (app, promise) => {
|
||||
return new Ember.Test.Promise((resolve) => {
|
||||
Ember.Test.adapter.asyncStart();
|
||||
|
||||
promise.then(() => {
|
||||
Ember.run.schedule('afterRender', null, resolve);
|
||||
Ember.Test.adapter.asyncEnd();
|
||||
});
|
||||
});
|
||||
});
|
||||
28
types/ember/test/transition.ts
Executable file
28
types/ember/test/transition.ts
Executable file
@ -0,0 +1,28 @@
|
||||
import Ember from 'ember';
|
||||
|
||||
Ember.Route.extend({
|
||||
beforeModel(transition: Ember.Transition) {
|
||||
if (new Date() > new Date('January 1, 1980')) {
|
||||
alert('Sorry, you need a time machine to enter this route.');
|
||||
transition.abort();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Ember.Controller.extend({
|
||||
previousTransition: <Ember.Transition | null> null,
|
||||
|
||||
actions: {
|
||||
login() {
|
||||
// Log the user in, then reattempt previous transition if it exists.
|
||||
let previousTransition = this.get('previousTransition');
|
||||
if (previousTransition) {
|
||||
this.set('previousTransition', null);
|
||||
previousTransition.retry();
|
||||
} else {
|
||||
// Default back to homepage
|
||||
this.transitionToRoute('index');
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
71
types/ember/test/utils.ts
Executable file
71
types/ember/test/utils.ts
Executable file
@ -0,0 +1,71 @@
|
||||
import Ember from 'ember';
|
||||
import * as utils from '@ember/utils';
|
||||
import { assertType } from "./lib/assert";
|
||||
|
||||
function testIsNoneType() {
|
||||
const maybeUndefined: string | undefined = 'not actually undefined';
|
||||
if (utils.isNone(maybeUndefined)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const anotherString = maybeUndefined + 'another string';
|
||||
}
|
||||
|
||||
function testMerge() {
|
||||
assertType<{ first: string, last: string }>(
|
||||
Ember.merge({ first: 'Tom' }, { last: 'Dale' })
|
||||
);
|
||||
}
|
||||
|
||||
function testAssign() {
|
||||
assertType<{ first: string, middle: string, last: string }>(
|
||||
Ember.assign({ first: 'Tom' }, { middle: 'M' }, { last: 'Dale' })
|
||||
);
|
||||
}
|
||||
|
||||
function testOnError() {
|
||||
Ember.onerror = function(error) {
|
||||
Ember.$.post('/report-error', {
|
||||
stack: error.stack,
|
||||
otherInformation: 'whatever app state you want to provide'
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
function testMakeArray() {
|
||||
assertType<any[]>(Ember.makeArray());
|
||||
assertType<any[]>(Ember.makeArray(null));
|
||||
assertType<any[]>(Ember.makeArray(undefined));
|
||||
assertType<string[]>(Ember.makeArray('lindsay'));
|
||||
assertType<number[]>(Ember.makeArray([1, 2, 42]));
|
||||
}
|
||||
|
||||
function testDeprecateFunc() {
|
||||
function newMethod(first: string, second: number): string {
|
||||
return '';
|
||||
}
|
||||
|
||||
let oldMethod = Ember.deprecateFunc('Please use the new method', { id: 'deprecated.id', until: '6.0' }, newMethod);
|
||||
assertType<string>(newMethod('first', 123));
|
||||
assertType<string>(oldMethod('first', 123));
|
||||
}
|
||||
|
||||
function testDefineProperty() {
|
||||
const contact = {};
|
||||
|
||||
// ES5 compatible mode
|
||||
Ember.defineProperty(contact, 'firstName', {
|
||||
writable: true,
|
||||
configurable: false,
|
||||
enumerable: true,
|
||||
value: 'Charles'
|
||||
});
|
||||
|
||||
// define a simple property
|
||||
Ember.defineProperty(contact, 'lastName', undefined, 'Jolley');
|
||||
|
||||
// define a computed property
|
||||
Ember.defineProperty(contact, 'fullName', Ember.computed('firstName', 'lastName', function() {
|
||||
return `${this.firstName} ${this.lastName}`;
|
||||
}));
|
||||
}
|
||||
39
types/ember/tsconfig.json
Normal file → Executable file
39
types/ember/tsconfig.json
Normal file → Executable file
@ -1,24 +1,49 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"target": "es5",
|
||||
"lib": [
|
||||
"es6",
|
||||
"dom"
|
||||
],
|
||||
"noImplicitAny": true,
|
||||
"noImplicitThis": false,
|
||||
"noImplicitThis": true,
|
||||
"strictNullChecks": true,
|
||||
"strictFunctionTypes": true,
|
||||
"strictFunctionTypes": false,
|
||||
"baseUrl": "../",
|
||||
"typeRoots": [
|
||||
"../"
|
||||
],
|
||||
"typeRoots": ["../"],
|
||||
"types": [],
|
||||
"noEmit": true,
|
||||
"forceConsistentCasingInFileNames": true
|
||||
},
|
||||
"files": [
|
||||
"index.d.ts",
|
||||
"ember-tests.ts"
|
||||
"test/lib/assert.ts",
|
||||
"test/application.ts",
|
||||
"test/ember-tests.ts",
|
||||
"test/event.ts",
|
||||
"test/extend.ts",
|
||||
"test/create.ts",
|
||||
"test/object.ts",
|
||||
"test/observable.ts",
|
||||
"test/mixin.ts",
|
||||
"test/reopen.ts",
|
||||
"test/detect.ts",
|
||||
"test/detect-instance.ts",
|
||||
"test/array.ts",
|
||||
"test/array-ext.ts",
|
||||
"test/array-proxy.ts",
|
||||
"test/helper.ts",
|
||||
"test/computed.ts",
|
||||
"test/component.ts",
|
||||
"test/function-ext.ts",
|
||||
"test/inject.ts",
|
||||
"test/utils.ts",
|
||||
"test/transition.ts",
|
||||
"test/router.ts",
|
||||
"test/run.ts",
|
||||
"test/test.ts",
|
||||
"test/controller.ts",
|
||||
"test/route.ts"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
21
types/ember/tslint.json
Normal file → Executable file
21
types/ember/tslint.json
Normal file → Executable file
@ -4,11 +4,24 @@
|
||||
// Heavy use of Function type in this older package.
|
||||
"ban-types": false,
|
||||
"jsdoc-format": false,
|
||||
"no-any-union": false,
|
||||
"no-misused-new": false,
|
||||
// not sure what this means
|
||||
|
||||
// these are disabled because of rfc176 module exports
|
||||
"strict-export-declare-modifiers": false,
|
||||
"no-single-declare-module": false,
|
||||
"no-unnecessary-generics": false,
|
||||
"no-unnecessary-qualifier": false
|
||||
"no-declare-current-package": false,
|
||||
"no-self-import": false,
|
||||
|
||||
// We use interfaces in a number of places to express things (including
|
||||
// mixins in particular, but also including extending a global
|
||||
// interface) which TS currently can't express correctly.
|
||||
"no-empty-interface": false,
|
||||
|
||||
"no-duplicate-imports": false,
|
||||
"no-unnecessary-qualifier": false,
|
||||
"prefer-const": false,
|
||||
"no-void-expression": false,
|
||||
"only-arrow-functions": false,
|
||||
"no-submodule-imports": false
|
||||
}
|
||||
}
|
||||
|
||||
961
types/rsvp/index.d.ts
vendored
Normal file → Executable file
961
types/rsvp/index.d.ts
vendored
Normal file → Executable file
@ -1,382 +1,629 @@
|
||||
// Type definitions for RSVP 3.3.3
|
||||
// Type definitions for RSVP 4.0
|
||||
// Project: https://github.com/tildeio/rsvp.js
|
||||
// Definitions by: Taylor Brown <https://github.com/Taytay>
|
||||
// Mikael Kohlmyr <https://github.com/mkohlmyr>
|
||||
// Theron Cross <https://github.com/theroncross>
|
||||
// Chris Krycho <https://github.com/chriskrycho>
|
||||
// Definitions by: Chris Krycho <https://github.com/chriskrycho>
|
||||
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
|
||||
// TypeScript Version: 2.4
|
||||
|
||||
// Some of this file was taken from the type definitions for es6-promise https://github.com/borisyankov/DefinitelyTyped/blob/master/es6-promise/es6-promise.d.ts
|
||||
// Credit for that file goes to: François de Campredon <https://github.com/fdecampredon>
|
||||
// These types are derived in large part from the Microsoft-supplied types for
|
||||
// ES2015 Promises. They have been tweaked to support RSVP's extensions to the
|
||||
// Promises A+ spec and the additional helper functions it supplies.
|
||||
|
||||
// Some of this file was taken from the type definitions for Q : https://github.com/borisyankov/DefinitelyTyped/blob/master/q/Q.d.ts
|
||||
// Credit for that file goes to: Barrie Nemetchek <https://github.com/bnemetchek>, Andrew Gaspar <https://github.com/AndrewGaspar>, John Reilly <https://github.com/johnnyreilly>
|
||||
declare module 'rsvp' {
|
||||
namespace RSVP {
|
||||
// All the Promise methods essentially flatten existing promises, so that
|
||||
// you don't end up with `Promise<Promise<Promise<string>>>` if you happen
|
||||
// to return another `Promise` from a `.then()` invocation, etc. So all of
|
||||
// them can take a type or a promise-like/then-able type.
|
||||
type Arg<T> = T | PromiseLike<T>;
|
||||
|
||||
declare namespace RSVP {
|
||||
type Resolution<T, U, C> = (value: T) => U | Thenable<U, C>;
|
||||
type Rejection<T, C, D> = (error: C) => D | Thenable<T, D>;
|
||||
// RSVP supplies status for promises in certain places.
|
||||
enum State {
|
||||
fulfilled = 'fulfilled',
|
||||
rejected = 'rejected',
|
||||
pending = 'pending',
|
||||
}
|
||||
|
||||
interface Thenable<T, C> {
|
||||
then(label?: string): Thenable<T, C>;
|
||||
then<U>(onFulfillment: Resolution<T, U, C>, label?: string): Thenable<U, C>;
|
||||
then<U, D>(
|
||||
onFulfillment: Resolution<T, U, C>,
|
||||
onRejected: Rejection<T, C, D>,
|
||||
label?: string
|
||||
): Thenable<U, D>;
|
||||
}
|
||||
type Resolved<T> = {
|
||||
state: State.fulfilled;
|
||||
value: T;
|
||||
};
|
||||
|
||||
interface Catchable<C> {
|
||||
catch(label?: string): Catchable<C>;
|
||||
catch<D>(onRejection: (error: C) => D, label?: string): Catchable<D>;
|
||||
}
|
||||
type Rejected<T = any> = {
|
||||
state: State.rejected;
|
||||
reason: T;
|
||||
};
|
||||
|
||||
interface Deferred<T, C> {
|
||||
promise: Promise<T, C>;
|
||||
resolve(value: T): void;
|
||||
reject(reason: C): void;
|
||||
}
|
||||
type Pending = {
|
||||
state: State.pending;
|
||||
};
|
||||
|
||||
type PromiseStates = 'fulfilled' | 'rejected' | 'pending';
|
||||
interface IPromiseState<T, C> {
|
||||
state: PromiseStates;
|
||||
value: T;
|
||||
reason: C;
|
||||
}
|
||||
type PromiseState<T> = Resolved<T> | Rejected | Pending;
|
||||
|
||||
class Resolved<T, C> implements IPromiseState<T, C> {
|
||||
state: 'fulfilled';
|
||||
value: T;
|
||||
reason: never;
|
||||
}
|
||||
type Deferred<T> = {
|
||||
promise: Promise<T>;
|
||||
resolve: (value?: RSVP.Arg<T>) => void;
|
||||
reject: (reason?: any) => void;
|
||||
};
|
||||
|
||||
class Rejected<T, C> implements IPromiseState<T, C> {
|
||||
state: 'rejected';
|
||||
value: never;
|
||||
reason: C;
|
||||
}
|
||||
interface InstrumentEvent {
|
||||
guid: string; // guid of promise. Must be globally unique, not just within the implementation
|
||||
childGuid: string; // child of child promise (for chained via `then`)
|
||||
eventName: string; // one of ['created', 'chained', 'fulfilled', 'rejected']
|
||||
detail: any; // fulfillment value or rejection reason, if applicable
|
||||
label: string; // label passed to promise's constructor
|
||||
timeStamp: number; // milliseconds elapsed since 1 January 1970 00:00:00 UTC up until now
|
||||
}
|
||||
|
||||
class Pending<T, C> implements IPromiseState<T, C> {
|
||||
state: 'pending';
|
||||
value: never;
|
||||
reason: never;
|
||||
}
|
||||
interface ObjectWithEventMixins {
|
||||
on(
|
||||
eventName: 'created' | 'chained' | 'fulfilled' | 'rejected',
|
||||
listener: (event: InstrumentEvent) => void
|
||||
): void;
|
||||
on(eventName: 'error', errorHandler: (reason: any) => void): void;
|
||||
on(eventName: string, callback: (value: any) => void): void;
|
||||
off(eventName: string, callback?: (value: any) => void): void;
|
||||
trigger(eventName: string, options?: any, label?: string): void;
|
||||
}
|
||||
|
||||
type PromiseState<T, C> = Resolved<T, C> | Rejected<C, C> | Pending<T, C>;
|
||||
class EventTarget {
|
||||
/** `RSVP.EventTarget.mixin` extends an object with EventTarget methods. */
|
||||
static mixin(object: object): ObjectWithEventMixins;
|
||||
|
||||
type PromiseHash<T, C> = { [P in keyof T]: Thenable<T[P], C> | T[P] };
|
||||
/** Registers a callback to be executed when `eventName` is triggered */
|
||||
static on(
|
||||
eventName: 'created' | 'chained' | 'fulfilled' | 'rejected',
|
||||
listener: (event: InstrumentEvent) => void
|
||||
): void;
|
||||
static on(eventName: 'error', errorHandler: (reason: any) => void): void;
|
||||
static on(eventName: string, callback: (value: any) => void): void;
|
||||
|
||||
type SettledHash<T, C> = { [P in keyof T]: PromiseState<T[P], C> };
|
||||
|
||||
interface InstrumentEvent {
|
||||
guid: string; // guid of promise. Must be globally unique, not just within the implementation
|
||||
childGuid: string; // child of child promise (for chained via `then`)
|
||||
eventName: string; // one of ['created', 'chained', 'fulfilled', 'rejected']
|
||||
detail: any; // fulfillment value or rejection reason, if applicable
|
||||
label: string; // label passed to promise's constructor
|
||||
timeStamp: number; // milliseconds elapsed since 1 January 1970 00:00:00 UTC up until now
|
||||
}
|
||||
|
||||
interface ObjectWithEventMixins {
|
||||
on(
|
||||
eventName: 'created' | 'chained' | 'fulfilled' | 'rejected',
|
||||
listener: (event: InstrumentEvent) => void
|
||||
): void;
|
||||
on(eventName: 'error', errorHandler: (reason: any) => void): void;
|
||||
on(eventName: string, callback: (value: any) => void): void;
|
||||
off(eventName: string, callback?: (value: any) => void): void;
|
||||
trigger(eventName: string, options?: any, label?: string): void;
|
||||
}
|
||||
|
||||
class Promise<T, C> implements Thenable<T, C>, Catchable<C> {
|
||||
/**
|
||||
* If you call resolve in the body of the callback passed to the constructor,
|
||||
* your promise is fulfilled with result object passed to resolve.
|
||||
* If you call reject your promise is rejected with the object passed to reject.
|
||||
* For consistency and debugging (eg stack traces), obj should be an instanceof Error.
|
||||
* Any errors thrown in the constructor callback will be implicitly passed to reject().
|
||||
*/
|
||||
constructor(
|
||||
callback: (
|
||||
resolve: (result?: T | Thenable<T, never>) => void,
|
||||
reject: (error: C | Thenable<never, C>) => void
|
||||
) => void,
|
||||
label?: string
|
||||
);
|
||||
|
||||
/**
|
||||
* onFulfillment is called when/if "promise" resolves. onRejected is called when/if "promise" rejects.
|
||||
* Both are optional, if either/both are omitted the next onFulfillment/onRejected in the chain is called.
|
||||
* Both callbacks have a single parameter , the fulfillment value or rejection reason.
|
||||
* "then" returns a new promise equivalent to the value you return from onFulfillment/onRejected after being passed through Promise.resolve.
|
||||
* If an error is thrown in the callback, the returned promise rejects with that error.
|
||||
*
|
||||
* @param onFulfillment called when/if "promise" resolves
|
||||
* @param onRejected called when/if "promise" rejects
|
||||
* @param label useful for tooling
|
||||
*/
|
||||
then<U, D>(
|
||||
onFulfillment: Resolution<T, U, C>,
|
||||
onRejected: Rejection<T, C, D>,
|
||||
label?: string
|
||||
): Promise<U, D>;
|
||||
then<U>(onFulfillment: Resolution<T, U, C>, label?: string): Promise<U, C>;
|
||||
then(label?: string): Promise<T, C>;
|
||||
|
||||
/**
|
||||
* Sugar for promise.then(undefined, onRejected)
|
||||
*/
|
||||
catch(label?: string): Promise<T, C>;
|
||||
catch<D>(onRejection: Rejection<T, C, D>, label?: string): Promise<T, D>;
|
||||
|
||||
finally(finallyCallback: Function): Promise<T, C>;
|
||||
|
||||
/**
|
||||
* `RSVP.Promise.all` accepts an array of promises, and returns a new promise which
|
||||
* is fulfilled with an array of fulfillment values for the passed promises, or
|
||||
* rejected with the reason of the first passed promise to be rejected. It casts all
|
||||
* elements of the passed iterable to promises as it runs this algorithm.
|
||||
/**
|
||||
* You can use `off` to stop firing a particular callback for an event.
|
||||
*
|
||||
* If you don't pass a `callback` argument to `off`, ALL callbacks for the
|
||||
* event will not be executed when the event fires.
|
||||
*/
|
||||
static all<T, C>(promises: Thenable<T, C>[], label?: string): Promise<T[], C>;
|
||||
static off(eventName: string, callback?: (value: any) => void): void;
|
||||
|
||||
/**
|
||||
* `RSVP.Promise.race` returns a new promise which is settled in the same way as the
|
||||
* first passed promise to settle.
|
||||
*
|
||||
* `RSVP.Promise.race` is deterministic in that only the state of the first
|
||||
* settled promise matters. For example, even if other promises given to the
|
||||
* `promises` array argument are resolved, but the first settled promise has
|
||||
* become rejected before the other promises became fulfilled, the returned
|
||||
* promise will become rejected.
|
||||
*/
|
||||
static race<T, C>(promises: Promise<T, C>[]): Promise<T, C>;
|
||||
/**
|
||||
* Use `trigger` to fire custom events.
|
||||
*
|
||||
* You can also pass a value as a second argument to `trigger` that will be
|
||||
* passed as an argument to all event listeners for the event
|
||||
*/
|
||||
static trigger(eventName: string, options?: any, label?: string): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a promise that will become resolved with the passed `value`
|
||||
*/
|
||||
static resolve<T>(value: T, label?: string): Promise<T, never>;
|
||||
class Promise<T> implements PromiseLike<T> {
|
||||
constructor(
|
||||
executor: (
|
||||
resolve: (value?: RSVP.Arg<T>) => void,
|
||||
reject: (reason?: any) => void
|
||||
) => void
|
||||
);
|
||||
|
||||
/**
|
||||
* Deprecated in favor of resolve
|
||||
*/
|
||||
static cast<T>(value: T, label?: string): Promise<T, never>;
|
||||
new<T>(
|
||||
executor: (
|
||||
resolve: (value?: RSVP.Arg<T>) => void,
|
||||
reject: (reason?: any) => void
|
||||
) => void
|
||||
): RSVP.Promise<T>;
|
||||
|
||||
/**
|
||||
* Returns a promise rejected with the passed `reason`.
|
||||
*/
|
||||
static reject<C>(reason: C): Promise<never, C>;
|
||||
then<TResult1 = T, TResult2 = never>(
|
||||
onFulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null,
|
||||
onRejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null,
|
||||
label?: string
|
||||
): RSVP.Promise<TResult1 | TResult2>;
|
||||
|
||||
catch<TResult = never>(
|
||||
onRejected?: ((reason: any) => TResult | PromiseLike<TResult>) | undefined | null,
|
||||
label?: string
|
||||
): RSVP.Promise<T | TResult>;
|
||||
|
||||
finally<U>(onFinally?: U | PromiseLike<U>): RSVP.Promise<T>;
|
||||
|
||||
static all<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(
|
||||
values: [
|
||||
Arg<T1>,
|
||||
Arg<T2>,
|
||||
Arg<T3>,
|
||||
Arg<T4>,
|
||||
Arg<T5>,
|
||||
Arg<T6>,
|
||||
Arg<T7>,
|
||||
Arg<T8>,
|
||||
Arg<T9>,
|
||||
Arg<T10>
|
||||
],
|
||||
label?: string
|
||||
): RSVP.Promise<[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]>;
|
||||
static all<T1, T2, T3, T4, T5, T6, T7, T8, T9>(
|
||||
values: [
|
||||
Arg<T1>,
|
||||
Arg<T2>,
|
||||
Arg<T3>,
|
||||
Arg<T4>,
|
||||
Arg<T5>,
|
||||
Arg<T6>,
|
||||
Arg<T7>,
|
||||
Arg<T8>,
|
||||
Arg<T9>
|
||||
],
|
||||
label?: string
|
||||
): RSVP.Promise<[T1, T2, T3, T4, T5, T6, T7, T8, T9]>;
|
||||
static all<T1, T2, T3, T4, T5, T6, T7, T8>(
|
||||
values: [Arg<T1>, Arg<T2>, Arg<T3>, Arg<T4>, Arg<T5>, Arg<T6>, Arg<T7>, Arg<T8>],
|
||||
label?: string
|
||||
): RSVP.Promise<[T1, T2, T3, T4, T5, T6, T7, T8]>;
|
||||
static all<T1, T2, T3, T4, T5, T6, T7>(
|
||||
values: [Arg<T1>, Arg<T2>, Arg<T3>, Arg<T4>, Arg<T5>, Arg<T6>, Arg<T7>],
|
||||
label?: string
|
||||
): RSVP.Promise<[T1, T2, T3, T4, T5, T6, T7]>;
|
||||
static all<T1, T2, T3, T4, T5, T6>(
|
||||
values: [Arg<T1>, Arg<T2>, Arg<T3>, Arg<T4>, Arg<T5>, Arg<T6>],
|
||||
label?: string
|
||||
): RSVP.Promise<[T1, T2, T3, T4, T5, T6]>;
|
||||
static all<T1, T2, T3, T4, T5>(
|
||||
values: [Arg<T1>, Arg<T2>, Arg<T3>, Arg<T4>, Arg<T5>],
|
||||
label?: string
|
||||
): RSVP.Promise<[T1, T2, T3, T4, T5]>;
|
||||
static all<T1, T2, T3, T4>(
|
||||
values: [Arg<T1>, Arg<T2>, Arg<T3>, Arg<T4>],
|
||||
label?: string
|
||||
): RSVP.Promise<[T1, T2, T3, T4]>;
|
||||
static all<T1, T2, T3>(
|
||||
values: [Arg<T1>, Arg<T2>, Arg<T3>],
|
||||
label?: string
|
||||
): RSVP.Promise<[T1, T2, T3]>;
|
||||
static all<T1, T2>(values: [Arg<T1>, Arg<T2>], label?: string): Promise<[T1, T2]>;
|
||||
static all<T>(values: (Arg<T>)[], label?: string): RSVP.Promise<T[]>;
|
||||
|
||||
static race<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(
|
||||
values: [
|
||||
Arg<T1>,
|
||||
Arg<T2>,
|
||||
Arg<T3>,
|
||||
Arg<T4>,
|
||||
Arg<T5>,
|
||||
Arg<T6>,
|
||||
Arg<T7>,
|
||||
Arg<T8>,
|
||||
Arg<T9>,
|
||||
T10 | PromiseLike<T10>
|
||||
],
|
||||
label?: string
|
||||
): RSVP.Promise<T1 | T2 | T3 | T4 | T5 | T6 | T7 | T8 | T9 | T10>;
|
||||
static race<T1, T2, T3, T4, T5, T6, T7, T8, T9>(
|
||||
values: [
|
||||
Arg<T1>,
|
||||
Arg<T2>,
|
||||
Arg<T3>,
|
||||
Arg<T4>,
|
||||
Arg<T5>,
|
||||
Arg<T6>,
|
||||
Arg<T7>,
|
||||
Arg<T8>,
|
||||
Arg<T9>
|
||||
],
|
||||
label?: string
|
||||
): RSVP.Promise<T1 | T2 | T3 | T4 | T5 | T6 | T7 | T8 | T9>;
|
||||
static race<T1, T2, T3, T4, T5, T6, T7, T8>(
|
||||
values: [Arg<T1>, Arg<T2>, Arg<T3>, Arg<T4>, Arg<T5>, Arg<T6>, Arg<T7>, Arg<T8>],
|
||||
label?: string
|
||||
): RSVP.Promise<T1 | T2 | T3 | T4 | T5 | T6 | T7 | T8>;
|
||||
static race<T1, T2, T3, T4, T5, T6, T7>(
|
||||
values: [Arg<T1>, Arg<T2>, Arg<T3>, Arg<T4>, Arg<T5>, Arg<T6>, Arg<T7>],
|
||||
label?: string
|
||||
): RSVP.Promise<T1 | T2 | T3 | T4 | T5 | T6 | T7>;
|
||||
static race<T1, T2, T3, T4, T5, T6>(
|
||||
values: [Arg<T1>, Arg<T2>, Arg<T3>, Arg<T4>, Arg<T5>, Arg<T6>],
|
||||
label?: string
|
||||
): RSVP.Promise<T1 | T2 | T3 | T4 | T5 | T6>;
|
||||
static race<T1, T2, T3, T4, T5>(
|
||||
values: [Arg<T1>, Arg<T2>, Arg<T3>, Arg<T4>, Arg<T5>],
|
||||
label?: string
|
||||
): RSVP.Promise<T1 | T2 | T3 | T4 | T5>;
|
||||
static race<T1, T2, T3, T4>(
|
||||
values: [Arg<T1>, Arg<T2>, Arg<T3>, Arg<T4>],
|
||||
label?: string
|
||||
): RSVP.Promise<T1 | T2 | T3 | T4>;
|
||||
static race<T1, T2, T3>(
|
||||
values: [Arg<T1>, Arg<T2>, Arg<T3>],
|
||||
label?: string
|
||||
): RSVP.Promise<T1 | T2 | T3>;
|
||||
static race<T1, T2>(values: [Arg<T1>, Arg<T2>], label?: string): RSVP.Promise<T1 | T2>;
|
||||
static race<T>(values: (Arg<T>)[], label?: string): RSVP.Promise<T>;
|
||||
|
||||
static reject(reason?: any, label?: string): RSVP.Promise<never>;
|
||||
|
||||
static resolve<T>(value?: Arg<T>, label?: string): RSVP.Promise<T>;
|
||||
static resolve(): RSVP.Promise<void>;
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
static cast: typeof RSVP.Promise.resolve;
|
||||
}
|
||||
|
||||
const all: typeof Promise.all;
|
||||
const race: typeof Promise.race;
|
||||
const reject: typeof Promise.reject;
|
||||
const resolve: typeof Promise.resolve;
|
||||
function rethrow(reason: any): void;
|
||||
|
||||
const cast: typeof Promise.cast;
|
||||
|
||||
const on: typeof EventTarget.on;
|
||||
const off: typeof EventTarget.off;
|
||||
|
||||
// ----- denodeify ----- //
|
||||
// Here be absurd things because we don't have variadic types. All of
|
||||
// this will go away if we can ever write this:
|
||||
//
|
||||
// denodeify<...T, ...A>(
|
||||
// nodeFunc: (...args: ...A, callback: (err: any, ...cbArgs: ...T) => any) => void,
|
||||
// options?: false
|
||||
// ): (...args: ...A) => RSVP.Promise<...T>
|
||||
//
|
||||
// That day, however, may never come. So, in the meantime, we do this.
|
||||
|
||||
function denodeify<T1, T2, T3, A>(
|
||||
nodeFunc: (
|
||||
arg1: A,
|
||||
callback: (err: any, data1: T1, data2: T2, data3: T3) => void
|
||||
) => void,
|
||||
options?: false
|
||||
): (arg1: A) => RSVP.Promise<T1>;
|
||||
|
||||
function denodeify<T1, T2, A>(
|
||||
nodeFunc: (arg1: A, callback: (err: any, data1: T1, data2: T2) => void) => void,
|
||||
options?: false
|
||||
): (arg1: A) => RSVP.Promise<T1>;
|
||||
|
||||
function denodeify<T, A>(
|
||||
nodeFunc: (arg1: A, callback: (err: any, data: T) => void) => void,
|
||||
options?: false
|
||||
): (arg1: A) => RSVP.Promise<T>;
|
||||
|
||||
function denodeify<T1, T2, T3, A>(
|
||||
nodeFunc: (
|
||||
arg1: A,
|
||||
callback: (err: any, data1: T1, data2: T2, data3: T3) => void
|
||||
) => void,
|
||||
options: true
|
||||
): (arg1: A) => RSVP.Promise<[T1, T2, T3]>;
|
||||
|
||||
function denodeify<T1, T2, A>(
|
||||
nodeFunc: (arg1: A, callback: (err: any, data1: T1, data2: T2) => void) => void,
|
||||
options: true
|
||||
): (arg1: A) => RSVP.Promise<[T1, T2]>;
|
||||
|
||||
function denodeify<T, A>(
|
||||
nodeFunc: (arg1: A, callback: (err: any, data: T) => void) => void,
|
||||
options: true
|
||||
): (arg1: A) => RSVP.Promise<[T]>;
|
||||
|
||||
function denodeify<T1, T2, T3, A, K1 extends string, K2 extends string, K3 extends string>(
|
||||
nodeFunc: (
|
||||
arg1: A,
|
||||
callback: (err: any, data1: T1, data2: T2, data3: T3) => void
|
||||
) => void,
|
||||
options: [K1, K2, K3]
|
||||
): (arg1: A) => RSVP.Promise<{ [K in K1]: T1 } & { [K in K2]: T2 } & { [K in K3]: T3 }>;
|
||||
|
||||
function denodeify<T1, T2, A, K1 extends string, K2 extends string>(
|
||||
nodeFunc: (arg1: A, callback: (err: any, data1: T1, data2: T2) => void) => void,
|
||||
options: [K1, K2]
|
||||
): (arg1: A) => RSVP.Promise<{ [K in K1]: T1 } & { [K in K2]: T2 }>;
|
||||
|
||||
function denodeify<T, A, K1 extends string>(
|
||||
nodeFunc: (arg1: A, callback: (err: any, data: T) => void) => void,
|
||||
options: [K1]
|
||||
): (arg1: A) => RSVP.Promise<{ [K in K1]: T }>;
|
||||
|
||||
// ----- hash and hashSettled ----- //
|
||||
function hash<T>(object: { [P in keyof T]: Arg<T[P]> }, label?: string): RSVP.Promise<T>;
|
||||
function hashSettled<T>(
|
||||
object: { [P in keyof T]: Arg<T[P]> },
|
||||
label?: string
|
||||
): RSVP.Promise<{ [P in keyof T]: PromiseState<T[P]> }>;
|
||||
|
||||
function allSettled<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(
|
||||
entries: [
|
||||
Arg<T1>,
|
||||
Arg<T2>,
|
||||
Arg<T3>,
|
||||
Arg<T4>,
|
||||
Arg<T5>,
|
||||
Arg<T6>,
|
||||
Arg<T7>,
|
||||
Arg<T8>,
|
||||
Arg<T9>,
|
||||
Arg<T10>
|
||||
],
|
||||
label?: string
|
||||
): RSVP.Promise<
|
||||
[
|
||||
PromiseState<T1>,
|
||||
PromiseState<T2>,
|
||||
PromiseState<T3>,
|
||||
PromiseState<T4>,
|
||||
PromiseState<T5>,
|
||||
PromiseState<T6>,
|
||||
PromiseState<T7>,
|
||||
PromiseState<T8>,
|
||||
PromiseState<T9>
|
||||
]
|
||||
>;
|
||||
function allSettled<T1, T2, T3, T4, T5, T6, T7, T8, T9>(
|
||||
entries: [
|
||||
Arg<T1>,
|
||||
Arg<T2>,
|
||||
Arg<T3>,
|
||||
Arg<T4>,
|
||||
Arg<T5>,
|
||||
Arg<T6>,
|
||||
Arg<T7>,
|
||||
Arg<T8>,
|
||||
Arg<T9>
|
||||
],
|
||||
label?: string
|
||||
): RSVP.Promise<
|
||||
[
|
||||
PromiseState<T1>,
|
||||
PromiseState<T2>,
|
||||
PromiseState<T3>,
|
||||
PromiseState<T4>,
|
||||
PromiseState<T5>,
|
||||
PromiseState<T6>,
|
||||
PromiseState<T7>,
|
||||
PromiseState<T8>,
|
||||
PromiseState<T9>
|
||||
]
|
||||
>;
|
||||
function allSettled<T1, T2, T3, T4, T5, T6, T7, T8>(
|
||||
entries: [Arg<T1>, Arg<T2>, Arg<T3>, Arg<T4>, Arg<T5>, Arg<T6>, Arg<T7>, Arg<T8>],
|
||||
label?: string
|
||||
): RSVP.Promise<
|
||||
[
|
||||
PromiseState<T1>,
|
||||
PromiseState<T2>,
|
||||
PromiseState<T3>,
|
||||
PromiseState<T4>,
|
||||
PromiseState<T5>,
|
||||
PromiseState<T6>,
|
||||
PromiseState<T7>,
|
||||
PromiseState<T8>
|
||||
]
|
||||
>;
|
||||
function allSettled<T1, T2, T3, T4, T5, T6, T7>(
|
||||
entries: [Arg<T1>, Arg<T2>, Arg<T3>, Arg<T4>, Arg<T5>, Arg<T6>, Arg<T7>],
|
||||
label?: string
|
||||
): RSVP.Promise<
|
||||
[
|
||||
PromiseState<T1>,
|
||||
PromiseState<T2>,
|
||||
PromiseState<T3>,
|
||||
PromiseState<T4>,
|
||||
PromiseState<T5>,
|
||||
PromiseState<T6>,
|
||||
PromiseState<T7>
|
||||
]
|
||||
>;
|
||||
function allSettled<T1, T2, T3, T4, T5, T6>(
|
||||
entries: [Arg<T1>, Arg<T2>, Arg<T3>, Arg<T4>, Arg<T5>, Arg<T6>],
|
||||
label?: string
|
||||
): RSVP.Promise<
|
||||
[
|
||||
PromiseState<T1>,
|
||||
PromiseState<T2>,
|
||||
PromiseState<T3>,
|
||||
PromiseState<T4>,
|
||||
PromiseState<T5>,
|
||||
PromiseState<T6>
|
||||
]
|
||||
>;
|
||||
function allSettled<T1, T2, T3, T4, T5>(
|
||||
entries: [Arg<T1>, Arg<T2>, Arg<T3>, Arg<T4>, Arg<T5>],
|
||||
label?: string
|
||||
): RSVP.Promise<
|
||||
[
|
||||
PromiseState<T1>,
|
||||
PromiseState<T2>,
|
||||
PromiseState<T3>,
|
||||
PromiseState<T4>,
|
||||
PromiseState<T5>
|
||||
]
|
||||
>;
|
||||
function allSettled<T1, T2, T3, T4>(
|
||||
entries: [Arg<T1>, Arg<T2>, Arg<T3>, Arg<T4>],
|
||||
label?: string
|
||||
): RSVP.Promise<[PromiseState<T1>, PromiseState<T2>, PromiseState<T3>, PromiseState<T4>]>;
|
||||
function allSettled<T1, T2, T3>(
|
||||
entries: [Arg<T1>, Arg<T2>, Arg<T3>],
|
||||
label?: string
|
||||
): RSVP.Promise<[PromiseState<T1>, PromiseState<T2>, PromiseState<T3>]>;
|
||||
function allSettled<T1, T2>(
|
||||
entries: [Arg<T1>, Arg<T2>],
|
||||
label?: string
|
||||
): RSVP.Promise<[PromiseState<T1>, PromiseState<T2>]>;
|
||||
function allSettled<T>(entries: Arg<T>[], label?: string): RSVP.Promise<[PromiseState<T>]>;
|
||||
|
||||
function map<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, U>(
|
||||
entries: [
|
||||
Arg<T1>,
|
||||
Arg<T2>,
|
||||
Arg<T3>,
|
||||
Arg<T4>,
|
||||
Arg<T5>,
|
||||
Arg<T6>,
|
||||
Arg<T7>,
|
||||
Arg<T8>,
|
||||
Arg<T9>,
|
||||
Arg<T10>
|
||||
],
|
||||
mapFn: (item: T1 | T2 | T3 | T4 | T5 | T6 | T7 | T8 | T9 | T10) => U,
|
||||
label?: string
|
||||
): RSVP.Promise<Array<U> & { length: 10 }>;
|
||||
|
||||
function map<T1, T2, T3, T4, T5, T6, T7, T8, T9, U>(
|
||||
entries: [
|
||||
Arg<T1>,
|
||||
Arg<T2>,
|
||||
Arg<T3>,
|
||||
Arg<T4>,
|
||||
Arg<T5>,
|
||||
Arg<T6>,
|
||||
Arg<T7>,
|
||||
Arg<T8>,
|
||||
Arg<T9>
|
||||
],
|
||||
mapFn: (item: T1 | T2 | T3 | T4 | T5 | T6 | T7 | T8 | T9) => U,
|
||||
label?: string
|
||||
): RSVP.Promise<Array<U> & { length: 9 }>;
|
||||
function map<T1, T2, T3, T4, T5, T6, T7, T8, U>(
|
||||
entries: [Arg<T1>, Arg<T2>, Arg<T3>, Arg<T4>, Arg<T5>, Arg<T6>, Arg<T7>, Arg<T8>],
|
||||
mapFn: (item: T1 | T2 | T3 | T4 | T5 | T6 | T7 | T8) => U,
|
||||
label?: string
|
||||
): RSVP.Promise<Array<U> & { length: 8 }>;
|
||||
function map<T1, T2, T3, T4, T5, T6, T7, U>(
|
||||
entries: [Arg<T1>, Arg<T2>, Arg<T3>, Arg<T4>, Arg<T5>, Arg<T6>, Arg<T7>],
|
||||
mapFn: (item: T1 | T2 | T3 | T4 | T5 | T6 | T7) => U,
|
||||
label?: string
|
||||
): RSVP.Promise<Array<U> & { length: 7 }>;
|
||||
function map<T1, T2, T3, T4, T5, T6, U>(
|
||||
entries: [Arg<T1>, Arg<T2>, Arg<T3>, Arg<T4>, Arg<T5>, Arg<T6>],
|
||||
mapFn: (item: T1 | T2 | T3 | T4 | T5 | T6) => U,
|
||||
label?: string
|
||||
): RSVP.Promise<Array<U> & { length: 6 }>;
|
||||
function map<T1, T2, T3, T4, T5, U>(
|
||||
entries: [Arg<T1>, Arg<T2>, Arg<T3>, Arg<T4>, Arg<T5>],
|
||||
mapFn: (item: T1 | T2 | T3 | T4 | T5) => U,
|
||||
label?: string
|
||||
): RSVP.Promise<Array<U> & { length: 5 }>;
|
||||
function map<T1, T2, T3, T4, U>(
|
||||
entries: [Arg<T1>, Arg<T2>, Arg<T3>, Arg<T4>],
|
||||
mapFn: (item: T1 | T2 | T3 | T4) => U,
|
||||
label?: string
|
||||
): RSVP.Promise<Array<U> & { length: 4 }>;
|
||||
function map<T1, T2, T3, U>(
|
||||
entries: [Arg<T1>, Arg<T2>, Arg<T3>],
|
||||
mapFn: (item: T1 | T2 | T3) => U,
|
||||
label?: string
|
||||
): RSVP.Promise<Array<U> & { length: 3 }>;
|
||||
function map<T1, T2, U>(
|
||||
entries: [Arg<T1>, Arg<T2>],
|
||||
mapFn: (item: T1 | T2) => U,
|
||||
label?: string
|
||||
): RSVP.Promise<Array<U> & { length: 2 }>;
|
||||
function map<T, U>(
|
||||
entries: Arg<T>[],
|
||||
mapFn: (item: T) => U,
|
||||
label?: string
|
||||
): RSVP.Promise<Array<U> & { length: 1 }>;
|
||||
|
||||
function filter<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(
|
||||
entries: [
|
||||
Arg<T1>,
|
||||
Arg<T2>,
|
||||
Arg<T3>,
|
||||
Arg<T4>,
|
||||
Arg<T5>,
|
||||
Arg<T6>,
|
||||
Arg<T7>,
|
||||
Arg<T8>,
|
||||
Arg<T9>,
|
||||
Arg<T10>
|
||||
],
|
||||
filterFn: (item: T1 | T2 | T3 | T4 | T5 | T6 | T7 | T8 | T9 | T10) => boolean,
|
||||
label?: string
|
||||
): RSVP.Promise<Array<T1 | T2 | T3 | T4 | T5 | T6 | T7 | T8 | T9 | T10>>;
|
||||
function filter<T1, T2, T3, T4, T5, T6, T7, T8, T9>(
|
||||
entries: [
|
||||
Arg<T1>,
|
||||
Arg<T2>,
|
||||
Arg<T3>,
|
||||
Arg<T4>,
|
||||
Arg<T5>,
|
||||
Arg<T6>,
|
||||
Arg<T7>,
|
||||
Arg<T8>,
|
||||
Arg<T9>
|
||||
],
|
||||
filterFn: (item: T1 | T2 | T3 | T4 | T5 | T6 | T7 | T8 | T9) => boolean,
|
||||
label?: string
|
||||
): RSVP.Promise<Array<T1 | T2 | T3 | T4 | T5 | T6 | T7 | T8 | T9>>;
|
||||
function filter<T1, T2, T3, T4, T5, T6, T7, T8>(
|
||||
entries: [Arg<T1>, Arg<T2>, Arg<T3>, Arg<T4>, Arg<T5>, Arg<T6>, Arg<T7>, Arg<T8>],
|
||||
filterFn: (item: T1 | T2 | T3 | T4 | T5 | T6 | T7 | T8) => boolean,
|
||||
label?: string
|
||||
): RSVP.Promise<Array<T1 | T2 | T3 | T4 | T5 | T6 | T7 | T8>>;
|
||||
function filter<T1, T2, T3, T4, T5, T6, T7>(
|
||||
entries: [Arg<T1>, Arg<T2>, Arg<T3>, Arg<T4>, Arg<T5>, Arg<T6>, Arg<T7>],
|
||||
filterFn: (item: T1 | T2 | T3 | T4 | T5 | T6 | T7) => boolean,
|
||||
label?: string
|
||||
): RSVP.Promise<Array<T1 | T2 | T3 | T4 | T5 | T6 | T7>>;
|
||||
function filter<T1, T2, T3, T4, T5, T6>(
|
||||
entries: [Arg<T1>, Arg<T2>, Arg<T3>, Arg<T4>, Arg<T5>, Arg<T6>],
|
||||
filterFn: (item: T1 | T2 | T3 | T4 | T5 | T6) => boolean,
|
||||
label?: string
|
||||
): RSVP.Promise<Array<T1 | T2 | T3 | T4 | T5 | T6> & { length: 6 }>;
|
||||
function filter<T1, T2, T3, T4, T5>(
|
||||
entries: [Arg<T1>, Arg<T2>, Arg<T3>, Arg<T4>, Arg<T5>],
|
||||
filterFn: (item: T1 | T2 | T3 | T4 | T5) => boolean,
|
||||
label?: string
|
||||
): RSVP.Promise<Array<T1 | T2 | T3 | T4 | T5>>;
|
||||
function filter<T1, T2, T3, T4>(
|
||||
entries: [Arg<T1>, Arg<T2>, Arg<T3>, Arg<T4>],
|
||||
filterFn: (item: T1 | T2 | T3 | T4) => boolean,
|
||||
label?: string
|
||||
): RSVP.Promise<Array<T1 | T2 | T3 | T4>>;
|
||||
function filter<T1, T2, T3>(
|
||||
entries: [Arg<T1>, Arg<T2>, Arg<T3>],
|
||||
filterFn: (item: T1 | T2 | T3) => boolean,
|
||||
label?: string
|
||||
): RSVP.Promise<Array<T1 | T2 | T3>>;
|
||||
function filter<T1, T2>(
|
||||
entries: [Arg<T1>, Arg<T2>],
|
||||
filterFn: (item: T1 | T2) => boolean,
|
||||
label?: string
|
||||
): RSVP.Promise<Array<T1 | T2>>;
|
||||
function filter<T>(
|
||||
entries: Arg<T>[],
|
||||
filterFn: (item: T) => boolean,
|
||||
label?: string
|
||||
): RSVP.Promise<Array<T>>;
|
||||
|
||||
function defer<T>(label?: string): Deferred<T>;
|
||||
|
||||
function configure<T>(name: string): T;
|
||||
function configure<T>(name: string, value: T): void;
|
||||
|
||||
function asap<T, U>(callback: (callbackArg: T) => U, arg: T): void;
|
||||
|
||||
const async: typeof asap;
|
||||
}
|
||||
|
||||
export namespace EventTarget {
|
||||
/** `RSVP.EventTarget.mixin` extends an object with EventTarget methods. */
|
||||
function mixin(object: object): ObjectWithEventMixins;
|
||||
export default RSVP;
|
||||
|
||||
/** Registers a callback to be executed when `eventName` is triggered */
|
||||
function on(
|
||||
eventName: 'created' | 'chained' | 'fulfilled' | 'rejected',
|
||||
listener: (event: InstrumentEvent) => void
|
||||
): void;
|
||||
function on(eventName: 'error', errorHandler: (reason: any) => void): void;
|
||||
function on(eventName: string, callback: (value: any) => void): void;
|
||||
|
||||
/**
|
||||
* You can use `off` to stop firing a particular callback for an event.
|
||||
*
|
||||
* If you don't pass a `callback` argument to `off`, ALL callbacks for the
|
||||
* event will not be executed when the event fires.
|
||||
*/
|
||||
function off(eventName: string, callback?: (value: any) => void): void;
|
||||
|
||||
/**
|
||||
* Use `trigger` to fire custom events.
|
||||
*
|
||||
* You can also pass a value as a second argument to `trigger` that will be
|
||||
* passed as an argument to all event listeners for the event
|
||||
*/
|
||||
function trigger(eventName: string, options?: any, label?: string): void;
|
||||
}
|
||||
|
||||
export function configure(
|
||||
configName: 'instrument' | 'instrument-with-stack',
|
||||
shouldInstrument: boolean
|
||||
): void;
|
||||
export function configure(configName: string, value: any): void;
|
||||
|
||||
/**
|
||||
* Make a promise that fulfills when every item in the array fulfills, and rejects if (and when) any item rejects.
|
||||
* the array passed to all can be a mixture of promise-like objects and other objects.
|
||||
* The fulfillment value is an array (in order) of fulfillment values. The rejection value is the first rejection value.
|
||||
*/
|
||||
export function all<T, C>(promises: Thenable<T, C>[]): Promise<T[], C>;
|
||||
|
||||
/**
|
||||
* `RSVP.hash` is similar to `RSVP.all`, but takes an object instead of an array
|
||||
* for its `promises` argument.
|
||||
*
|
||||
* Returns a promise that is fulfilled when all the given promises have been
|
||||
* fulfilled, or rejected if any of them become rejected. The returned promise
|
||||
* is fulfilled with a hash that has the same key names as the `promises` object
|
||||
* argument. If any of the values in the object are not promises, they will
|
||||
* simply be copied over to the fulfilled object.
|
||||
*
|
||||
* If any of the `promises` given to `RSVP.hash` are rejected, the first promise
|
||||
* that is rejected will be given as the reason to the rejection handler.
|
||||
*/
|
||||
export function hash<T, C>(promises: PromiseHash<T, C>): Promise<T, C>;
|
||||
|
||||
/**
|
||||
* `RSVP.map` is similar to JavaScript's native `map` method. `mapFn` is eagerly called
|
||||
* meaning that as soon as any promise resolves its value will be passed to `mapFn`.
|
||||
* `RSVP.map` returns a promise that will become fulfilled with the result of running
|
||||
* `mapFn` on the values the promises become fulfilled with.
|
||||
*
|
||||
* If any of the `promises` given to `RSVP.map` are rejected, the first promise
|
||||
* that is rejected will be given as an argument to the returned promise's
|
||||
* rejection handler.
|
||||
*/
|
||||
export function map<T, U, C>(
|
||||
promises: Thenable<T, C>[],
|
||||
mapFn: (item: T) => U,
|
||||
label?: string
|
||||
): Promise<U[], C>;
|
||||
|
||||
/**
|
||||
* `RSVP.allSettled` is similar to `RSVP.all`, but instead of implementing
|
||||
* a fail-fast method, it waits until all the promises have returned and
|
||||
* shows you all the results. This is useful if you want to handle multiple
|
||||
* promises' failure states together as a set.
|
||||
*/
|
||||
export function allSettled<T, C>(promises: Thenable<T, C>[]): Promise<PromiseState<T, C>[], C>;
|
||||
|
||||
/**
|
||||
* `RSVP.hashSettled` is similar to `RSVP.allSettled`, but takes an object
|
||||
* instead of an array for its `promises` argument.
|
||||
*
|
||||
* Unlike `RSVP.all` or `RSVP.hash`, which implement a fail-fast method,
|
||||
* but like `RSVP.allSettled`, `hashSettled` waits until all the
|
||||
* constituent promises have returned and then shows you all the results
|
||||
* with their states and values/reasons. This is useful if you want to
|
||||
* handle multiple promises' failure states together as a set.
|
||||
*/
|
||||
export function hashSettled<T, C>(promises: PromiseHash<T, C>): Promise<SettledHash<T, C>, C>;
|
||||
|
||||
/**
|
||||
* Make a Promise that fulfills when any item fulfills, and rejects if any item rejects.
|
||||
*/
|
||||
function race<T, C>(promises: Promise<T, C>[]): Promise<T, C>;
|
||||
|
||||
/**
|
||||
* `RSVP.denodeify` takes a "node-style" function and returns a function that
|
||||
* will return an `RSVP.Promise`. You can use `denodeify` in Node.js or the
|
||||
* browser when you'd prefer to use promises over using callbacks. For example,
|
||||
* `denodeify` transforms the following:
|
||||
*
|
||||
* ```
|
||||
* let fs = require('fs');
|
||||
*
|
||||
* fs.readFile('myfile.txt', function(err, data){
|
||||
* if (err) return handleError(err);
|
||||
* handleData(data);
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* into:
|
||||
*
|
||||
* ```
|
||||
* let fs = require('fs');
|
||||
* let readFile = RSVP.denodeify(fs.readFile);
|
||||
*
|
||||
* readFile('myfile.txt').then(handleData, handleError);
|
||||
* ```
|
||||
*
|
||||
* If the node function has multiple success parameters, then denodeify just
|
||||
* returns the first one:
|
||||
*
|
||||
* ```
|
||||
* let request = RSVP.denodeify(require('request'));
|
||||
*
|
||||
* request('http://example.com').then(function(res) {
|
||||
* // ...
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* However, if you need all success parameters, setting denodeify's second
|
||||
* parameter to true causes it to return all success parameters as an array:
|
||||
*
|
||||
* ```
|
||||
* let request = RSVP.denodeify(require('request'), true);
|
||||
*
|
||||
* request('http://example.com').then(function(result) {
|
||||
* // result[0] -> res
|
||||
* // result[1] -> body
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* Or if you pass it an array with names it returns the parameters as a hash:
|
||||
*
|
||||
* ```
|
||||
* let request = RSVP.denodeify(require('request'), ['res', 'body']);
|
||||
*
|
||||
* request('http://example.com').then(function(result) {
|
||||
* // result.res
|
||||
* // result.body
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
export function denodeify<A, T, C>(
|
||||
nodeFunction: Function,
|
||||
options: boolean | string[]
|
||||
): (...args: A[]) => Promise<T, C>;
|
||||
|
||||
/**
|
||||
* `RSVP.defer` returns an object similar to jQuery's `$.Deferred`.
|
||||
* `RSVP.defer` should be used when porting over code reliant on `$.Deferred`'s
|
||||
* interface. New code should use the `RSVP.Promise` constructor instead.
|
||||
*
|
||||
* The object returned from `RSVP.defer` is a plain object with three properties:
|
||||
* * promise - an `RSVP.Promise`.
|
||||
* * reject - a function that causes the `promise` property on this object to become rejected
|
||||
* * resolve - a function that causes the `promise` property on this object to become fulfilled.
|
||||
*/
|
||||
export function defer<T, C>(label?: string): Deferred<T, C>;
|
||||
|
||||
/**
|
||||
* `RSVP.Promise.reject` returns a promise rejected with the passed `reason`.
|
||||
*/
|
||||
export function reject<C>(reason: C): Promise<never, C>;
|
||||
|
||||
/**
|
||||
* `RSVP.Promise.resolve` returns a promise that will become resolved with the
|
||||
* passed `value`.
|
||||
*/
|
||||
export function resolve<T>(value: T): Promise<T, never>;
|
||||
|
||||
/**
|
||||
* `RSVP.filter` is similar to JavaScript's native `filter` method, except that it
|
||||
* waits for all promises to become fulfilled before running the `filterFn` on
|
||||
* each item in given to `promises`. `RSVP.filter` returns a promise that will
|
||||
* become fulfilled with the result of running `filterFn` on the values the
|
||||
* promises become fulfilled with.
|
||||
*/
|
||||
export function filter<T, C>(
|
||||
promises: Thenable<T, C>[],
|
||||
filterFn: (value: T) => boolean | Promise<any, any>
|
||||
): Promise<T[], C>;
|
||||
|
||||
/**
|
||||
* `RSVP.rethrow` will rethrow an error on the next turn of the JavaScript event
|
||||
* loop in order to aid debugging.
|
||||
*
|
||||
* Promises A+ specifies that any exceptions that occur with a promise must be
|
||||
* caught by the promises implementation and bubbled to the last handler. For
|
||||
* this reason, it is recommended that you always specify a second rejection
|
||||
* handler function to `then`. However, `RSVP.rethrow` will throw the exception
|
||||
* outside of the promise, so it bubbles up to your console if in the browser,
|
||||
* or domain/cause uncaught exception in Node. `rethrow` will also throw the
|
||||
* error again so the error can be handled by the promise per the spec.
|
||||
*/
|
||||
export function rethrow<C>(reason: C): void;
|
||||
export const asap: typeof RSVP.asap;
|
||||
export const cast: typeof RSVP.cast;
|
||||
export const Promise: typeof RSVP.Promise;
|
||||
export const EventTarget: typeof RSVP.EventTarget;
|
||||
export const all: typeof RSVP.all;
|
||||
export const allSettled: typeof RSVP.allSettled;
|
||||
export const race: typeof RSVP.race;
|
||||
export const hash: typeof RSVP.hash;
|
||||
export const hashSettled: typeof RSVP.hashSettled;
|
||||
export const rethrow: typeof RSVP.rethrow;
|
||||
export const defer: typeof RSVP.defer;
|
||||
export const denodeify: typeof RSVP.denodeify;
|
||||
export const configure: typeof RSVP.configure;
|
||||
export const on: typeof RSVP.on;
|
||||
export const off: typeof RSVP.off;
|
||||
export const resolve: typeof RSVP.resolve;
|
||||
export const reject: typeof RSVP.reject;
|
||||
export const map: typeof RSVP.map;
|
||||
export const async: typeof RSVP.async;
|
||||
export const filter: typeof RSVP.filter;
|
||||
}
|
||||
|
||||
export = RSVP;
|
||||
|
||||
397
types/rsvp/rsvp-tests.ts
Normal file → Executable file
397
types/rsvp/rsvp-tests.ts
Normal file → Executable file
@ -1,83 +1,326 @@
|
||||
import RSVP = require('rsvp');
|
||||
import RSVP from 'rsvp';
|
||||
import { all, race, resolve } from 'rsvp';
|
||||
|
||||
let promise1: RSVP.Promise<number, Error> = RSVP.Promise.resolve(1);
|
||||
let promise1a: RSVP.Promise<number, Error> = RSVP.resolve(1);
|
||||
/** 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
|
||||
declare function assertType<T>(value: T): void;
|
||||
|
||||
let promise2: RSVP.Promise<number, Error> = RSVP.Promise.resolve(2);
|
||||
async function testAsyncAwait() {
|
||||
const awaitedNothing = await RSVP.resolve();
|
||||
const awaitedValue = await RSVP.resolve('just a value');
|
||||
|
||||
let promise3: RSVP.Promise<number, Error> = RSVP.Promise.reject(new Error('3'));
|
||||
let promise3a: RSVP.Promise<number, Error> = RSVP.reject(new Error('3'));
|
||||
async function returnsAPromise(): RSVP.Promise<string> {
|
||||
return RSVP.resolve('look, a string');
|
||||
}
|
||||
|
||||
let promiseArray = [promise1, promise2, promise3];
|
||||
|
||||
let promiseHash = {
|
||||
promiseA: promise1,
|
||||
promiseB: promise2,
|
||||
promiseC: promise3,
|
||||
notAPromise: 4,
|
||||
};
|
||||
|
||||
RSVP.Promise.all(promiseArray).then(arr => {}, err => {});
|
||||
RSVP.all(promiseArray).then(arr => {}, err => {});
|
||||
|
||||
RSVP.Promise.race(promiseArray).then(arr => {}, err => {});
|
||||
RSVP.race(promiseArray).then(arr => {}, err => {});
|
||||
|
||||
RSVP.allSettled(promiseArray).then(arr => {}, err => {});
|
||||
|
||||
let deferred = RSVP.defer();
|
||||
deferred.resolve('Success');
|
||||
deferred.promise.then(value => {});
|
||||
|
||||
let filterFn = (item: number) => {
|
||||
return item > 1;
|
||||
};
|
||||
RSVP.filter(promiseArray, filterFn).then(result => {});
|
||||
|
||||
RSVP.hashSettled(promiseHash).then(hash => {
|
||||
return (
|
||||
hash.promiseA.state === 'fulfilled' &&
|
||||
hash.promiseB.value === 2 &&
|
||||
hash.promiseC.reason === '3' &&
|
||||
hash.notAPromise.state === 'fulfilled'
|
||||
);
|
||||
});
|
||||
|
||||
RSVP.hash(promiseHash).then(
|
||||
values => {
|
||||
return (
|
||||
values.promiseA < 0 &&
|
||||
values.promiseB === 4 &&
|
||||
values.promiseC === 12 &&
|
||||
values.notAPromise > 0
|
||||
);
|
||||
},
|
||||
err => {}
|
||||
);
|
||||
|
||||
let mapFn = function(item: number) {
|
||||
return item + 1;
|
||||
};
|
||||
RSVP.map(promiseArray, mapFn).then(function(result) {});
|
||||
|
||||
let promise = new Promise(function(resolve, reject) {
|
||||
resolve();
|
||||
reject();
|
||||
});
|
||||
promise.then(value => {}, reason => {});
|
||||
|
||||
function throws() {
|
||||
throw new Error('Whoops!');
|
||||
assertType<RSVP.Promise<string>>(returnsAPromise());
|
||||
assertType<string>(await returnsAPromise());
|
||||
}
|
||||
let throwingPromise = new RSVP.Promise(function(resolve, reject) {
|
||||
throws();
|
||||
});
|
||||
throwingPromise.catch(RSVP.rethrow).then(value => {}, reason => {});
|
||||
|
||||
let someObject = {};
|
||||
RSVP.EventTarget.mixin(someObject);
|
||||
RSVP.EventTarget.on('fulfilled', someString => {
|
||||
return someString;
|
||||
});
|
||||
RSVP.EventTarget.trigger('fulfilled', 'woohoo');
|
||||
RSVP.EventTarget.off('fulfilled');
|
||||
function testCast() {
|
||||
RSVP.Promise.cast('foo').then(value => {
|
||||
assertType<string>(value);
|
||||
});
|
||||
|
||||
RSVP.cast(42).then(value => {
|
||||
assertType<number>(value);
|
||||
});
|
||||
}
|
||||
|
||||
function testConfigure() {
|
||||
assertType<void>(RSVP.configure('name', { with: 'some value' }));
|
||||
assertType<{}>(RSVP.configure('name'));
|
||||
}
|
||||
|
||||
function testAsap() {
|
||||
const result = RSVP.asap(something => {
|
||||
console.log(something);
|
||||
}, 'srsly');
|
||||
|
||||
assertType<void>(result);
|
||||
}
|
||||
|
||||
function testAsync() {
|
||||
const result = RSVP.async(something => {
|
||||
console.log(something);
|
||||
}, 'rly srsly');
|
||||
|
||||
assertType<void>(result);
|
||||
}
|
||||
|
||||
function testPromise() {
|
||||
const promiseOfString = new RSVP.Promise((resolve: any, reject: any) => resolve('some string'));
|
||||
assertType<RSVP.Promise<number>>(promiseOfString.then((s: string) => s.length));
|
||||
}
|
||||
|
||||
function testAll() {
|
||||
const imported = all([]);
|
||||
const empty = RSVP.Promise.all([]);
|
||||
|
||||
const everyPromise = RSVP.all([
|
||||
'string',
|
||||
RSVP.resolve(42),
|
||||
RSVP.resolve({ hash: 'with values' }),
|
||||
]);
|
||||
|
||||
assertType<RSVP.Promise<[string, number, { hash: string }]>>(everyPromise);
|
||||
|
||||
const anyFailure = RSVP.all([12, 'strings', RSVP.reject('anywhere')]);
|
||||
assertType<RSVP.Promise<{}>>(anyFailure);
|
||||
|
||||
let promise1 = RSVP.resolve(1);
|
||||
let promise2 = RSVP.resolve('2');
|
||||
let promise3 = RSVP.resolve({ key: 13 });
|
||||
RSVP.Promise.all([promise1, promise2, promise3], 'my label').then(function(array) {
|
||||
assertType<number>(array[0]);
|
||||
assertType<string>(array[1]);
|
||||
assertType<{ key: number }>(array[2]);
|
||||
});
|
||||
}
|
||||
|
||||
function testAllSettled() {
|
||||
const resolved1 = RSVP.resolve(1);
|
||||
const resolved2 = RSVP.resolve('wat');
|
||||
const rejected = RSVP.reject(new Error('oh teh noes'));
|
||||
const pending = new RSVP.Promise<{ neato: string }>((resolve, reject) => {
|
||||
if ('something') {
|
||||
resolve({ neato: 'yay' });
|
||||
} else {
|
||||
reject('nay');
|
||||
}
|
||||
});
|
||||
|
||||
// Types flow into resolution properly
|
||||
RSVP.allSettled([resolved1, resolved2, rejected, pending]).then(states => {
|
||||
assertType<RSVP.PromiseState<number>>(states[0]);
|
||||
assertType<RSVP.PromiseState<string>>(states[1]);
|
||||
assertType<RSVP.PromiseState<never>>(states[2]);
|
||||
assertType<RSVP.PromiseState<{ neato: string }>>(states[3]);
|
||||
});
|
||||
|
||||
// Switching on state gives the correctly available items.
|
||||
RSVP.allSettled([resolved1, resolved2, rejected, pending]).then(states => {
|
||||
states.forEach(element => {
|
||||
switch (element.state) {
|
||||
case RSVP.State.fulfilled:
|
||||
assertType<RSVP.Resolved<typeof element.value>>(element);
|
||||
break;
|
||||
|
||||
case RSVP.State.rejected:
|
||||
assertType<RSVP.Rejected<typeof element.reason>>(element);
|
||||
break;
|
||||
|
||||
case RSVP.State.pending:
|
||||
assertType<RSVP.Pending>(element);
|
||||
break;
|
||||
|
||||
default:
|
||||
// Someday maybe TS will have exhaustiveness checks.
|
||||
break;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function testDefer() {
|
||||
let deferred = RSVP.defer<string>();
|
||||
deferred.resolve('Success!');
|
||||
deferred.promise.then(function(value) {
|
||||
assertType<string>(value);
|
||||
});
|
||||
}
|
||||
|
||||
// Using this to differentiate the types cleanly
|
||||
type A1 = Array<{ arg: boolean }>;
|
||||
type D1 = number;
|
||||
type D2 = string;
|
||||
type D3 = { some: boolean };
|
||||
|
||||
declare const nodeFn1Arg1CbParam: (arg1: A1, callback: (err: any, data: D1) => void) => void;
|
||||
declare const nodeFn1Arg2CbParam: (
|
||||
arg1: A1,
|
||||
callback: (err: any, data1: D1, data2: D2) => void
|
||||
) => void;
|
||||
declare const nodeFn1Arg3CbParam: (
|
||||
arg1: A1,
|
||||
callback: (err: any, data1: D1, data2: D2, data3: D3) => void
|
||||
) => void;
|
||||
|
||||
function testDenodeify() {
|
||||
// version with no `options` or `options: false`, and single T
|
||||
assertType<(value: A1) => RSVP.Promise<D1>>(RSVP.denodeify(nodeFn1Arg1CbParam));
|
||||
assertType<(value: A1) => RSVP.Promise<D1>>(RSVP.denodeify(nodeFn1Arg1CbParam, false));
|
||||
|
||||
// version with no `options` or `options: false`, and multiple T
|
||||
assertType<(value: A1) => RSVP.Promise<D1>>(RSVP.denodeify(nodeFn1Arg2CbParam));
|
||||
assertType<(value: A1) => RSVP.Promise<D1>>(RSVP.denodeify(nodeFn1Arg3CbParam));
|
||||
assertType<(value: A1) => RSVP.Promise<D1>>(RSVP.denodeify(nodeFn1Arg2CbParam, false));
|
||||
assertType<(value: A1) => RSVP.Promise<D1>>(RSVP.denodeify(nodeFn1Arg3CbParam, false));
|
||||
|
||||
// version with `options: true` and single or multiple T
|
||||
assertType<(value: A1) => RSVP.Promise<[D1]>>(RSVP.denodeify(nodeFn1Arg1CbParam, true));
|
||||
assertType<(value: A1) => RSVP.Promise<[D1, D2]>>(RSVP.denodeify(nodeFn1Arg2CbParam, true));
|
||||
assertType<(value: A1) => RSVP.Promise<[D1, D2, D3]>>(RSVP.denodeify(nodeFn1Arg3CbParam, true));
|
||||
|
||||
// We can't actually map the key names here, because we would need full-on
|
||||
// dependent typing to use the *values of an array* as the keys of the
|
||||
// resulting object.
|
||||
assertType<(value: A1) => RSVP.Promise<{ first: D1 }>>(
|
||||
RSVP.denodeify(nodeFn1Arg1CbParam, ['first'])
|
||||
);
|
||||
assertType<(value: A1) => RSVP.Promise<{ first: D1; second: D2 }>>(
|
||||
RSVP.denodeify(nodeFn1Arg2CbParam, ['first', 'second'])
|
||||
);
|
||||
assertType<(value: A1) => RSVP.Promise<{ first: D1; second: D2; third: D3 }>>(
|
||||
RSVP.denodeify(nodeFn1Arg3CbParam, ['first', 'second', 'third'])
|
||||
);
|
||||
|
||||
const foo = RSVP.denodeify(nodeFn1Arg2CbParam, ['quux', 'baz']);
|
||||
foo([{ arg: true }]).then(value => {
|
||||
console.log(value.quux + 1);
|
||||
console.log(value.baz.length);
|
||||
});
|
||||
}
|
||||
|
||||
function testFilter() {
|
||||
RSVP.filter([RSVP.resolve(1), RSVP.resolve(2)], item => item > 1, 'over one').then(results => {
|
||||
assertType<number[]>(results);
|
||||
});
|
||||
|
||||
RSVP.filter(
|
||||
[RSVP.resolve('a string'), RSVP.resolve(112233)],
|
||||
item => String(item).length < 10,
|
||||
'short string'
|
||||
).then(results => {
|
||||
assertType<Array<string | number>>(results);
|
||||
});
|
||||
|
||||
// This is the best we can do: we can't actually write the full type here,
|
||||
// which would be `assertType<never>(results)`, but TS can't infer that.
|
||||
const isString = (item: any): item is string => typeof item === 'string';
|
||||
RSVP.filter([RSVP.reject('for any reason')], isString).then(results => {
|
||||
assertType<{}>(results);
|
||||
});
|
||||
}
|
||||
|
||||
function testHash() {
|
||||
let promises = {
|
||||
myPromise: RSVP.resolve(1),
|
||||
yourPromise: RSVP.resolve('2'),
|
||||
theirPromise: RSVP.resolve({ key: 3 }),
|
||||
notAPromise: 4,
|
||||
};
|
||||
RSVP.hash(promises, 'my label').then(function(hash) {
|
||||
assertType<number>(hash.myPromise);
|
||||
assertType<string>(hash.yourPromise);
|
||||
assertType<{ key: number }>(hash.theirPromise);
|
||||
assertType<number>(hash.notAPromise);
|
||||
});
|
||||
}
|
||||
|
||||
function testHashSettled() {
|
||||
function isFulfilled<T>(state: RSVP.PromiseState<T>): state is RSVP.Resolved<T> {
|
||||
return state.state === RSVP.State.fulfilled;
|
||||
}
|
||||
let promises = {
|
||||
myPromise: RSVP.Promise.resolve(1),
|
||||
yourPromise: RSVP.Promise.resolve('2'),
|
||||
theirPromise: RSVP.Promise.resolve({ key: 3 }),
|
||||
notAPromise: 4,
|
||||
};
|
||||
RSVP.hashSettled(promises).then(function(hash) {
|
||||
if (isFulfilled(hash.myPromise)) {
|
||||
assertType<number>(hash.myPromise.value);
|
||||
}
|
||||
if (isFulfilled(hash.yourPromise)) {
|
||||
assertType<string>(hash.yourPromise.value);
|
||||
}
|
||||
if (isFulfilled(hash.theirPromise)) {
|
||||
assertType<{ key: number }>(hash.theirPromise.value);
|
||||
}
|
||||
if (isFulfilled(hash.notAPromise)) {
|
||||
assertType<number>(hash.notAPromise.value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function testMap() {
|
||||
RSVP.map([RSVP.resolve(1), RSVP.resolve(2)], item => item + 1, 'add one').then(results => {
|
||||
assertType<number[]>(results);
|
||||
assertType<{ length: 2 }>(results);
|
||||
});
|
||||
|
||||
RSVP.map([RSVP.resolve('a string'), RSVP.resolve(112233)], String).then(results => {
|
||||
assertType<string[]>(results);
|
||||
assertType<{ length: 2 }>(results);
|
||||
});
|
||||
|
||||
// This is the best we can do: we can't actually write the full type here,
|
||||
// which would be `assertType<never>(results)`, but TS can't infer that.
|
||||
RSVP.map([RSVP.reject('for any reason')], String).then(results => {
|
||||
assertType<{}>(results);
|
||||
});
|
||||
}
|
||||
|
||||
function testRace() {
|
||||
const imported = race([]);
|
||||
const firstPromise = RSVP.race([{ notAPromise: true }, RSVP.resolve({ some: 'value' })]);
|
||||
assertType<RSVP.Promise<{ notAPromise: boolean } | { some: string }>>(firstPromise);
|
||||
|
||||
let promise1 = RSVP.resolve(1);
|
||||
let promise2 = RSVP.resolve('2');
|
||||
RSVP.Promise.race([promise1, promise2], 'my label').then(function(result) {
|
||||
assertType<string | number>(result);
|
||||
});
|
||||
}
|
||||
|
||||
function testReject() {
|
||||
assertType<RSVP.Promise<never>>(RSVP.reject());
|
||||
assertType<RSVP.Promise<never>>(RSVP.reject('this is a string'));
|
||||
|
||||
RSVP.reject({ ok: false }).catch(reason => {
|
||||
console.log(`${reason} could be anything`);
|
||||
});
|
||||
RSVP.reject({ ok: false }, 'some label').catch((reason: any) => reason.ok);
|
||||
|
||||
let promise = RSVP.Promise.reject(new Error('WHOOPS'));
|
||||
}
|
||||
|
||||
function testResolve() {
|
||||
assertType<RSVP.Promise<void>>(RSVP.resolve());
|
||||
assertType<RSVP.Promise<string>>(RSVP.resolve('this is a string'));
|
||||
assertType<RSVP.Promise<string>>(RSVP.resolve(RSVP.resolve('nested')));
|
||||
assertType<RSVP.Promise<string>>(RSVP.resolve(Promise.resolve('nested')));
|
||||
|
||||
let promise = RSVP.Promise.resolve(1);
|
||||
let imported = resolve(1);
|
||||
}
|
||||
|
||||
function testRethrow() {
|
||||
RSVP.reject(new Error('all the badness'))
|
||||
.catch(RSVP.rethrow)
|
||||
.then(value => {
|
||||
assertType<void>(value);
|
||||
})
|
||||
.catch(reason => {
|
||||
if (reason instanceof Error) {
|
||||
console.log(reason);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function testOnAndOff() {
|
||||
RSVP.on('error', (reason: Error) => {
|
||||
console.log(`it was an error: ${reason}`);
|
||||
});
|
||||
|
||||
RSVP.off('whatever', (value: any) => {
|
||||
console.log(
|
||||
`any old value will do: ${value !== undefined && value !== null
|
||||
? value.toString()
|
||||
: 'even undefined'}`
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
18
types/rsvp/tsconfig.json
Normal file → Executable file
18
types/rsvp/tsconfig.json
Normal file → Executable file
@ -1,23 +1,17 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"lib": [
|
||||
"es6"
|
||||
],
|
||||
"target": "es5",
|
||||
"lib": ["es6", "dom"],
|
||||
"noImplicitAny": true,
|
||||
"noImplicitThis": true,
|
||||
"strictNullChecks": true,
|
||||
"strictFunctionTypes": true,
|
||||
"strictFunctionTypes": false,
|
||||
"baseUrl": "../",
|
||||
"typeRoots": [
|
||||
"../"
|
||||
],
|
||||
"typeRoots": ["../"],
|
||||
"types": [],
|
||||
"noEmit": true,
|
||||
"forceConsistentCasingInFileNames": true
|
||||
},
|
||||
"files": [
|
||||
"index.d.ts",
|
||||
"rsvp-tests.ts"
|
||||
]
|
||||
}
|
||||
"files": ["index.d.ts", "rsvp-tests.ts"]
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user