mirror of
https://github.com/zhigang1992/DefinitelyTyped.git
synced 2026-05-28 08:17:54 +08:00
[ember] Refactor some private types into ghost modules (#28735)
* [ember] refactor some private types into ghost modules * [ember] additional tests for low-level CP and Observable types * [ember] fix: add tests/core-object
This commit is contained in:
committed by
Ryan Cavanaugh
parent
856deff048
commit
992b5b5f11
5
types/ember/-private-types/mixin.d.ts
vendored
Normal file
5
types/ember/-private-types/mixin.d.ts
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
import Ember from 'ember';
|
||||
/**
|
||||
* Ember.Object.extend(...) accepts any number of mixins or literals.
|
||||
*/
|
||||
declare type MixinOrLiteral<T, Base> = Ember.Mixin<T, Base> | T;
|
||||
28
types/ember/-private-types/object.d.ts
vendored
Normal file
28
types/ember/-private-types/object.d.ts
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Used to infer the type of ember classes of type `T`.
|
||||
*
|
||||
* Generally you would use `EmberClass.create()` instead of `new EmberClass()`.
|
||||
*
|
||||
* The single-arg constructor is required by the typescript compiler.
|
||||
* The multi-arg constructor is included for better ergonomics.
|
||||
*
|
||||
* Implementation is carefully chosen for the reasons described in
|
||||
* https://github.com/typed-ember/ember-typings/pull/29
|
||||
*/
|
||||
export type EmberClassConstructor<T> = (new (properties?: object) => T) & (new (...args: any[]) => T);
|
||||
|
||||
/**
|
||||
* Check that any arguments to `create()` match the type's properties.
|
||||
*
|
||||
* Accept any additional properties and add merge them into the instance.
|
||||
*/
|
||||
export type EmberInstanceArguments<T> = Partial<T> & {
|
||||
[key: string]: any;
|
||||
};
|
||||
|
||||
/**
|
||||
* Accept any additional properties and add merge them into the prototype.
|
||||
*/
|
||||
export interface EmberClassArguments {
|
||||
[key: string]: any;
|
||||
}
|
||||
34
types/ember/-private-types/object/computed.d.ts
vendored
Normal file
34
types/ember/-private-types/object/computed.d.ts
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
import ComputedProperty from '@ember/object/computed';
|
||||
/**
|
||||
* Deconstructs computed properties into the types which would be returned by `.get()`.
|
||||
*/
|
||||
export type UnwrapComputedPropertyGetter<T> =
|
||||
T extends ComputedProperty<infer U, any> ? U :
|
||||
T;
|
||||
export type UnwrapComputedPropertyGetters<T> = {
|
||||
[P in keyof T]: UnwrapComputedPropertyGetter<T[P]>;
|
||||
};
|
||||
|
||||
export type UnwrapComputedPropertySetter<T> =
|
||||
T extends ComputedProperty<any, infer V> ? V :
|
||||
T;
|
||||
export type UnwrapComputedPropertySetters<T> = {
|
||||
[P in keyof T]: UnwrapComputedPropertySetter<T[P]>;
|
||||
};
|
||||
|
||||
export type ComputedPropertyGetterFunction<T> = (this: any, key: string) => T;
|
||||
export type ComputedPropertySetterFunction<T> = (this: any, key: string, newVal: T, oldVal: T) => T;
|
||||
|
||||
export interface ComputedPropertyGetterObj<T> {
|
||||
get(this: any, key: string): T;
|
||||
}
|
||||
|
||||
export interface ComputedPropertySetterObj<T> {
|
||||
set(this: any, key: string, value: T): T;
|
||||
}
|
||||
export type ComputedPropertyObj<T> = ComputedPropertyGetterObj<T> | ComputedPropertySetterObj<T> | (ComputedPropertyGetterObj<T> & ComputedPropertySetterObj<T>);
|
||||
|
||||
export type ComputedPropertyGetter<T> = ComputedPropertyGetterFunction<T> | ComputedPropertyGetterObj<T>;
|
||||
export type ComputedPropertySetter<T> = ComputedPropertySetterFunction<T> | ComputedPropertySetterObj<T>;
|
||||
|
||||
export type ComputedPropertyCallback<T> = ComputedPropertyGetterFunction<T> | ComputedPropertyObj<T>;
|
||||
14
types/ember/-private-types/utils.d.ts
vendored
Normal file
14
types/ember/-private-types/utils.d.ts
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* Map type `T` to a plain object hash with the identity mapping.
|
||||
*
|
||||
* Discards any additional object identity like the ability to `new()` up the class.
|
||||
* The `new()` capability is added back later by merging `EmberClassConstructor<T>`
|
||||
*
|
||||
* Implementation is carefully chosen for the reasons described in
|
||||
* https://github.com/typed-ember/ember-typings/pull/29
|
||||
*/
|
||||
export type Objectify<T> = Readonly<T>;
|
||||
export type ExtractPropertyNamesOfType<T, S> = {
|
||||
[K in keyof T]: T[K] extends S ? K : never
|
||||
}[keyof T];
|
||||
export type Fix<T> = { [K in keyof T]: T[K] };
|
||||
73
types/ember/index.d.ts
vendored
73
types/ember/index.d.ts
vendored
@@ -16,6 +16,16 @@
|
||||
/// <reference types="handlebars" />
|
||||
|
||||
declare module 'ember' {
|
||||
import {
|
||||
UnwrapComputedPropertySetters,
|
||||
UnwrapComputedPropertySetter,
|
||||
UnwrapComputedPropertyGetters,
|
||||
UnwrapComputedPropertyGetter,
|
||||
ComputedPropertyCallback
|
||||
} from 'ember/-private-types/object/computed';
|
||||
import { Objectify, Fix } from 'ember/-private-types/utils';
|
||||
import { EmberClassArguments, EmberClassConstructor, EmberInstanceArguments } from 'ember/-private-types/object';
|
||||
|
||||
// Capitalization is intentional: this makes it much easier to re-export RSVP on
|
||||
// the Ember namespace.
|
||||
import Rsvp from 'rsvp';
|
||||
@@ -42,52 +52,6 @@ declare module 'ember' {
|
||||
: F extends (a: infer A, b: infer B, c: infer C, d: infer D, e: infer E) => any
|
||||
? [A, B, C, D, E]
|
||||
: never;
|
||||
/**
|
||||
* Deconstructs computed properties into the types which would be returned by `.get()`.
|
||||
*/
|
||||
type UnwrapComputedPropertyGetter<T> =
|
||||
T extends Ember.ComputedProperty<infer U, any> ? U :
|
||||
T;
|
||||
type UnwrapComputedPropertyGetters<T> = {
|
||||
[P in keyof T]: UnwrapComputedPropertyGetter<T[P]>;
|
||||
};
|
||||
|
||||
type UnwrapComputedPropertySetter<T> =
|
||||
T extends Ember.ComputedProperty<any, infer U> ? U :
|
||||
T;
|
||||
type UnwrapComputedPropertySetters<T> = {
|
||||
[P in keyof T]: UnwrapComputedPropertySetter<T[P]>;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check that any arguments to `create()` match the type's properties.
|
||||
*
|
||||
* Accept any additional properties and add merge them into the instance.
|
||||
*/
|
||||
type EmberInstanceArguments<T> = Partial<T> & {
|
||||
[key: string]: any;
|
||||
};
|
||||
|
||||
/**
|
||||
* Accept any additional properties and add merge them into the prototype.
|
||||
*/
|
||||
interface EmberClassArguments {
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* Map type `T` to a plain object hash with the identity mapping.
|
||||
*
|
||||
* Discards any additional object identity like the ability to `new()` up the class.
|
||||
* The `new()` capability is added back later by merging `EmberClassConstructor<T>`
|
||||
*
|
||||
* Implementation is carefully chosen for the reasons described in
|
||||
* https://github.com/typed-ember/ember-typings/pull/29
|
||||
*/
|
||||
type Objectify<T> = Readonly<T>;
|
||||
|
||||
type Fix<T> = { [K in keyof T]: T[K] };
|
||||
|
||||
/**
|
||||
* Ember.Object.extend(...) accepts any number of mixins or literals.
|
||||
*/
|
||||
@@ -104,23 +68,6 @@ declare module 'ember' {
|
||||
* Implementation is carefully chosen for the reasons described in
|
||||
* https://github.com/typed-ember/ember-typings/pull/29
|
||||
*/
|
||||
type EmberClassConstructor<T> = (new (properties?: object) => T) & (new (...args: any[]) => T);
|
||||
|
||||
type ComputedPropertyGetterFunction<T> = (this: any, key: string) => T;
|
||||
|
||||
interface ComputedPropertyGet<T> {
|
||||
get(this: any, key: string): T;
|
||||
}
|
||||
|
||||
interface ComputedPropertySet<T> {
|
||||
set(this: any, key: string, value: T): T;
|
||||
}
|
||||
|
||||
type ComputedPropertyCallback<T> =
|
||||
| ComputedPropertyGetterFunction<T>
|
||||
| ComputedPropertyGet<T>
|
||||
| ComputedPropertySet<T>
|
||||
| (ComputedPropertyGet<T> & ComputedPropertySet<T>);
|
||||
|
||||
interface ActionsHash {
|
||||
[index: string]: (...params: any[]) => any;
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
/**
|
||||
* Tests to ensure that access modifier keywords are appropriately
|
||||
* respected and supported
|
||||
*/
|
||||
import Ember from 'ember';
|
||||
import { assertType } from './lib/assert';
|
||||
|
||||
@@ -8,13 +12,16 @@ class Foo extends Ember.Object {
|
||||
}
|
||||
const f = new Foo();
|
||||
assertType<string>(f.hello());
|
||||
// protected property should not be visible from outside of Foo
|
||||
assertType<string>(f.bar()); // $ExpectError
|
||||
// private property should not be visible from outside of Foo
|
||||
assertType<string>(f.baz()); // $ExpectError
|
||||
|
||||
class Foo2 extends Ember.Object.extend({
|
||||
bar: ''
|
||||
}) {
|
||||
hello() { return 'world'; }
|
||||
// Cannot override with a mis-matched property type
|
||||
protected bar() { return 'bar'; } // $ExpectError
|
||||
private baz() { return 'baz'; }
|
||||
}
|
||||
|
||||
@@ -3,6 +3,9 @@ import Component from '@ember/component';
|
||||
import Object, { computed } from '@ember/object';
|
||||
import hbs from 'htmlbars-inline-precompile';
|
||||
import { assertType } from "./lib/assert";
|
||||
import ComputedProperty from '@ember/object/computed';
|
||||
import { ExtractPropertyNamesOfType } from 'ember/-private-types/utils';
|
||||
import { UnwrapComputedPropertySetter } from 'ember/-private-types/object/computed';
|
||||
|
||||
Component.extend({
|
||||
layout: hbs`
|
||||
|
||||
198
types/ember/test/core-object.ts
Normal file
198
types/ember/test/core-object.ts
Normal 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)[]
|
||||
@@ -2,4 +2,4 @@
|
||||
// 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;
|
||||
export declare function assertType<T>(value: T): T;
|
||||
|
||||
82
types/ember/test/private/computed-tests.ts
Normal file
82
types/ember/test/private/computed-tests.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
import { Ember } from "ember";
|
||||
import { computed } from "@ember/object";
|
||||
import { UnwrapComputedPropertySetters, UnwrapComputedPropertyGetters, UnwrapComputedPropertySetter, UnwrapComputedPropertyGetter } from "ember/-private-types/object/computed";
|
||||
import ComputedProperty from "@ember/object/computed";
|
||||
import { assertType } from "../lib/assert";
|
||||
|
||||
class Example1 extends Ember.Object.extend({
|
||||
firstName: '',
|
||||
lastName: '',
|
||||
allNames: computed('fullName', function() {
|
||||
return [this.fullName];
|
||||
}),
|
||||
fullName: computed('firstName', 'lastName', function() {
|
||||
return `${this.firstName} ${this.lastName}`;
|
||||
})
|
||||
}) {
|
||||
allNames!: ComputedProperty<string[]>;
|
||||
fullName!: ComputedProperty<string>;
|
||||
}
|
||||
|
||||
let unwrappedGetters1: UnwrapComputedPropertyGetters<Example1> = {} as any;
|
||||
unwrappedGetters1.firstName; // $ExpectType string
|
||||
unwrappedGetters1.lastName; // $ExpectType string
|
||||
unwrappedGetters1.fullName; // $ExpectType string
|
||||
unwrappedGetters1.allNames; // $ExpectType string[]
|
||||
|
||||
let unwrappedSetters1: UnwrapComputedPropertySetters<Example1> = {} as any;
|
||||
unwrappedSetters1.firstName; // $ExpectType string
|
||||
unwrappedSetters1.lastName; // $ExpectType string
|
||||
unwrappedSetters1.fullName; // $ExpectType string
|
||||
unwrappedSetters1.allNames; // $ExpectType string[]
|
||||
|
||||
class Example2 extends Ember.Object.extend({
|
||||
allNames: computed('fullName', function() {
|
||||
return [this.fullName + ''];
|
||||
}) ,
|
||||
fullName: computed('firstName', 'lastName', function() {
|
||||
return `${this.firstName} ${this.lastName}`;
|
||||
})
|
||||
}) {
|
||||
firstName = '';
|
||||
lastName = '';
|
||||
foo() {
|
||||
this.fullName; // $ExpectType ComputedProperty<string, string>
|
||||
this.allNames; // $ExpectType ComputedProperty<string[], string[]>
|
||||
this.firstName; // $ExpectType string
|
||||
this.lastName; // $ExpectType string
|
||||
|
||||
this.get('fullName').split(','); // $ExpectType string[]
|
||||
this.get('allNames')[0]; // $ExpectType string
|
||||
this.get('firstName').split(','); // $ExpectType string[]
|
||||
this.get('lastName').split(','); // $ExpectType string[]
|
||||
}
|
||||
}
|
||||
let ex2 = new Example2();
|
||||
|
||||
let unwrappedGetters2: UnwrapComputedPropertyGetters<typeof ex2> = (ex2 as any) as UnwrapComputedPropertyGetters<typeof ex2>;
|
||||
assertType<string>(unwrappedGetters2.firstName); // $ExpectType string
|
||||
assertType<string>(unwrappedGetters2.lastName); // $ExpectType string
|
||||
assertType<string>(unwrappedGetters2.fullName); // $ExpectType string
|
||||
assertType<string[]>(unwrappedGetters2.allNames); // $ExpectType string[]
|
||||
|
||||
let unwrappedSetters2: UnwrapComputedPropertySetters<typeof ex2> = null as any;
|
||||
assertType<string>(unwrappedSetters2.firstName); // $ExpectType string
|
||||
assertType<string>(unwrappedSetters2.lastName); // $ExpectType string
|
||||
assertType<string>(unwrappedSetters2.fullName); // $ExpectType string
|
||||
assertType<string[]>(unwrappedSetters2.allNames); // $ExpectType string[]
|
||||
|
||||
ex2.fullName; // $ExpectType ComputedProperty<string, string>
|
||||
ex2.allNames; // $ExpectType ComputedProperty<string[], string[]>
|
||||
ex2.firstName; // $ExpectType string
|
||||
|
||||
type UnwStringSet = UnwrapComputedPropertySetter<string>; // $ExpectType string
|
||||
type UnwStringGet = UnwrapComputedPropertyGetter<string>; // $ExpectType string
|
||||
type UnwCpStringSet1 = UnwrapComputedPropertySetter<ComputedProperty<string>>; // $ExpectType string
|
||||
type UnwCpStringGet1 = UnwrapComputedPropertyGetter<ComputedProperty<string>>; // $ExpectType string
|
||||
type UnwCpStringSet2 = UnwrapComputedPropertySetter<ComputedProperty<string, string>>; // $ExpectType string
|
||||
type UnwCpStringGet2 = UnwrapComputedPropertyGetter<ComputedProperty<string, string>>; // $ExpectType string
|
||||
type UnwCpStringSet3 = UnwrapComputedPropertySetter<ComputedProperty<number, string>>; // $ExpectType string
|
||||
type UnwCpStringGet3 = UnwrapComputedPropertyGetter<ComputedProperty<number, string>>; // $ExpectType number
|
||||
type UnwCpStringSet4 = UnwrapComputedPropertySetter<ComputedProperty<string, number>>; // $ExpectType number
|
||||
type UnwCpStringGet4 = UnwrapComputedPropertyGetter<ComputedProperty<string, number>>; // $ExpectType string
|
||||
175
types/ember/test/private/observable-tests.ts
Normal file
175
types/ember/test/private/observable-tests.ts
Normal file
@@ -0,0 +1,175 @@
|
||||
import Observable from "@ember/object/observable";
|
||||
import { UnwrapComputedPropertyGetter, UnwrapComputedPropertyGetters, UnwrapComputedPropertySetters, UnwrapComputedPropertySetter } from "ember/-private-types/object/computed";
|
||||
// tslint-disable-next-line
|
||||
import { assertType } from "../lib/assert";
|
||||
import { Ember } from "ember";
|
||||
import { ExtractPropertyNamesOfType } from "ember/-private-types/utils";
|
||||
|
||||
class OtherThing {
|
||||
observerOfDemo(target: DemoObservable, key: 'foo') {}
|
||||
}
|
||||
|
||||
class DemoObservable implements Observable {
|
||||
foo: string;
|
||||
isFoo = true;
|
||||
bar: [boolean, boolean];
|
||||
baz?: number;
|
||||
constructor() {
|
||||
this.foo = 'hello';
|
||||
this.bar = [false, true];
|
||||
this.baz = 9;
|
||||
this.addObserver('foo', this, 'fooDidChange');
|
||||
this.addObserver('foo', this, 'fooDidChangeProtected'); // $ExpectError
|
||||
this.addObserver('foo', this, this.fooDidChange);
|
||||
this.addObserver('foo', this, this.fooDidChangeProtected);
|
||||
const ot = new OtherThing();
|
||||
this.addObserver('foo', ot, ot.observerOfDemo);
|
||||
Ember.addObserver(this, 'foo', this, 'fooDidChange');
|
||||
Ember.addObserver(this, 'foo', this, 'fooDidChangeProtected'); // $ExpectError
|
||||
Ember.addObserver(this, 'foo', this, this.fooDidChange);
|
||||
Ember.addObserver(this, 'foo', this, this.fooDidChangeProtected);
|
||||
this.removeObserver('foo', this, 'fooDidChange');
|
||||
this.removeObserver('foo', this, 'fooDidChangeProtected'); // $ExpectError
|
||||
this.removeObserver('foo', this, this.fooDidChange);
|
||||
this.removeObserver('foo', this, this.fooDidChangeProtected);
|
||||
Ember.removeObserver(this, 'foo', this, 'fooDidChange');
|
||||
Ember.removeObserver(this, 'foo', this, 'fooDidChangeProtected'); // $ExpectError
|
||||
Ember.removeObserver(this, 'foo', this, this.fooDidChange);
|
||||
const lambda = () => {
|
||||
this.fooDidChange(this, 'foo');
|
||||
};
|
||||
this.addObserver('foo', lambda);
|
||||
this.addObserver('foo', (sender, key, value, rev) => {
|
||||
assertType<DemoObservable>(sender);
|
||||
assertType<'foo'>(key);
|
||||
assertType<string>(value);
|
||||
assertType<number>(rev);
|
||||
});
|
||||
this.removeObserver('foo', lambda);
|
||||
Ember.addObserver(this, 'foo', lambda);
|
||||
Ember.removeObserver(this, 'foo', lambda);
|
||||
}
|
||||
|
||||
fooDidChange(obj: this, propName: keyof this) {}
|
||||
protected fooDidChangeProtected(obj: this, propName: keyof this) {}
|
||||
get<K extends keyof this>(key: K): UnwrapComputedPropertyGetter<this[K]> {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
getProperties<K extends keyof this>(list: K[]): Pick<UnwrapComputedPropertyGetters<this>, K>;
|
||||
getProperties<K extends keyof this>(...list: K[]): Pick<UnwrapComputedPropertyGetters<this>, K>;
|
||||
getProperties(...rest: any[]): any {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
set<K extends keyof this>(key: K, value: this[K]): this[K] {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
setProperties<K extends keyof this>(hash: Pick<UnwrapComputedPropertySetters<this>, K>): Pick< UnwrapComputedPropertySetters<this>, K> {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
notifyPropertyChange(keyName: string): this {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
addObserver<Target>(key: keyof this, target: Target, method: keyof Target | ((this: Target, sender: this, key: keyof this, value: any, rev: number) => void)): void;
|
||||
addObserver<K extends keyof this>(key: K, method: keyof this | ((this: this, sender: this, key: K, value: this[K], rev: number) => void)): void;
|
||||
addObserver(key: any, target: any, method?: any) {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
removeObserver<Target>(key: keyof this, target: Target, method: keyof Target | ((this: Target, sender: this, key: keyof this, value: any, rev: number) => void)): void;
|
||||
removeObserver(key: keyof this, method: keyof this | ((this: this, sender: this, key: keyof this, value: any, rev: number) => void)): void;
|
||||
removeObserver(key: any, target: any, method?: any): void {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
getWithDefault<K extends keyof this>(key: K, defaultValue: UnwrapComputedPropertyGetter<this[K]>): UnwrapComputedPropertyGetter<this[K]> {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
incrementProperty(keyName: ExtractPropertyNamesOfType<this, number | undefined>, increment?: number): number {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
decrementProperty(keyName: ExtractPropertyNamesOfType<this, number | undefined>, decrement?: number): number {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
toggleProperty(keyName: ExtractPropertyNamesOfType<this, boolean | undefined>): boolean {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
cacheFor<K extends keyof this>(key: K): UnwrapComputedPropertyGetter<this[K]> | undefined {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
}
|
||||
const o = new DemoObservable();
|
||||
|
||||
/**
|
||||
* get
|
||||
*/
|
||||
assertType<string>(o.get('foo')); // $ExpectType string
|
||||
assertType<[boolean, boolean]>(o.get('bar')); // $ExpectType [boolean, boolean]
|
||||
assertType<number | undefined>(o.get('baz')); // $ExpectType number | undefined
|
||||
|
||||
/**
|
||||
* incrementProperty, decrementProperty
|
||||
*/
|
||||
assertType<number>(o.incrementProperty('baz')); // $ExpectType number
|
||||
assertType<number>(o.decrementProperty('baz')); // $ExpectType number
|
||||
assertType<number>(o.incrementProperty('baz', 3)); // $ExpectType number
|
||||
assertType<number>(o.decrementProperty('baz', 12)); // $ExpectType number
|
||||
// non-numeric property case
|
||||
assertType<number>(o.incrementProperty('bar')); // $ExpectError
|
||||
assertType<number>(o.decrementProperty('bar')); // $ExpectError
|
||||
// empty case
|
||||
assertType<number>(o.incrementProperty()); // $ExpectError
|
||||
assertType<number>(o.decrementProperty()); // $ExpectError
|
||||
|
||||
/**
|
||||
* toggleProperty
|
||||
*/
|
||||
o.toggleProperty('isFoo'); // $ExpectType boolean
|
||||
o.toggleProperty(); // $ExpectError
|
||||
|
||||
/**
|
||||
* getWithDefault
|
||||
*/
|
||||
assertType<string>(o.getWithDefault('foo', 'zzz')); // $ExpectType string
|
||||
assertType<[boolean, boolean]>(o.getWithDefault('bar', [false, false])); // $ExpectType [boolean, boolean]
|
||||
assertType<number | undefined>(o.getWithDefault('baz', 10)); // $ExpectType number | undefined
|
||||
// improper arguments cases
|
||||
assertType<number | undefined>(o.getWithDefault('baz', '10')); // $ExpectError
|
||||
assertType<number | undefined>(o.getWithDefault('baz')); // $ExpectError
|
||||
assertType<number | undefined>(o.getWithDefault()); // $ExpectError
|
||||
|
||||
/**
|
||||
* getProperties
|
||||
*/
|
||||
// ('foo', 'bar')
|
||||
assertType<{ foo: string, bar: [boolean, boolean] }>(o.getProperties('foo', 'bar')); // $ExpectType { foo: string; bar: [boolean, boolean]; }
|
||||
// ['foo', 'bar']
|
||||
assertType<{ foo: string, bar: [boolean, boolean] }>(o.getProperties(['foo', 'bar'])); // $ExpectType { foo: string; bar: [boolean, boolean]; }
|
||||
// empty cases
|
||||
assertType<{}>(o.getProperties()); // $ExpectType {}
|
||||
assertType<{}>(o.getProperties([])); // $ExpectType {}
|
||||
// property that doesn't exist
|
||||
assertType<any>(o.getProperties('jeanShorts', 'foo')); // $ExpectError
|
||||
assertType<any>(o.getProperties(['foo', 'jeanShorts'])); // $ExpectError
|
||||
|
||||
/**
|
||||
* set
|
||||
*/
|
||||
assertType<string>(o.set('foo', 'abc')); // $ExpectType string
|
||||
assertType<[boolean, boolean]>(o.set('bar', [false, false])); // $ExpectType [boolean, boolean]
|
||||
assertType<number | undefined>(o.set('baz', undefined)); // $ExpectType number | undefined
|
||||
assertType<number | undefined>(o.set('baz', 10)); // $ExpectType number | undefined
|
||||
// property that doesn't exist
|
||||
assertType<any>(o.set('jeanShorts', 10)); // $ExpectError
|
||||
|
||||
/**
|
||||
* setProperties
|
||||
*/
|
||||
assertType<{ foo: string, bar: [boolean, boolean] }>(o.setProperties({ foo: 'abc', bar: [true, true] })); // $ExpectType { foo: string; bar: [boolean, boolean]; }
|
||||
// empty case
|
||||
assertType<{}>(o.setProperties({})); // $ExpectType {}
|
||||
// property that doesn't exist
|
||||
assertType<any>(o.setProperties({ jeanShorts: 'under the pants' })); // $ExpectError
|
||||
|
||||
/**
|
||||
* notifyPropertyChange
|
||||
*/
|
||||
assertType<DemoObservable>(o.notifyPropertyChange('foo')); // $ExpectType DemoObservable
|
||||
assertType<Observable>(o.notifyPropertyChange('jeanShorts')); // $ExpectError
|
||||
62
types/ember/test/techniques/properties-from-this.ts
Normal file
62
types/ember/test/techniques/properties-from-this.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* These tests validate that the method of pulling property types off of this
|
||||
* continues to work. We use this technique in the critical Observable interface
|
||||
* that serves to implement a lot of Ember.CoreObject's functionality
|
||||
*/
|
||||
|
||||
class BoxedProperty<Get, Set = Get> {
|
||||
__getType: Get;
|
||||
__setType: Set;
|
||||
}
|
||||
|
||||
type UnboxGetProperty<T> = T extends BoxedProperty<infer V, any> ? V : T;
|
||||
type UnboxSetProperty<T> = T extends BoxedProperty<any, infer V> ? V : T;
|
||||
|
||||
class GetAndSet {
|
||||
get<K extends keyof this>(key: K): UnboxGetProperty<this[K]> {
|
||||
return this[key] as any;
|
||||
}
|
||||
set<K extends keyof this>(key: K, newVal: UnboxSetProperty<this[K]>): UnboxSetProperty<this[K]> {
|
||||
const rawVal: UnboxSetProperty<this[K]> = this[key] as any;
|
||||
if (rawVal instanceof BoxedProperty) {
|
||||
rawVal.__setType = newVal;
|
||||
}
|
||||
this[key] = newVal as any;
|
||||
return newVal;
|
||||
}
|
||||
}
|
||||
|
||||
class Foo123 extends GetAndSet {
|
||||
// tslint:disable-next-line:no-inferrable-types
|
||||
a: number;
|
||||
b: [boolean, boolean];
|
||||
c: string;
|
||||
cpA!: BoxedProperty<string>;
|
||||
constructor() {
|
||||
super();
|
||||
this.a = 1;
|
||||
this.b = [true, false];
|
||||
this.c = 'hello';
|
||||
}
|
||||
}
|
||||
|
||||
let f = new Foo123();
|
||||
|
||||
f.get('a'); // $ExpectType number
|
||||
f.set('a'); // $ExpectError
|
||||
f.set('a', '1'); // $ExpectError
|
||||
f.set('a', 1); // $ExpectType number
|
||||
|
||||
f.get('b'); // $ExpectType [boolean, boolean]
|
||||
f.set('b', 1); // $ExpectError
|
||||
f.set('b', []); // $ExpectError
|
||||
f.set('b', [true]); // $ExpectError
|
||||
f.set('b', [false, true]); // $ExpectType [boolean, boolean]
|
||||
f.set('b', [false, true, false]); // $ExpectError
|
||||
|
||||
f.get('c'); // $ExpectType string
|
||||
f.set('c', '1'); // $ExpectType string
|
||||
|
||||
f.get('cpA'); // $ExpectType string
|
||||
f.set('cpA', ['newValue']); // $ExpectError
|
||||
f.set('cpA', 'newValue'); // $ExpectType string
|
||||
@@ -20,7 +20,14 @@
|
||||
},
|
||||
"files": [
|
||||
"index.d.ts",
|
||||
"-private-types/utils.d.ts",
|
||||
"-private-types/mixin.d.ts",
|
||||
"-private-types/object.d.ts",
|
||||
"-private-types/object/computed.d.ts",
|
||||
"test/lib/assert.ts",
|
||||
"test/private/computed-tests.ts",
|
||||
"test/private/observable-tests.ts",
|
||||
"test/techniques/properties-from-this.ts",
|
||||
"test/access-modifier.ts",
|
||||
"test/application-instance.ts",
|
||||
"test/application.ts",
|
||||
@@ -30,9 +37,9 @@
|
||||
"test/component.ts",
|
||||
"test/computed.ts",
|
||||
"test/controller.ts",
|
||||
"test/core-object.ts",
|
||||
"test/create-negative.ts",
|
||||
"test/create.ts",
|
||||
"test/create.ts",
|
||||
"test/detect-instance.ts",
|
||||
"test/detect.ts",
|
||||
"test/ember-tests.ts",
|
||||
|
||||
Reference in New Issue
Block a user