mirror of
https://github.com/gosticks/DefinitelyTyped.git
synced 2025-10-16 12:05:41 +00:00
Ember Data fixes (#34245)
* ember-data: fix bugs and improve type safety. * ember-data: handle `each(Transformed)?Attribute`. * ember-data: fix a lint error.
This commit is contained in:
parent
7e92d8b69d
commit
a819975d58
98
types/ember-data/index.d.ts
vendored
98
types/ember-data/index.d.ts
vendored
@ -16,8 +16,14 @@ import ModelRegistry from 'ember-data/types/registries/model';
|
||||
import SerializerRegistry from 'ember-data/types/registries/serializer';
|
||||
import AdapterRegistry from 'ember-data/types/registries/adapter';
|
||||
|
||||
type AttributesFor<Model> = keyof Model; // TODO: filter to attr properties only (TS 2.8)
|
||||
type RelationshipsFor<Model> = keyof Model; // TODO: filter to hasMany/belongsTo properties only (TS 2.8)
|
||||
/**
|
||||
The keys from the actual Model class, removing all the keys which come from
|
||||
the base class.
|
||||
*/
|
||||
type ModelKeys<Model extends DS.Model> = Exclude<keyof Model, keyof DS.Model>;
|
||||
|
||||
type AttributesFor<Model extends DS.Model> = ModelKeys<Model>; // TODO: filter to attr properties only (TS 2.8)
|
||||
type RelationshipsFor<Model extends DS.Model> = ModelKeys<Model>; // TODO: filter to hasMany/belongsTo properties only (TS 2.8)
|
||||
|
||||
export interface ChangedAttributes {
|
||||
[key: string]: [any, any] | undefined;
|
||||
@ -49,9 +55,9 @@ export namespace DS {
|
||||
*/
|
||||
function errorsArrayToHash(errors: any[]): {};
|
||||
|
||||
interface RelationshipOptions<Model> {
|
||||
interface RelationshipOptions<M extends Model> {
|
||||
async?: boolean;
|
||||
inverse?: RelationshipsFor<Model> | null;
|
||||
inverse?: RelationshipsFor<M> | null;
|
||||
polymorphic?: boolean;
|
||||
}
|
||||
|
||||
@ -457,12 +463,12 @@ export namespace DS {
|
||||
* Create a JSON representation of the record, using the serialization
|
||||
* strategy of the store's adapter.
|
||||
*/
|
||||
serialize(options?: { includeId?: boolean }): {};
|
||||
serialize(options?: { includeId?: boolean }): object;
|
||||
/**
|
||||
* Use [DS.JSONSerializer](DS.JSONSerializer.html) to
|
||||
* get the JSON representation of a record.
|
||||
*/
|
||||
toJSON(options: {}): {};
|
||||
toJSON(options?: { includeId?: boolean }): object;
|
||||
/**
|
||||
* Fired when the record is ready to be interacted with,
|
||||
* that is either loaded from the server or created locally.
|
||||
@ -502,15 +508,15 @@ export namespace DS {
|
||||
* method if you want to allow the user to still `rollbackAttributes()`
|
||||
* after a delete was made.
|
||||
*/
|
||||
deleteRecord(): any;
|
||||
deleteRecord(): void;
|
||||
/**
|
||||
* Same as `deleteRecord`, but saves the record immediately.
|
||||
*/
|
||||
destroyRecord(options?: {}): RSVP.Promise<any>;
|
||||
destroyRecord(options?: { adapterOptions?: object }): RSVP.Promise<this>;
|
||||
/**
|
||||
* Unloads the record from the store. This will cause the record to be destroyed and freed up for garbage collection.
|
||||
*/
|
||||
unloadRecord(): any;
|
||||
unloadRecord(): void;
|
||||
/**
|
||||
* Returns an object, whose keys are changed properties, and value is
|
||||
* an [oldProp, newProp] array.
|
||||
@ -520,16 +526,16 @@ export namespace DS {
|
||||
* If the model `hasDirtyAttributes` this function will discard any unsaved
|
||||
* changes. If the model `isNew` it will be removed from the store.
|
||||
*/
|
||||
rollbackAttributes(): any;
|
||||
rollbackAttributes(): void;
|
||||
/**
|
||||
* Save the record and persist any changes to the record to an
|
||||
* external source via the adapter.
|
||||
*/
|
||||
save(options?: {}): RSVP.Promise<this>;
|
||||
save(options?: { adapterOptions?: object }): RSVP.Promise<this>;
|
||||
/**
|
||||
* Reload the record from the adapter.
|
||||
*/
|
||||
reload(): RSVP.Promise<any>;
|
||||
reload(options?: { adapterOptions?: object }): RSVP.Promise<this>;
|
||||
/**
|
||||
* Get the reference for the specified belongsTo relationship.
|
||||
*/
|
||||
@ -547,7 +553,7 @@ export namespace DS {
|
||||
this: T,
|
||||
callback: (name: string, details: RelationshipMeta<T>) => void,
|
||||
binding?: any
|
||||
): any;
|
||||
): void;
|
||||
/**
|
||||
* Represents the model's class name as a string. This can be used to look up the model's class name through
|
||||
* `DS.Store`'s modelFor method.
|
||||
@ -605,14 +611,14 @@ export namespace DS {
|
||||
static eachRelationship<M extends Model = Model>(
|
||||
callback: (name: string, details: RelationshipMeta<M>) => void,
|
||||
binding?: any
|
||||
): any;
|
||||
): void;
|
||||
/**
|
||||
* Given a callback, iterates over each of the types related to a model,
|
||||
* invoking the callback with the related type's class. Each type will be
|
||||
* returned just once, regardless of how many different relationships it has
|
||||
* with a model.
|
||||
*/
|
||||
static eachRelatedType(callback: Function, binding: any): any;
|
||||
static eachRelatedType(callback: (name: string) => void, binding?: any): void;
|
||||
/**
|
||||
* A map whose keys are the attributes of the model (properties
|
||||
* described by DS.attr) and whose values are the meta object for the
|
||||
@ -630,26 +636,27 @@ export namespace DS {
|
||||
* Iterates through the attributes of the model, calling the passed function on each
|
||||
* attribute.
|
||||
*/
|
||||
static eachAttribute(callback: Function, binding: {}): any;
|
||||
static eachAttribute<Class extends typeof Model, M extends InstanceType<Class>>(
|
||||
this: Class,
|
||||
callback: (
|
||||
name: ModelKeys<M>,
|
||||
meta: AttributeMeta<M>
|
||||
) => void,
|
||||
binding?: any
|
||||
): void;
|
||||
/**
|
||||
* Iterates through the transformedAttributes of the model, calling
|
||||
* the passed function on each attribute. Note the callback will not be
|
||||
* called for any attributes that do not have an transformation type.
|
||||
*/
|
||||
static eachTransformedAttribute(callback: Function, binding: {}): any;
|
||||
/**
|
||||
* Discards any unsaved changes to the given attribute. This feature is not enabled by default. You must enable `ds-rollback-attribute` and be running a canary build.
|
||||
*/
|
||||
rollbackAttribute(): any;
|
||||
/**
|
||||
* This Ember.js hook allows an object to be notified when a property
|
||||
* is defined.
|
||||
*/
|
||||
didDefineProperty(
|
||||
proto: {},
|
||||
key: string,
|
||||
value: Ember.ComputedProperty<any>
|
||||
): any;
|
||||
static eachTransformedAttribute<Class extends typeof Model>(
|
||||
this: Class,
|
||||
callback: (
|
||||
name: ModelKeys<InstanceType<Class>>,
|
||||
type: keyof TransformRegistry
|
||||
) => void,
|
||||
binding?: any
|
||||
): void;
|
||||
}
|
||||
/**
|
||||
* ### State
|
||||
@ -700,7 +707,7 @@ export namespace DS {
|
||||
* Used to get the latest version of all of the records in this array
|
||||
* from the adapter.
|
||||
*/
|
||||
update(): any;
|
||||
update(): PromiseArray<T>;
|
||||
/**
|
||||
* Saves all of the records in the `RecordArray`.
|
||||
*/
|
||||
@ -782,7 +789,7 @@ export namespace DS {
|
||||
/**
|
||||
* `ids()` returns an array of the record ids in this relationship.
|
||||
*/
|
||||
ids(): any[];
|
||||
ids(): string[];
|
||||
/**
|
||||
* The meta data for the has-many relationship.
|
||||
*/
|
||||
@ -948,7 +955,7 @@ export namespace DS {
|
||||
/**
|
||||
* Get snapshots of the underlying record array
|
||||
*/
|
||||
snapshots(): any[];
|
||||
snapshots(): Snapshot[];
|
||||
}
|
||||
class Snapshot<K extends keyof ModelRegistry = any> {
|
||||
/**
|
||||
@ -994,14 +1001,19 @@ export namespace DS {
|
||||
belongsTo<L extends RelationshipsFor<ModelRegistry[K]>>(
|
||||
keyName: L,
|
||||
options?: {}
|
||||
): Snapshot<K>['record'][L] | string | null | undefined;
|
||||
): Snapshot | null | undefined;
|
||||
belongsTo<L extends RelationshipsFor<ModelRegistry[K]>>(
|
||||
keyName: L,
|
||||
options: { id: true }
|
||||
): string | null | undefined;
|
||||
|
||||
/**
|
||||
* Returns the current value of a hasMany relationship.
|
||||
*/
|
||||
hasMany<L extends RelationshipsFor<ModelRegistry[K]>>(
|
||||
keyName: L,
|
||||
options?: { ids: false }
|
||||
): Array<Snapshot<K>['record'][L]> | undefined;
|
||||
): Snapshot[] | undefined;
|
||||
hasMany<L extends RelationshipsFor<ModelRegistry[K]>>(
|
||||
keyName: L,
|
||||
options: { ids: true }
|
||||
@ -1011,21 +1023,21 @@ export namespace DS {
|
||||
* function on each attribute.
|
||||
*/
|
||||
eachAttribute<M extends ModelRegistry[K]>(
|
||||
callback: (key: keyof M, meta: AttributeMeta<M>) => void,
|
||||
callback: (key: ModelKeys<M>, meta: AttributeMeta<M>) => void,
|
||||
binding?: {}
|
||||
): any;
|
||||
): void;
|
||||
/**
|
||||
* Iterates through all the relationships of the model, calling the passed
|
||||
* function on each relationship.
|
||||
*/
|
||||
eachRelationship<M extends ModelRegistry[K]>(
|
||||
callback: (key: keyof M, meta: RelationshipMeta<M>) => void,
|
||||
callback: (key: ModelKeys<M>, meta: RelationshipMeta<M>) => void,
|
||||
binding?: {}
|
||||
): any;
|
||||
): void;
|
||||
/**
|
||||
* Serializes the snapshot using the serializer for the model.
|
||||
*/
|
||||
serialize(options: {}): {};
|
||||
serialize<O extends object>(options: O): object;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1095,7 +1107,8 @@ export namespace DS {
|
||||
*/
|
||||
query<K extends keyof ModelRegistry>(
|
||||
modelName: K,
|
||||
query: any
|
||||
query: object,
|
||||
options?: { adapterOptions?: object }
|
||||
): AdapterPopulatedRecordArray<ModelRegistry[K]> &
|
||||
PromiseArray<ModelRegistry[K]>;
|
||||
/**
|
||||
@ -1105,7 +1118,8 @@ export namespace DS {
|
||||
*/
|
||||
queryRecord<K extends keyof ModelRegistry>(
|
||||
modelName: K,
|
||||
query: any
|
||||
query: object,
|
||||
options?: { adapterOptions?: object }
|
||||
): RSVP.Promise<ModelRegistry[K]>;
|
||||
/**
|
||||
* `findAll` asks the adapter's `findAll` method to find the records for the
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import Ember from 'ember';
|
||||
import DS, { ChangedAttributes } from 'ember-data';
|
||||
import { assertType } from "./lib/assert";
|
||||
import RSVP from 'rsvp';
|
||||
|
||||
const Person = DS.Model.extend({
|
||||
firstName: DS.attr(),
|
||||
@ -33,5 +34,26 @@ user.serialize();
|
||||
user.serialize({ includeId: true });
|
||||
user.serialize({ includeId: true });
|
||||
|
||||
const attributes = user.changedAttributes();
|
||||
assertType<ChangedAttributes>(attributes);
|
||||
const attributes: ChangedAttributes = user.changedAttributes();
|
||||
|
||||
user.rollbackAttributes(); // $ExpectType void
|
||||
|
||||
let destroyResult: RSVP.Promise<typeof user>;
|
||||
destroyResult = user.destroyRecord();
|
||||
destroyResult = user.destroyRecord({});
|
||||
destroyResult = user.destroyRecord({ adapterOptions: {}});
|
||||
destroyResult = user.destroyRecord({ adapterOptions: { waffles: 'are yummy' }});
|
||||
|
||||
user.deleteRecord(); // $ExpectType void
|
||||
|
||||
user.unloadRecord(); // $ExpectType void
|
||||
|
||||
let jsonified: object;
|
||||
jsonified = user.toJSON();
|
||||
jsonified = user.toJSON({ includeId: true });
|
||||
|
||||
let reloaded: RSVP.Promise<typeof user>;
|
||||
reloaded = user.reload();
|
||||
reloaded = user.reload({});
|
||||
reloaded = user.reload({ adapterOptions: {} });
|
||||
reloaded = user.reload({ adapterOptions: { fastAsCanBe: 'yessirree' } });
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
import Ember from 'ember';
|
||||
import DS from 'ember-data';
|
||||
import TransformRegistry from 'ember-data/types/registries/transform';
|
||||
import { assertType } from './lib/assert';
|
||||
|
||||
declare const store: DS.Store;
|
||||
|
||||
@ -8,24 +10,65 @@ const Person = DS.Model.extend({
|
||||
parent: DS.belongsTo('folder', { inverse: 'children' })
|
||||
});
|
||||
|
||||
// $ExpectType void
|
||||
Person.eachAttribute(() => {});
|
||||
// $ExpectType void
|
||||
Person.eachAttribute(() => {}, {});
|
||||
// $ExpectType void
|
||||
Person.eachAttribute((name, meta) => {
|
||||
assertType<'children' | 'parent'>(name);
|
||||
assertType<{
|
||||
type: keyof TransformRegistry;
|
||||
options: object;
|
||||
name: 'children' | 'parent';
|
||||
parentType: DS.Model;
|
||||
isAttribute: true;
|
||||
}>(meta);
|
||||
});
|
||||
|
||||
// $ExpectType void
|
||||
Person.eachTransformedAttribute(() => {});
|
||||
// $ExpectType void
|
||||
Person.eachTransformedAttribute(() => {}, {});
|
||||
// $ExpectType void
|
||||
Person.eachTransformedAttribute((name, type) => {
|
||||
assertType<'children' | 'parent'>(name);
|
||||
let t: keyof TransformRegistry = type;
|
||||
});
|
||||
|
||||
const Polymorphic = DS.Model.extend({
|
||||
paymentMethods: DS.hasMany('payment-method', { polymorphic: true })
|
||||
});
|
||||
|
||||
// $ExpectType void
|
||||
Polymorphic.eachRelationship(() => '');
|
||||
// $ExpectType void
|
||||
Polymorphic.eachRelationship(() => '', {});
|
||||
// $ExpectType void
|
||||
Polymorphic.eachRelationship((n, meta) => {
|
||||
let s: string = n;
|
||||
let m: 'belongsTo' | 'hasMany' = meta.kind;
|
||||
});
|
||||
let p = Polymorphic.create();
|
||||
// $ExpectType void
|
||||
p.eachRelationship(() => '');
|
||||
// $ExpectType void
|
||||
p.eachRelationship(() => '', {});
|
||||
// $ExpectType void
|
||||
p.eachRelationship((n, meta) => {
|
||||
let s: string = n;
|
||||
let m: 'belongsTo' | 'hasMany' = meta.kind;
|
||||
});
|
||||
|
||||
// $ExpectType void
|
||||
Polymorphic.eachRelatedType(() => '');
|
||||
// $ExpectType void
|
||||
Polymorphic.eachRelatedType(() => '', {});
|
||||
// $ExpectType void
|
||||
Polymorphic.eachRelatedType((name) => {
|
||||
let s: string = name;
|
||||
});
|
||||
|
||||
export class Comment extends DS.Model {
|
||||
author = DS.attr('string');
|
||||
}
|
||||
|
||||
@ -1,6 +1,10 @@
|
||||
import Ember from 'ember';
|
||||
import DS from 'ember-data';
|
||||
|
||||
interface Dict<T> {
|
||||
[key: string]: T | null | undefined;
|
||||
}
|
||||
|
||||
const JsonApi = DS.JSONAPISerializer.extend({});
|
||||
|
||||
const Customized = DS.JSONAPISerializer.extend({
|
||||
@ -74,14 +78,16 @@ const SerializerUsingSnapshots = DS.RESTSerializer.extend({
|
||||
|
||||
DS.Serializer.extend({
|
||||
serialize(snapshot: DS.Snapshot<'message-for-serializer'>, options: {}) {
|
||||
let json: any = {
|
||||
let json: Dict<any> = {
|
||||
id: snapshot.id
|
||||
};
|
||||
|
||||
// $ExpectType void
|
||||
snapshot.eachAttribute((key, attribute) => {
|
||||
json[key] = snapshot.attr(key);
|
||||
});
|
||||
|
||||
// $ExpectType void
|
||||
snapshot.eachRelationship((key, relationship) => {
|
||||
if (relationship.kind === 'belongsTo') {
|
||||
json[key] = snapshot.belongsTo(key, { id: true });
|
||||
|
||||
@ -24,6 +24,7 @@ let post = store.createRecord('post', {
|
||||
});
|
||||
|
||||
post.save(); // => POST to '/posts'
|
||||
post.save({ adapterOptions: { makeItSo: 'number one ' } });
|
||||
post.save().then(saved => {
|
||||
assertType<Post>(saved);
|
||||
});
|
||||
|
||||
Loading…
Reference in New Issue
Block a user