options-test.ts 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501
  1. import Vue, { PropType, VNode } from "../index";
  2. import { ComponentOptions, Component } from "../index";
  3. import { CreateElement } from "../vue";
  4. interface MyComponent extends Vue {
  5. a: number;
  6. }
  7. const option: ComponentOptions<MyComponent> = {
  8. data() {
  9. return {
  10. a: 123
  11. }
  12. }
  13. }
  14. // contravariant generic should use never
  15. const anotherOption: ComponentOptions<never> = option
  16. const componentType: Component = option
  17. Vue.component('sub-component', {
  18. components: {
  19. a: Vue.component(""),
  20. b: {}
  21. }
  22. });
  23. Vue.component('prop-component', {
  24. props: {
  25. size: Number,
  26. name: {
  27. type: String,
  28. default: '0',
  29. required: true,
  30. }
  31. },
  32. data() {
  33. return {
  34. fixedSize: this.size.toFixed(),
  35. capName: this.name.toUpperCase()
  36. }
  37. }
  38. });
  39. Vue.component('string-prop', {
  40. props: ['size', 'name'],
  41. data() {
  42. return {
  43. fixedSize: this.size.whatever,
  44. capName: this.name.isany
  45. }
  46. }
  47. });
  48. class User {
  49. private u = 1
  50. }
  51. class Cat {
  52. private u = 1
  53. }
  54. interface IUser {
  55. foo: string,
  56. bar: number
  57. }
  58. interface ICat {
  59. foo: any,
  60. bar: object
  61. }
  62. type ConfirmCallback = (confirm: boolean) => void;
  63. Vue.component('union-prop', {
  64. props: {
  65. cat: Object as PropType<ICat>,
  66. complexUnion: { type: [User, Number] as PropType<User | number> },
  67. kittyUser: Object as PropType<ICat & IUser>,
  68. callback: Function as PropType<ConfirmCallback>,
  69. union: [User, Number] as PropType<User | number>
  70. },
  71. data() {
  72. this.cat;
  73. this.complexUnion;
  74. this.kittyUser;
  75. this.callback(true);
  76. this.union;
  77. return {
  78. fixedSize: this.union,
  79. }
  80. }
  81. });
  82. Vue.component('union-prop-with-no-casting', {
  83. props: {
  84. mixed: [RegExp, Array],
  85. object: [Cat, User],
  86. primitive: [String, Number],
  87. regex: RegExp
  88. },
  89. data() {
  90. this.mixed;
  91. this.object;
  92. this.primitive;
  93. this.regex.compile;
  94. }
  95. })
  96. Vue.component('prop-with-primitive-default', {
  97. props: {
  98. id: {
  99. type: String,
  100. default: () => String(Math.round(Math.random() * 10000000))
  101. }
  102. },
  103. created(): void {
  104. this.id;
  105. }
  106. });
  107. Vue.component('component', {
  108. data() {
  109. this.$mount
  110. this.size
  111. return {
  112. a: 1
  113. }
  114. },
  115. props: {
  116. size: Number,
  117. name: {
  118. type: String,
  119. default: '0',
  120. required: true,
  121. }
  122. },
  123. propsData: {
  124. msg: "Hello"
  125. },
  126. computed: {
  127. aDouble(): number {
  128. return this.a * 2;
  129. },
  130. aPlus: {
  131. get(): number {
  132. return this.a + 1;
  133. },
  134. set(v: number) {
  135. this.a = v - 1;
  136. },
  137. cache: false
  138. }
  139. },
  140. methods: {
  141. plus(): void {
  142. this.a++;
  143. this.aDouble.toFixed();
  144. this.aPlus = 1;
  145. this.size.toFixed();
  146. }
  147. },
  148. watch: {
  149. 'a': function(val: number, oldVal: number) {
  150. console.log(`new: ${val}, old: ${oldVal}`);
  151. },
  152. 'b': 'someMethod',
  153. 'c': {
  154. handler(val, oldVal) {
  155. this.a = val
  156. },
  157. deep: true
  158. },
  159. d: {
  160. handler: 'someMethod',
  161. immediate: true
  162. }
  163. },
  164. el: "#app",
  165. template: "<div>{{ message }}</div>",
  166. render(createElement) {
  167. return createElement("div", {
  168. attrs: {
  169. id: "foo"
  170. },
  171. props: {
  172. myProp: "bar"
  173. },
  174. directives: [{
  175. name: 'a',
  176. value: 'foo'
  177. }],
  178. domProps: {
  179. innerHTML: "baz"
  180. },
  181. on: {
  182. click: new Function
  183. },
  184. nativeOn: {
  185. click: new Function
  186. },
  187. class: {
  188. foo: true,
  189. bar: false
  190. },
  191. style: {
  192. color: 'red',
  193. fontSize: '14px'
  194. },
  195. key: 'myKey',
  196. ref: 'myRef',
  197. refInFor: true
  198. }, [
  199. createElement(),
  200. createElement("div", "message"),
  201. createElement(Vue.component("component")),
  202. createElement({} as ComponentOptions<Vue>),
  203. createElement({
  204. functional: true,
  205. render(c: CreateElement) {
  206. return createElement()
  207. }
  208. }),
  209. createElement(() => Vue.component("component")),
  210. createElement(() => ( {} as ComponentOptions<Vue> )),
  211. createElement((resolve, reject) => {
  212. resolve({} as ComponentOptions<Vue>);
  213. reject();
  214. }),
  215. "message",
  216. [createElement("div", "message")]
  217. ]);
  218. },
  219. renderError(createElement, err) {
  220. return createElement('pre', { style: { color: 'red' }}, err.stack)
  221. },
  222. staticRenderFns: [],
  223. beforeCreate() {
  224. (this as any).a = 1;
  225. },
  226. created() {},
  227. beforeDestroy() {},
  228. destroyed() {},
  229. beforeMount() {},
  230. mounted() {},
  231. beforeUpdate() {},
  232. updated() {},
  233. activated() {},
  234. deactivated() {},
  235. errorCaptured(err, vm, info) {
  236. err.message
  237. vm.$emit('error')
  238. info.toUpperCase()
  239. return true
  240. },
  241. serverPrefetch () {
  242. return Promise.resolve()
  243. },
  244. directives: {
  245. a: {
  246. bind() {},
  247. inserted() {},
  248. update() {},
  249. componentUpdated() {},
  250. unbind() {}
  251. },
  252. b(el, binding, vnode, oldVnode) {
  253. el.textContent;
  254. binding.name;
  255. binding.value;
  256. binding.oldValue;
  257. binding.expression;
  258. binding.arg;
  259. binding.modifiers["modifier"];
  260. }
  261. },
  262. components: {
  263. a: Vue.component(""),
  264. b: {} as ComponentOptions<Vue>
  265. },
  266. transitions: {},
  267. filters: {
  268. double(value: number) {
  269. return value * 2;
  270. }
  271. },
  272. parent: new Vue,
  273. mixins: [Vue.component(""), ({} as ComponentOptions<Vue>)],
  274. name: "Component",
  275. extends: {} as ComponentOptions<Vue>,
  276. delimiters: ["${", "}"]
  277. });
  278. Vue.component('custom-prop-type-function', {
  279. props: {
  280. callback: Function as PropType<(confirm: boolean) => void>,
  281. },
  282. methods: {
  283. confirm(){
  284. this.callback(true);
  285. }
  286. }
  287. });
  288. Vue.component('provide-inject', {
  289. provide: {
  290. foo: 1
  291. },
  292. inject: {
  293. injectFoo: 'foo',
  294. injectBar: Symbol(),
  295. injectBaz: { from: 'baz' },
  296. injectQux: { default: 1 },
  297. injectQuux: { from: 'quuz', default: () => ({ value: 1 })}
  298. }
  299. })
  300. Vue.component('provide-function', {
  301. provide: () => ({
  302. foo: 1
  303. })
  304. })
  305. Vue.component('component-with-slot', {
  306. render (h): VNode {
  307. return h('div', this.$slots.default)
  308. }
  309. })
  310. Vue.component('component-with-scoped-slot', {
  311. render (h) {
  312. interface ScopedSlotProps {
  313. msg: string
  314. }
  315. return h('div', [
  316. h('child', [
  317. // default scoped slot as children
  318. (props: ScopedSlotProps) => [h('span', [props.msg])]
  319. ]),
  320. h('child', {
  321. scopedSlots: {
  322. // named scoped slot as vnode data
  323. item: (props: ScopedSlotProps) => [h('span', [props.msg])]
  324. }
  325. }),
  326. h('child', [
  327. // return single VNode (will be normalized to an array)
  328. (props: ScopedSlotProps) => h('span', [props.msg])
  329. ]),
  330. h('child', {
  331. // Passing down all slots from parent
  332. scopedSlots: this.$scopedSlots
  333. }),
  334. h('child', {
  335. // Passing down single slot from parent
  336. scopedSlots: {
  337. default: this.$scopedSlots.default
  338. }
  339. })
  340. ])
  341. },
  342. components: {
  343. child: {
  344. render (this: Vue, h: CreateElement) {
  345. const defaultSlot = this.$scopedSlots['default']!({ msg: 'hi' })
  346. defaultSlot && defaultSlot.forEach(vnode => {
  347. vnode.tag
  348. })
  349. return h('div', [
  350. defaultSlot,
  351. this.$scopedSlots['item']!({ msg: 'hello' })
  352. ])
  353. }
  354. }
  355. }
  356. })
  357. Vue.component('narrow-array-of-vnode-type', {
  358. render (h): VNode {
  359. const slot = this.$scopedSlots.default!({})
  360. if (typeof slot === 'string') {
  361. // <template slot-scope="data">bare string</template>
  362. return h('span', slot)
  363. } else if (Array.isArray(slot)) {
  364. // template with multiple children
  365. const first = slot[0]
  366. if (!Array.isArray(first) && typeof first !== 'string' && first) {
  367. return first
  368. } else {
  369. return h()
  370. }
  371. } else if (slot) {
  372. // <div slot-scope="data">bare VNode</div>
  373. return slot
  374. } else {
  375. // empty template, slot === undefined
  376. return h()
  377. }
  378. }
  379. })
  380. Vue.component('functional-component', {
  381. props: ['prop'],
  382. functional: true,
  383. inject: ['foo'],
  384. render(createElement, context) {
  385. context.props;
  386. context.children;
  387. context.slots();
  388. context.data;
  389. context.parent;
  390. context.scopedSlots;
  391. context.listeners.click;
  392. return createElement("div", {}, context.children);
  393. }
  394. });
  395. Vue.component('functional-component-object-inject', {
  396. functional: true,
  397. inject: {
  398. foo: 'foo',
  399. bar: Symbol(),
  400. baz: { from: 'baz' },
  401. qux: { default: 1 },
  402. quux: { from: 'quuz', default: () => ({ value: 1 })}
  403. },
  404. render(h) {
  405. return h('div')
  406. }
  407. })
  408. Vue.component('functional-component-check-optional', {
  409. functional: true
  410. })
  411. Vue.component('functional-component-multi-root', {
  412. functional: true,
  413. render(h) {
  414. return [
  415. h("tr", [h("td", "foo"), h("td", "bar")]),
  416. h("tr", [h("td", "lorem"), h("td", "ipsum")])
  417. ]
  418. }
  419. })
  420. Vue.component("async-component", ((resolve, reject) => {
  421. setTimeout(() => {
  422. resolve(Vue.component("component"));
  423. }, 0);
  424. return new Promise((resolve) => {
  425. resolve({
  426. functional: true,
  427. render(h: CreateElement) { return h('div') }
  428. });
  429. })
  430. }));
  431. Vue.component('functional-component-v-model', {
  432. props: ['foo'],
  433. functional: true,
  434. model: {
  435. prop: 'foo',
  436. event: 'change'
  437. },
  438. render(createElement, context) {
  439. return createElement("input", {
  440. on: {
  441. input: new Function()
  442. },
  443. domProps: {
  444. value: context.props.foo
  445. }
  446. });
  447. }
  448. });
  449. Vue.component('async-es-module-component', () => import('./es-module'))
  450. Vue.component('directive-expression-optional-string', {
  451. render(createElement) {
  452. return createElement("div", {
  453. directives: [
  454. {
  455. name: 'has-expression',
  456. value: 2,
  457. expression: '1 + 1',
  458. }, {
  459. name: 'no-expression',
  460. value: 'foo',
  461. },
  462. ],
  463. })
  464. }
  465. });