// @declaration: true // @strict: true // @target: es5 // In methods of an object literal with no contextual type, 'this' has the type // of the object literal. let obj1 = { a: 1, f() { return this.a; }, b: "hello", c: { g() { this.g(); } }, get d() { return this.a; }, get e() { return this.b; }, set e(value) { this.b = value; } }; // In methods of an object literal with a contextual type, 'this' has the // contextual type. type Point = { x: number; y: number; z?: number; moveBy(dx: number, dy: number, dz?: number): void; } let p1: Point = { x: 10, y: 20, moveBy(dx, dy, dz) { this.x += dx; this.y += dy; if (this.z && dz) { this.z += dz; } } }; let p2: Point | null = { x: 10, y: 20, moveBy(dx, dy, dz) { this.x += dx; this.y += dy; if (this.z && dz) { this.z += dz; } } }; let p3: Point | undefined = { x: 10, y: 20, moveBy(dx, dy, dz) { this.x += dx; this.y += dy; if (this.z && dz) { this.z += dz; } } }; let p4: Point | null | undefined = { x: 10, y: 20, moveBy(dx, dy, dz) { this.x += dx; this.y += dy; if (this.z && dz) { this.z += dz; } } }; declare function f1(p: Point): void; f1({ x: 10, y: 20, moveBy(dx, dy, dz) { this.x += dx; this.y += dy; if (this.z && dz) { this.z += dz; } } }); declare function f2(p: Point | null | undefined): void; f2({ x: 10, y: 20, moveBy(dx, dy, dz) { this.x += dx; this.y += dy; if (this.z && dz) { this.z += dz; } } }); // In methods of an object literal with a contextual type that includes some // ThisType, 'this' is of type T. type ObjectDescriptor = { data?: D; methods?: M & ThisType; // Type of 'this' in methods is D & M } declare function makeObject(desc: ObjectDescriptor): D & M; let x1 = makeObject({ data: { x: 0, y: 0 }, methods: { moveBy(dx: number, dy: number) { this.x += dx; // Strongly typed this this.y += dy; // Strongly typed this } } }); // In methods contained in an object literal with a contextual type that includes // some ThisType, 'this' is of type T. type ObjectDescriptor2 = ThisType & { data?: D; methods?: M; } declare function makeObject2(desc: ObjectDescriptor): D & M; let x2 = makeObject2({ data: { x: 0, y: 0 }, methods: { moveBy(dx: number, dy: number) { this.x += dx; // Strongly typed this this.y += dy; // Strongly typed this } } }); // Check pattern similar to Object.defineProperty and Object.defineProperties type PropDesc = { value?: T; get?(): T; set?(value: T): void; } type PropDescMap = { [K in keyof T]: PropDesc; } declare function defineProp(obj: T, name: K, desc: PropDesc & ThisType): T & Record; declare function defineProps(obj: T, descs: PropDescMap & ThisType): T & U; let p10 = defineProp(p1, "foo", { value: 42 }); p10.foo = p10.foo + 1; let p11 = defineProp(p1, "bar", { get() { return this.x; }, set(value: number) { this.x = value; } }); p11.bar = p11.bar + 1; let p12 = defineProps(p1, { foo: { value: 42 }, bar: { get(): number { return this.x; }, set(value: number) { this.x = value; } } }); p12.foo = p12.foo + 1; p12.bar = p12.bar + 1; // Proof of concept for typing of Vue.js type Accessors = { [K in keyof T]: (() => T[K]) | Computed }; type Dictionary = { [x: string]: T } type Computed = { get?(): T; set?(value: T): void; } type VueOptions = ThisType & { data?: D | (() => D); methods?: M; computed?: Accessors

; } declare const Vue: new (options: VueOptions) => D & M & P; let vue = new Vue({ data: () => ({ x: 1, y: 2 }), methods: { f(x: string) { return this.x; } }, computed: { test(): number { return this.x; }, hello: { get() { return "hi"; }, set(value: string) { } } } }); vue; vue.x; vue.f("abc"); vue.test; vue.hello;