DefinitelyTyped/types/stampit/stampit-tests.ts
PopGoesTheWza d77ee72756 stampit 4.3 - better typing through generics (#39188)
* stampit 4.3

* fix `Error: stampit: Older version 3 must have a path mapping for itself.`

* fix`baseUrl` & `typeRoots`

* Some dtslint compliance

* header fix

* enhance

* tests

* tslint:disable

* naming

* fix refs/props changes + ExtendedDescriptor

* more $ExpectType tests

* Tentative `MethodMap` fix

* Updated  `MethodMap`tests

* additional testing (failing)

* fix `Composable` signature
2019-10-30 07:35:36 -07:00

341 lines
8.2 KiB
TypeScript

/** Import 'stampit' module */
import stampit from 'stampit';
/** Import 'stampit' as ... module */
// import * as Stamp from 'stampit';
/** selective import from module */
// import {
// compose,
// composers,
// conf,
// configuration,
// deepConf,
// deepConfiguration,
// deepProperties,
// deepProps,
// deepStatics,
// init,
// initializers,
// methods,
// properties,
// propertyDescriptors,
// props,
// staticDeepProperties,
// staticProperties,
// staticPropertyDescriptors,
// version,
// } from 'stampit';
const a = stampit().init(function(options) {
const a = options.args[0];
this.getA = () => {
return a;
};
});
a(); // Object -- so far so good.
a().getA(); // "a"
const b = stampit().init(function() {
const a = 'b';
this.getB = () => {
return a;
};
});
const c = stampit.compose(a, b);
const foo = c(); // we won't throw this one away...
foo.getA(); // "a"
foo.getB(); // "b"
// Here's a mixin with public methods, and some props:
const membership = stampit({
methods: {
members: {
itCanBe: "anything",
},
myMembers: {},
dbConnString: "pgs://data.local",
MY_LIMIT: 100,
myRegExp: /foobar/g,
add(member: any) {
this.members[member.name] = member;
return this;
},
getMember(name: any) {
return this.members[name];
}
},
props: {
members: {}
}
});
// Let's set some defaults:
const defaults = stampit().props({
name: 'The Saloon',
specials: 'Whisky, Gin, Tequila'
});
// Classical inheritance has nothing on this. No parent/child coupling. No deep inheritance hierarchies.
// Just good, clean code reusability.
const bar = stampit.compose(defaults, membership);
// Note that you can override props on instantiation:
const myBar = bar({ name: 'Moe\'s' });
// Silly, but proves that everything is as it should be.
myBar.add({ name: 'Homer' }).open().getMember('Homer');
const myStamp = stampit().methods({
foo() {
return 'foo';
},
methodOverride() {
return false;
},
myMembers: {},
dbConnString: "pgs://data.local",
MY_LIMIT: 100,
myRegExp: /foobar/g,
}).methods({
bar() {
return 'bar';
},
methodOverride() {
return true;
},
myMembers: {},
dbConnString: "pgs://data.local",
MY_LIMIT: 100,
myRegExp: /foobar/g,
});
myStamp.deepProps({
foo: { bar: 'bar' },
refsOverride: false
}).props({
bar: 'bar',
refsOverride: true
});
myStamp.init(function() {
const secret = 'foo';
this.getSecret = () => {
return secret;
};
}).init(function() {
this.a = true;
}).init(function() {
this.b = true;
}, function() {
this.c = true;
});
let obj = myStamp.create();
obj.getSecret && obj.a && obj.b && obj.c; // true
const newStamp = stampit({ props: { defaultNum: 1 } }).compose(myStamp);
const obj1 = stampit().methods({
a() {
return 'a';
},
myMembers: {},
dbConnString: "pgs://data.local",
MY_LIMIT: 100,
myRegExp: /foobar/g,
}, {
b() {
return 'b';
},
myMembers: {},
dbConnString: "pgs://data.local",
MY_LIMIT: 100,
myRegExp: /foobar/g,
}).create();
const obj2 = stampit().props({
a: 'a'
}, {
b: 'b'
}).create();
obj = defaults.compose(newStamp, membership).create();
// The old constructor / class thing...
const Constructor = function Constructor() {
this.thing = 'initialized';
};
Constructor.prototype.foo = function foo() {
return 'foo';
};
// A new stamp to compose with...
const newskool = stampit().methods({
bar: function bar() {
return 'bar';
},
myMembers: {},
dbConnString: "pgs://data.local",
MY_LIMIT: 100,
myRegExp: /foobar/g,
// your methods here...
}).init(function() {
this.baz = 'baz';
});
// Now you can compose those old constructors just like you could
// with any other stamp...
const myThing = stampit.compose(newskool);
const t = myThing();
t.thing; // 'initialized',
t.foo(); // 'foo',
t.bar(); // 'bar'
interface SomeStampInstance {
a: string;
b: string;
}
// Test import of stamp type
interface SomeStamp extends stampit.Stamp<SomeStampInstance> {
(params: { a: number; b: boolean}): SomeStampInstance;
}
const SomeStamp = stampit<SomeStamp>()
.init(function(params: { a: number; b: boolean}) {
this.a = '' + a; // this SomeStampInstance
this.b = '' + b;
});
SomeStamp({ a: 1, b: false }); // $ExpectType SomeStampInstance
SomeStamp({ a: 1, b: false }).a; // $ExpectType string
const d: stampit.ExtendedDescriptor<{}> = {
methods: {},
properties: {},
deepProperties: {},
propertyDescriptors: {},
initializers: [],
staticProperties: {},
staticDeepProperties: {},
staticPropertyDescriptors: {},
composers: [],
configuration: {},
deepConfiguration: {},
name: '',
// shorthands
props: {},
deepProps: {},
init: [],
statics: {},
deepStatics: {},
conf: {},
deepConf: {},
};
// The `.compose()` method
const compose = stampit.compose; // $ExpectType typeof stampit
const stampUntyped = compose(); // $ExpectType Stamp<any>
stampUntyped(); // $ExpectType any
// const stampAny = compose<any>(); // $ExpectType Stamp<any>
// stampAny(); // $ExpectType any
const stampBigint = compose<bigint>(); // $ExpectType never
const stampBoolean = compose<boolean>(); // $ExpectType never
const stampNull = compose<null>(); // $ExpectType never
const stampNumber = compose<number>(); // $ExpectType never
const stampString = compose<string>(); // $ExpectType never
const stampSymbol = compose<symbol>(); // $ExpectType never
const stampUndefined = compose<undefined>(); // $ExpectType never
const stampUnknown = compose<unknown>(); // $ExpectType Stamp<unknown>
stampUnknown(); // $ExpectType unknown
const stampNever = compose<never>(); // $ExpectType never
// Declare interface of objects created by stamps
interface Object0 {
action: () => void;
value: number;
}
interface Object1 {
reaction: () => void;
property: number;
}
const stampObject0 = compose<Object0>(); // $ExpectType Stamp<Object0>
stampObject0(); // $ExpectType Object0
const stampObject1 = compose<Object1>(); // $ExpectType Stamp<Object1>
stampObject1(); // $ExpectType Object1
// Define a typed ExtendedDescriptor and benefit its properly typed `this` in `methods`
const descriptor0: stampit.ExtendedDescriptor<Object0> = {
methods: {
logLocalThis() {
this; // $ExpectType Object0
},
myMembers: {},
dbConnString: "pgs://data.local",
MY_LIMIT: 100,
myRegExp: /foobar/g,
},
properties: {},
deepProperties: {},
propertyDescriptors: {},
staticProperties: {},
staticDeepProperties: {},
staticPropertyDescriptors: {},
initializers: [
function(options, context) {
this; // $ExpectType Object0
return context.instance;
}
],
composers: [
(parameters) => {
return parameters.stamp;
}
],
configuration: {},
deepConfiguration: {}
};
const stampDescriptor0 = compose<typeof descriptor0>(descriptor0); // $ExpectType Stamp<Object0>
stampDescriptor0(); // $ExpectType Object0
// check typed stamps... with untyped descriptor (`this` isn't typed in `methods`)
// inline type assertion is still possible though
const stampUntypedDescriptor0 = compose<Object0>(/* <stampit.ExtendedDescriptor<Object0>> */ {
methods: {
logLocalThis() {
this; // $ExpectType any
},
myMembers: {},
dbConnString: "pgs://data.local",
MY_LIMIT: 100,
myRegExp: /foobar/g,
},
} /* as stampit.ExtendedDescriptor<Object0> */);
stampUntypedDescriptor0; // $ExpectType Stamp<Object0>
stampUntypedDescriptor0(); // $ExpectType Object0
// Check a stamp's `.compose()` method
const stamp1 = stampObject0.compose<Object1>(); // $ExpectType Stamp<Object1>
stamp1(); // $ExpectType Object1
// Define an extended stamp.
// The type of created object cannot be changed afterward
// Lazy interface composition can be done using the `&` intersection operator
interface ExtendedStamp extends stampit.Stamp<Object0 & Object1> {
decompose: () => unknown;
}
// Invoke `.compose()` method with the type of the extended stamp
const extendedStamp0 = compose<ExtendedStamp>(); // $ExpectType ExtendedStamp
extendedStamp0(); // $ExpectType Object0 & Object1