[ember] refactor @ember/object types into their own package (#28835)

* [ember] @ember/object types refactored into their own package

* Update create-negative.ts
This commit is contained in:
Mike North
2018-09-17 01:08:12 -07:00
committed by Ryan Cavanaugh
parent 5a12a3f10f
commit 559078d30d
26 changed files with 1059 additions and 0 deletions

38
types/ember__object/computed.d.ts vendored Normal file
View File

@@ -0,0 +1,38 @@
import Ember from 'ember';
type ComputedProperty<Get, Set = Get> = Ember.ComputedProperty<Get, Set>;
declare const ComputedProperty: typeof Ember.ComputedProperty;
export default ComputedProperty;
export const alias: typeof Ember.computed.alias;
export const and: typeof Ember.computed.and;
export const bool: typeof Ember.computed.bool;
export const collect: typeof Ember.computed.collect;
export const deprecatingAlias: typeof Ember.computed.deprecatingAlias;
export const empty: typeof Ember.computed.empty;
export const equal: typeof Ember.computed.equal;
export const expandProperties: typeof Ember.expandProperties;
export const filter: typeof Ember.computed.filter;
export const filterBy: typeof Ember.computed.filterBy;
export const gt: typeof Ember.computed.gt;
export const gte: typeof Ember.computed.gte;
export const intersect: typeof Ember.computed.intersect;
export const lt: typeof Ember.computed.lt;
export const lte: typeof Ember.computed.lte;
export const map: typeof Ember.computed.map;
export const mapBy: typeof Ember.computed.mapBy;
export const match: typeof Ember.computed.match;
export const max: typeof Ember.computed.max;
export const min: typeof Ember.computed.min;
export const none: typeof Ember.computed.none;
export const not: typeof Ember.computed.not;
export const notEmpty: typeof Ember.computed.notEmpty;
export const oneWay: typeof Ember.computed.oneWay;
export const or: typeof Ember.computed.or;
export const readOnly: typeof Ember.computed.readOnly;
export const reads: typeof Ember.computed.reads;
export const setDiff: typeof Ember.computed.setDiff;
export const sort: typeof Ember.computed.sort;
export const sum: typeof Ember.computed.sum;
export const union: typeof Ember.computed.union;
export const uniq: typeof Ember.computed.uniq;
export const uniqBy: typeof Ember.computed.uniqBy;

3
types/ember__object/core.d.ts vendored Normal file
View File

@@ -0,0 +1,3 @@
import Ember from 'ember';
export default class CoreObject extends Ember.CoreObject { }

6
types/ember__object/evented.d.ts vendored Normal file
View File

@@ -0,0 +1,6 @@
import Ember from 'ember';
type Evented = Ember.Evented;
declare const Evented: typeof Ember.Evented;
export default Evented;
export const on: typeof Ember.on;

5
types/ember__object/events.d.ts vendored Normal file
View File

@@ -0,0 +1,5 @@
import Ember from 'ember';
export const addListener: typeof Ember.addListener;
export const removeListener: typeof Ember.removeListener;
export const sendEvent: typeof Ember.sendEvent;

19
types/ember__object/index.d.ts vendored Normal file
View File

@@ -0,0 +1,19 @@
// Type definitions for @ember/object 3.0
// Project: http://emberjs.com/
// Definitions by: Mike North <https://github.com/mike-north>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.8
import Ember from 'ember';
declare class EmberObject extends Ember.Object { }
export default EmberObject;
export const aliasMethod: typeof Ember.aliasMethod;
export const computed: typeof Ember.computed;
export const defineProperty: typeof Ember.defineProperty;
export const get: typeof Ember.get;
export const getProperties: typeof Ember.getProperties;
export const getWithDefault: typeof Ember.getWithDefault;
export const observer: typeof Ember.observer;
export const set: typeof Ember.set;
export const setProperties: typeof Ember.setProperties;
export const trySet: typeof Ember.trySet;

5
types/ember__object/internals.d.ts vendored Normal file
View File

@@ -0,0 +1,5 @@
import Ember from 'ember';
export const cacheFor: typeof Ember.cacheFor;
export const copy: typeof Ember.copy;
export const guidFor: typeof Ember.guidFor;

3
types/ember__object/mixin.d.ts vendored Normal file
View File

@@ -0,0 +1,3 @@
import Ember from 'ember';
export default class Mixin<T, Base = Ember.Object> extends Ember.Mixin<T, Base> {}

5
types/ember__object/observable.d.ts vendored Normal file
View File

@@ -0,0 +1,5 @@
import Ember from 'ember';
type Observable = Ember.Observable;
declare const Observable: typeof Ember.Observable;
export default Observable;

4
types/ember__object/observers.d.ts vendored Normal file
View File

@@ -0,0 +1,4 @@
import Ember from 'ember';
export const addObserver: typeof Ember.addObserver;
export const removeObserver: typeof Ember.removeObserver;

View File

@@ -0,0 +1,5 @@
import Ember from 'ember';
type PromiseProxyMixin<T> = Ember.PromiseProxyMixin<T>;
declare const PromiseProxyMixin: typeof Ember.PromiseProxyMixin;
export default PromiseProxyMixin;

3
types/ember__object/proxy.d.ts vendored Normal file
View File

@@ -0,0 +1,3 @@
import Ember from 'ember';
export default class ObjectProxy extends Ember.ObjectProxy { }

View File

@@ -0,0 +1,21 @@
import { assertType } from './lib/assert';
import EmberObject from '@ember/object';
class Foo extends EmberObject {
hello() { return 'world'; }
protected bar() { return 'bar'; }
private baz() { return 'baz'; }
}
const f = new Foo();
assertType<string>(f.hello());
assertType<string>(f.bar()); // $ExpectError
assertType<string>(f.baz()); // $ExpectError
// TODO: enable after TS 3.0 https://github.com/typed-ember/ember-cli-typescript/issues/291
// class Foo2 extends EmberObject.extend({
// bar: ''
// }) {
// hello() { return 'world'; }
// protected bar() { return 'bar'; } // $ExpectError
// private baz() { return 'baz'; }
// }

View File

@@ -0,0 +1,198 @@
import EmberObject, { computed } from '@ember/object';
import ComputedProperty, {
alias,
or,
and,
filter,
equal,
empty,
filterBy,
notEmpty,
none,
not,
min,
max,
gt,
gte,
lt,
lte,
readOnly,
reads,
setDiff,
sort,
intersect,
mapBy,
match,
map,
oneWay,
sum,
union,
uniqBy,
uniq,
deprecatingAlias,
bool,
collect
} from '@ember/object/computed';
import { assertType } from './lib/assert';
const Person = EmberObject.extend({
firstName: '',
lastName: '',
age: 0,
noArgs: computed<string>(() => 'test'),
fullName: computed<string>('firstName', 'lastName', function() {
return `${this.get('firstName')} ${this.get('lastName')}`;
}),
fullNameReadonly: computed<string>('fullName', function() {
return this.get('fullName');
}).readOnly(),
fullNameWritable: computed<string>('firstName', 'lastName', {
get() {
return this.get('fullName');
},
set(key, value) {
const [first, last] = value.split(' ');
this.set('firstName', first);
this.set('lastName', last);
return value;
}
}),
fullNameGetOnly: computed<string>('fullName', {
get() {
return this.get('fullName');
}
}),
fullNameSetOnly: computed<string>('firstName', 'lastName', {
set(key, value) {
const [first, last] = value.split(' ');
this.set('firstName', first);
this.set('lastName', last);
return value;
}
}),
combinators: computed<string>(function() {
return this.get('firstName');
}).property('firstName')
.meta({ foo: 'bar' })
.volatile()
.readOnly(),
explicitlyDeclared: alias('fullName') as ComputedProperty<string>,
});
const person = Person.create({
firstName: 'Fred',
lastName: 'Smith',
age: 29,
});
assertType<string>(person.firstName);
assertType<number>(person.age);
assertType<ComputedProperty<string>>(person.noArgs);
assertType<ComputedProperty<string>>(person.fullName);
assertType<ComputedProperty<string>>(person.fullNameReadonly);
assertType<ComputedProperty<string>>(person.fullNameWritable);
assertType<ComputedProperty<string>>(person.fullNameGetOnly);
assertType<ComputedProperty<string>>(person.fullNameSetOnly);
assertType<ComputedProperty<string>>(person.combinators);
assertType<ComputedProperty<string>>(person.explicitlyDeclared);
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<string>(person.get('explicitlyDeclared'));
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: computed(() => 'Fred'),
fullName: computed(() => 'Fred Smith')
}).create();
assertType<string>(person4.get('firstName'));
assertType<string>(person4.get('fullName'));
// computed property macros
const objectWithComputedProperties = EmberObject.extend({
alias: alias('foo'),
and: and('foo', 'bar', 'baz', 'qux'),
bool: bool('foo'),
collect: collect('foo', 'bar', 'baz', 'qux'),
deprecatingAlias: deprecatingAlias('foo', {
id: 'hamster.deprecate-banana',
until: '3.0.0'
}),
empty: empty('foo'),
equalNumber: equal('foo', 1),
equalString: equal('foo', 'bar'),
equalObject: equal('foo', {}),
filter: filter('foo', (item) => item === 'bar'),
filterBy1: filterBy('foo', 'bar'),
filterBy2: filterBy('foo', 'bar', false),
gt: gt('foo', 3),
gte: gte('foo', 3),
intersect: intersect('foo', 'bar', 'baz', 'qux'),
lt: lt('foo', 3),
lte: lte('foo', 3),
map: map('foo', (item, index) => item.bar),
mapBy: mapBy('foo', 'bar'),
match: match('foo', /^tom.ter$/),
max: max('foo'),
min: min('foo'),
none: none('foo'),
not: not('foo'),
notEmpty: notEmpty('foo'),
oneWay: oneWay('foo'),
or: or('foo', 'bar', 'baz', 'qux'),
readOnly: readOnly('foo'),
reads: reads('foo'),
setDiff: setDiff('foo', 'bar'),
sort1: sort('foo', 'bar'),
sort2: sort('foo', (itemA, itemB) => {
if (itemA < itemB) {
return -1;
} else if (itemA > itemB) {
return 1;
} else {
return 0;
}
}),
sum: sum('foo'),
union: union('foo', 'bar', 'baz', 'qux'),
uniq: uniq('foo'),
uniqBy: uniqBy('foo', 'bar')
});
const component2 = EmberObject.extend({
isAnimal: or('isDog', 'isCat')
}).create();
assertType<boolean>(component2.get('isAnimal'));

View File

@@ -0,0 +1,198 @@
import Ember from 'ember';
import { assertType } from './lib/assert';
/** Newable tests */
const co1 = new Ember.CoreObject();
// TODO: Enable in TS 3.0 see: https://github.com/typed-ember/ember-cli-typescript/issues/291
// co1.concatenatedProperties; // $ExpectType string[]
co1.isDestroyed; // $ExpectType boolean
co1.isDestroying; // $ExpectType boolean
co1.destroy(); // $ExpectType CoreObject
co1.toString(); // $ExpectType string
/** .create tests */
const co2 = Ember.CoreObject.create();
// TODO: Enable in TS 3.0 see: https://github.com/typed-ember/ember-cli-typescript/issues/291
// co2.concatenatedProperties; // $ExpectType string[]
co2.isDestroyed; // $ExpectType boolean
co2.isDestroying; // $ExpectType boolean
co2.destroy(); // $ExpectType CoreObject
co2.toString(); // $ExpectType string
/** .create tests w/ initial instance data passed in */
const co3 = Ember.CoreObject.create({ foo: '123', bar: 456 });
co3.foo; // $ExpectType string
co3.bar; // $ExpectType number
/** .extend with a zero-argument .create() */
const co4 = Ember.CoreObject.extend({
foo: '123',
bar: 456,
baz(): [string, number] {
return [this.foo, this.bar];
}
}).create();
co4.foo; // $ExpectType string
co4.bar; // $ExpectType number
co4.baz; // $ExpectType () => [string, number]
/** .extend with inconsistent arguments passed into .create() */
const class05 = Ember.CoreObject.extend({
foo: '123' as (string | boolean),
bar: 456,
baz() {
return [this.foo, this.bar];
}
});
const c05 = class05.create({ foo: 99 }); // $ExpectError
const c05b = class05.create({ foo: true });
const c05c = class05.create({ foo: 'abc' });
assertType<string>(c05b.foo); // $ExpectError
assertType<boolean>(c05c.foo); // $ExpectError
/** two .extend arguments with a zero-argument .create() */
const co6 = Ember.CoreObject.extend({
foo: '123',
bar: 456,
baz() {
return [this.foo, this.bar];
},
func1() {
// this includes stuff from CoreObject
this.init; // $ExpectType () => void
// this includes stuff from this extend-arg
this.foo; // $ExpectType string
// this does not include stuff from later extend args
this.bee; // $ExpectError
}
}, {
foo: 99,
bee: 'honey',
func2() {
// this includes stuff from CoreObject
this.init; // $ExpectType () => void
// this includes stuff from this extend-arg
// TODO: switch to "$ExpectType number" in TS 3.0 see: https://github.com/typed-ember/ember-cli-typescript/issues/291
this.foo; // $ExpectType string & number
// this includes stuff from earlier extend-args
this.bar; // $ExpectType number
}
}).create();
// TODO: enable in TS 3.0 see: https://github.com/typed-ember/ember-cli-typescript/issues/291
// assertType<string>(co6.foo); // $ExpectError
assertType<number>(co6.bar); // $ExpectType number
assertType<() => Array<string | number>>(co6.baz); // $ExpectType () => (string | number)[]
/** three .extend arguments with a zero-argument .create() */
const co7 = Ember.CoreObject.extend({
foo: '123',
bar: 456,
baz() {
return [this.foo, this.bar];
},
func1() {
// this includes stuff from CoreObject
this.init; // $ExpectType () => void
// this includes stuff from this extend-arg
this.foo; // $ExpectType string
// this does not include stuff from later extend args
this.bee; // $ExpectError
}
}, {
foo: 99,
bee: 'honey',
func2() {
// this includes stuff from CoreObject
this.init; // $ExpectType () => void
// this includes stuff from this extend-arg
// TODO: switch to "$ExpectType number" in TS 3.0 see: https://github.com/typed-ember/ember-cli-typescript/issues/291
this.foo; // $ExpectType string & number
// this includes stuff from earlier extend-args
this.bar; // $ExpectType number
}
}, {
foo: '99',
money: 'in the banana stand',
func3() {
// this includes stuff from CoreObject
this.init; // $ExpectType () => void
// this includes stuff from this extend-arg
this.money; // $ExpectType string
// this includes stuff from earlier extend-args
this.bee; // $ExpectType string
this.bar; // $ExpectType number
}
}).create();
// TODO: enable in TS 3.0 see: https://github.com/typed-ember/ember-cli-typescript/issues/291
// assertType<number>(co7.foo); // $ExpectError
assertType<number>(co7.bar); // $ExpectType number
assertType<string>(co7.money); // $ExpectType string
assertType<() => Array<string | number>>(co7.baz); // $ExpectType () => (string | number)[]
/** four .extend arguments with a zero-argument .create() */
const co8 = Ember.CoreObject.extend({
foo: '123',
bar: 456,
baz() {
return [this.foo, this.bar];
},
func1() {
// this includes stuff from CoreObject
this.init; // $ExpectType () => void
// this includes stuff from this extend-arg
this.foo; // $ExpectType string
// this does not include stuff from later extend args
this.bee; // $ExpectError
}
}, {
foo: 99,
bee: 'honey',
func2() {
// this includes stuff from CoreObject
this.init; // $ExpectType () => void
// this includes stuff from this extend-arg
// TODO: switch to "$ExpectType number" in TS 3.0 see: https://github.com/typed-ember/ember-cli-typescript/issues/291
this.foo; // $ExpectType string & number
// this includes stuff from earlier extend-args
this.bar; // $ExpectType number
// this does not include stuff from later extend args
this.money; // $ExpectError
}
}, {
foo: '99',
money: 'in the banana stand',
func3() {
// this includes stuff from CoreObject
this.init; // $ExpectType () => void
// this includes stuff from this extend-arg
this.money; // $ExpectType string
// this includes stuff from earlier extend-args
this.bee; // $ExpectType string
this.bar; // $ExpectType number
// this does not include stuff from later extend args
this.neighborhood; // $ExpectError
}
}, {
foo: '99',
neighborhood: 'sudden valley',
func4() {
// this includes stuff from CoreObject
this.init; // $ExpectType () => void
// this includes stuff from this extend-arg
this.neighborhood; // $ExpectType string
// this includes stuff from earlier extend-args
this.bee; // $ExpectType string
this.bar; // $ExpectType number
this.money; // $ExpectType string
}
}).create();
// TODO: enable in TS 3.0 see: https://github.com/typed-ember/ember-cli-typescript/issues/291
// assertType<number>(co8.foo); // $ExpectError
assertType<number>(co8.bar); // $ExpectType number
assertType<string>(co8.money); // $ExpectType string
assertType<() => Array<string | number>>(co8.baz); // $ExpectType () => (string | number)[]

View File

@@ -0,0 +1,9 @@
import { assertType } from './lib/assert';
import Ember from 'ember';
import { PersonWithNumberName, Person } from './create';
Person.create({ firstName: 99 }); // $ExpectError
Person.create({}, { firstName: 99 }); // $ExpectError
Person.create({}, {}, { firstName: 99 }); // $ExpectError
const p4 = new PersonWithNumberName();

View File

@@ -0,0 +1,54 @@
import { assertType } from './lib/assert';
import EmberObject, { computed } from '@ember/object';
import ComputedProperty from '@ember/object/computed';
/**
* Zero-argument case
*/
const o = EmberObject.create();
// create returns an object
assertType<object>(o);
// object returned by create type-checks as an instance of Ember.Object
assertType<boolean>(o.isDestroyed); // from instance
assertType<boolean>(o.isDestroying); // from instance
assertType<(key: keyof EmberObject) => any>(o.get); // from prototype
/**
* One-argument case
*/
const o1 = EmberObject.create({x: 9, y: 'hello', z: false});
assertType<number>(o1.x);
assertType<string>(o1.y);
o1.y; // $ExpectType string
o1.z; // $ExpectType boolean
const obj = EmberObject.create({ a: 1 }, { b: 2 }, { c: 3 });
assertType<number>(obj.b);
assertType<number>(obj.a);
assertType<number>(obj.c);
export class Person extends EmberObject {
fullName = computed('firstName', 'lastName', function() {
return [this.firstName + this.lastName].join(' ');
});
firstName: string;
lastName: string;
age: number;
}
const p = new Person();
assertType<string>(p.firstName);
assertType<ComputedProperty<string>>(p.fullName);
assertType<string>(p.get('fullName'));
const p2 = Person.create({ firstName: 'string' });
const p2b = Person.create({}, { firstName: 'string' });
const p2c = Person.create({}, {}, { firstName: 'string' });
export class PersonWithNumberName extends Person.extend({
fullName: 6
}) {}
const p4 = new PersonWithNumberName();
assertType<string>(p4.firstName);
assertType<number>(p4.fullName);

View File

@@ -0,0 +1,20 @@
import { assertType } from './lib/assert';
import EmberObject from '@ember/object';
const ExtendClass = EmberObject.extend({
foo: 'hello'
});
class ES6Class extends EmberObject {
bar: string;
}
const testObject = null;
if (ExtendClass.detectInstance(testObject)) {
assertType<string>(testObject.foo);
}
if (ES6Class.detectInstance(testObject)) {
assertType<string>(testObject.bar);
}

View File

@@ -0,0 +1,20 @@
import { assertType } from './lib/assert';
import EmberObject from '@ember/object';
const ExtendClass = EmberObject.extend({
foo: 'hello'
});
class ES6Class extends EmberObject {
bar: string;
}
const TestClass = EmberObject;
if (ExtendClass.detect(TestClass)) {
assertType<string>(TestClass.create().foo);
}
if (ES6Class.detect(TestClass)) {
assertType<string>(TestClass.create().bar);
}

View File

@@ -0,0 +1,61 @@
import EmberObject, { observer } from '@ember/object';
import { sendEvent, addListener, removeListener } from '@ember/object/events';
import Evented, { on } from '@ember/object/evented';
function testOn() {
const Job = EmberObject.extend({
logCompleted: on('completed', () => {
console.log('Job completed!');
})
});
const job = Job.create();
sendEvent(job, 'completed'); // Logs 'Job completed!'
}
function testEvented() {
const Person = EmberObject.extend(Evented, {
greet() {
this.trigger('greet');
}
});
const person = Person.create();
person.on('greet', () => {
console.log('Our person has greeted');
});
person.on('greet', () => {
console.log('Our person has greeted');
}).one('greet', () => {
console.log('Offer one-time special');
}).off('event', {}, () => {});
person.greet();
}
function testObserver() {
EmberObject.extend({
// TODO: enable after https://github.com/typed-ember/ember-cli-typescript/issues/290
// valueObserver: observer('value', () => {
// // Executes whenever the "value" property changes
// })
});
}
function testListener() {
EmberObject.extend({
init() {
addListener(this, 'willDestroy', this, 'willDestroyListener');
addListener(this, 'willDestroy', this, 'willDestroyListener', true);
addListener(this, 'willDestroy', this, this.willDestroyListener);
addListener(this, 'willDestroy', this, this.willDestroyListener, true);
removeListener(this, 'willDestroy', this, 'willDestroyListener');
removeListener(this, 'willDestroy', this, this.willDestroyListener);
},
willDestroyListener() {
}
});
}

View File

@@ -0,0 +1,61 @@
import EmberObject from '@ember/object';
import { assertType } from './lib/assert';
const Person = EmberObject.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 EmberObject {
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 EmberObject {
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);

View File

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

View File

@@ -0,0 +1,75 @@
import EmberObject, { computed } from "@ember/object";
const LifetimeHooks = EmberObject.extend({
resource: null as {} | null,
init() {
this._super();
this.resource = {};
},
willDestroy() {
delete this.resource;
this._super();
}
});
class MyObject30 extends EmberObject {
constructor() {
super();
}
}
class MyObject31 extends EmberObject {
constructor(properties: object) {
super(properties);
}
}
class Foo extends EmberObject {
a = computed({
get() { return ''; },
set(key: string, newVal: string) { return ''; }
});
b = 5;
baz() {
const y = this.b; // $ExpectType number
const z = this.a; // $ExpectType ComputedProperty<string, string>
this.b = 10;
this.get('b').toFixed(4); // $ExpectType string
this.set('a', 'abc').split(','); // $ExpectType string[]
this.set('b', 10).toFixed(4); // $ExpectType string
this.setProperties({ b: 11 });
// this.setProperties({ b: '11' }); // $ExpectError
this.setProperties({
a: 'def',
b: 11
});
}
}
// TODO: enable after TS 3.0 https://github.com/typed-ember/ember-cli-typescript/issues/291
// class Foo extends EmberObject.extend({
// a: computed({
// get() { return ''; },
// set(key: string, newVal: string) { return ''; }
// })
// }) {
// b = 5;
// baz() {
// const y = this.b; // $ExpectType number
// const z = this.a; // $ExpectType ComputedProperty<string, string>
// this.b = 10;
// this.get('b').toFixed(4); // $ExpectType string
// this.set('a', 'abc').split(','); // $ExpectType string[]
// this.set('b', 10).toFixed(4); // $ExpectType string
// this.setProperties({ b: 11 });
// // this.setProperties({ b: '11' }); // $ExpectError
// this.setProperties({
// a: 'def',
// b: 11
// });
// }
// }

View File

@@ -0,0 +1,114 @@
import { assertType } from './lib/assert';
import EmberObject, { computed, getWithDefault, getProperties, get, setProperties, set } from '@ember/object';
import { removeObserver, addObserver } from '@ember/object/observers';
class MyComponent extends EmberObject {
foo = 'bar';
init() {
this._super.apply(this, arguments);
this.addObserver('foo', this, 'fooDidChange');
this.addObserver('foo', this, this.fooDidChange);
addObserver(this, 'foo', this, 'fooDidChange');
addObserver(this, 'foo', this, this.fooDidChange);
this.removeObserver('foo', this, 'fooDidChange');
this.removeObserver('foo', this, this.fooDidChange);
removeObserver(this, 'foo', this, 'fooDidChange');
removeObserver(this, 'foo', this, this.fooDidChange);
const lambda = () => {
this.fooDidChange(this, 'foo');
};
this.addObserver('foo', lambda);
this.removeObserver('foo', lambda);
addObserver(this, 'foo', lambda);
removeObserver(this, 'foo', lambda);
}
fooDidChange(sender: this, key: keyof this) {
// your code
}
}
const myComponent = MyComponent.create();
myComponent.addObserver('foo', null, () => {});
myComponent.set('foo', 'baz');
const person = EmberObject.create({
name: 'Fred',
age: 29,
capitalized: computed<string>(function() {
return this.get('name').toUpperCase();
})
});
const pojo = { name: 'Fred', age: 29 };
function testGet() {
assertType<string>(get(person, 'name'));
assertType<number>(get(person, 'age'));
assertType<string>(get(person, 'capitalized'));
assertType<string>(person.get('name'));
assertType<number>(person.get('age'));
assertType<string>(person.get('capitalized'));
assertType<string>(get(pojo, 'name'));
}
function testGetProperties() {
assertType<{ name: string }>(getProperties(person, 'name'));
assertType<{ name: string, age: number }>(getProperties(person, 'name', 'age'));
assertType<{ name: string, age: number }>(getProperties(person, [ 'name', 'age' ]));
assertType<{ name: string, age: number, capitalized: string }>(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 }>(getProperties(pojo, 'name', 'age'));
}
function testGetWithDefault() {
assertType<string>(getWithDefault(person, 'name', 'Joe'));
assertType<number>(getWithDefault(person, 'age', 20));
assertType<string>(getWithDefault(person, 'capitalized', 'JOE'));
assertType<string>(person.getWithDefault('name', 'Joe'));
assertType<number>(person.getWithDefault('age', 20));
assertType<string>(person.getWithDefault('capitalized', 'JOE'));
assertType<string>(getWithDefault(pojo, 'name', 'JOE'));
}
function testSet() {
assertType<string>(set(person, 'name', 'Joe'));
assertType<number>(set(person, 'age', 35));
assertType<string>(set(person, 'capitalized', 'JOE'));
assertType<string>(person.set('name', 'Joe'));
assertType<number>(person.set('age', 35));
assertType<string>(person.set('capitalized', 'JOE'));
assertType<string>(set(pojo, 'name', 'Joe'));
}
function testSetProperties() {
assertType<{ name: string }>(setProperties(person, { name: 'Joe' }));
assertType<{ name: string, age: number }>(setProperties(person, { name: 'Joe', age: 35 }));
assertType<{ name: string, capitalized: string }>(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 }>(setProperties(pojo, { name: 'Joe', age: 35 }));
}
function testDynamic() {
const obj: any = {};
const dynamicKey: string = 'dummy'; // tslint:disable-line:no-inferrable-types
assertType<any>(get(obj, 'dummy'));
assertType<any>(get(obj, dynamicKey));
assertType<string>(getWithDefault(obj, 'dummy', 'default'));
assertType<string>(getWithDefault(obj, dynamicKey, 'default'));
assertType<{ dummy: any }>(getProperties(obj, 'dummy'));
assertType<{ dummy: any }>(getProperties(obj, [ 'dummy' ]));
assertType<object>(getProperties(obj, dynamicKey));
assertType<object>(getProperties(obj, [ dynamicKey ]));
assertType<string>(set(obj, 'dummy', 'value'));
assertType<string>(set(obj, dynamicKey, 'value'));
assertType<{ dummy: string }>(setProperties(obj, { dummy: 'value '}));
assertType<object>(setProperties(obj, { [dynamicKey]: 'value' }));
}

View File

@@ -0,0 +1,72 @@
import { assertType } from "./lib/assert";
import EmberObject from "@ember/object";
import Mixin from "@ember/object/mixin";
type Person = typeof Person.prototype;
const Person = EmberObject.extend({
name: '',
sayHello() {
alert(`Hello. My name is ${this.get('name')}`);
}
});
assertType<Person>(Person.reopen());
assertType<string>(Person.create().name);
// tslint:disable-next-line no-void-expression
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);
// tslint:disable-next-line no-void-expression
assertType<void>(Person2.create().sayHello());
assertType<string>(Person2.species);
const tom = Person2.create({
name: 'Tom Dale'
});
const badTom = Person2.create({ name: 99 }); // $ExpectError
const 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: Mixin<AutoResizeMixin>;
const ResizableTextArea = EmberObject.reopen(AutoResizeMixin, {
scaling: 1.0
});
const text = ResizableTextArea.create();
// TODO fix upstream
// assertType<boolean>(text.resizable);
assertType<number>(text.scaling);
const Reopened = EmberObject.reopenClass({ a: 1 }, { b: 2 }, { c: 3 });
assertType<number>(Reopened.a);
assertType<number>(Reopened.b);
assertType<number>(Reopened.c);

View File

@@ -0,0 +1,51 @@
{
"compilerOptions": {
"module": "commonjs",
"target": "es5",
"lib": [
"es6",
"dom"
],
"noImplicitAny": true,
"noImplicitThis": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"baseUrl": "../",
"typeRoots": [
"../"
],
"paths": {
"@ember/object": ["ember__object"],
"@ember/object/*": ["ember__object/*"]
},
"types": [],
"noEmit": true,
"forceConsistentCasingInFileNames": true
},
"files": [
"computed.d.ts",
"core.d.ts",
"evented.d.ts",
"events.d.ts",
"index.d.ts",
"internals.d.ts",
"mixin.d.ts",
"observable.d.ts",
"observers.d.ts",
"promise-proxy-mixin.d.ts",
"proxy.d.ts",
"test/lib/assert.ts",
"test/access-modifier.ts",
"test/core.ts",
"test/computed.ts",
"test/create.ts",
"test/create-negative.ts",
"test/detect.ts",
"test/detect-instance.ts",
"test/event.ts",
"test/extend.ts",
"test/object.ts",
"test/observable.ts",
"test/reopen.ts"
]
}

View File

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