options-test.ts 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516
  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. e: [
  164. 'handle1',
  165. function handle2 (val, oldVal) {},
  166. {
  167. handler: function handle3 (val, oldVal) {},
  168. }
  169. ],
  170. },
  171. el: '#app',
  172. template: '<div>{{ message }}</div>',
  173. render(createElement) {
  174. return createElement(
  175. 'div',
  176. {
  177. attrs: {
  178. id: 'foo'
  179. },
  180. props: {
  181. myProp: 'bar'
  182. },
  183. directives: [
  184. {
  185. name: 'a',
  186. value: 'foo'
  187. }
  188. ],
  189. domProps: {
  190. innerHTML: 'baz'
  191. },
  192. on: {
  193. click: new Function()
  194. },
  195. nativeOn: {
  196. click: new Function()
  197. },
  198. class: {
  199. foo: true,
  200. bar: false
  201. },
  202. style: {
  203. color: 'red',
  204. fontSize: '14px'
  205. },
  206. key: 'myKey',
  207. ref: 'myRef',
  208. refInFor: true
  209. },
  210. [
  211. createElement(),
  212. createElement('div', 'message'),
  213. createElement(Vue.component('component')),
  214. createElement({} as ComponentOptions<Vue>),
  215. createElement({
  216. functional: true,
  217. render(c: CreateElement) {
  218. return createElement()
  219. }
  220. }),
  221. createElement(() => Vue.component('component')),
  222. createElement(() => ({} as ComponentOptions<Vue>)),
  223. createElement((resolve, reject) => {
  224. resolve({} as ComponentOptions<Vue>)
  225. reject()
  226. }),
  227. 'message',
  228. [createElement('div', 'message')]
  229. ]
  230. )
  231. },
  232. renderError(createElement, err) {
  233. return createElement('pre', { style: { color: 'red' } }, err.stack)
  234. },
  235. staticRenderFns: [],
  236. beforeCreate() {
  237. ;(this as any).a = 1
  238. },
  239. created() {},
  240. beforeDestroy() {},
  241. destroyed() {},
  242. beforeMount() {},
  243. mounted() {},
  244. beforeUpdate() {},
  245. updated() {},
  246. activated() {},
  247. deactivated() {},
  248. errorCaptured(err, vm, info) {
  249. err.message
  250. vm.$emit('error')
  251. info.toUpperCase()
  252. return true
  253. },
  254. serverPrefetch() {
  255. return Promise.resolve()
  256. },
  257. directives: {
  258. a: {
  259. bind() {},
  260. inserted() {},
  261. update() {},
  262. componentUpdated() {},
  263. unbind() {}
  264. },
  265. b(el, binding, vnode, oldVnode) {
  266. el.textContent
  267. binding.name
  268. binding.value
  269. binding.oldValue
  270. binding.expression
  271. binding.arg
  272. binding.modifiers['modifier']
  273. }
  274. },
  275. components: {
  276. a: Vue.component(''),
  277. b: {} as ComponentOptions<Vue>
  278. },
  279. transitions: {},
  280. filters: {
  281. double(value: number) {
  282. return value * 2
  283. }
  284. },
  285. parent: new Vue(),
  286. mixins: [Vue.component(''), {} as ComponentOptions<Vue>],
  287. name: 'Component',
  288. extends: {} as ComponentOptions<Vue>,
  289. delimiters: ['${', '}']
  290. })
  291. Vue.component('custom-prop-type-function', {
  292. props: {
  293. callback: Function as PropType<(confirm: boolean) => void>
  294. },
  295. methods: {
  296. confirm() {
  297. this.callback(true)
  298. }
  299. }
  300. })
  301. Vue.component('provide-inject', {
  302. provide: {
  303. foo: 1
  304. },
  305. inject: {
  306. injectFoo: 'foo',
  307. injectBar: Symbol(),
  308. injectBaz: { from: 'baz' },
  309. injectQux: { default: 1 },
  310. injectQuux: { from: 'quuz', default: () => ({ value: 1 }) }
  311. }
  312. })
  313. Vue.component('provide-function', {
  314. provide: () => ({
  315. foo: 1
  316. })
  317. })
  318. Vue.component('component-with-slot', {
  319. render(h): VNode {
  320. return h('div', this.$slots.default)
  321. }
  322. })
  323. Vue.component('component-with-scoped-slot', {
  324. render(h) {
  325. interface ScopedSlotProps {
  326. msg: string
  327. }
  328. return h('div', [
  329. h('child', [
  330. // default scoped slot as children
  331. (props: ScopedSlotProps) => [h('span', [props.msg])]
  332. ]),
  333. h('child', {
  334. scopedSlots: {
  335. // named scoped slot as vnode data
  336. item: (props: ScopedSlotProps) => [h('span', [props.msg])]
  337. }
  338. }),
  339. h('child', [
  340. // return single VNode (will be normalized to an array)
  341. (props: ScopedSlotProps) => h('span', [props.msg])
  342. ]),
  343. h('child', {
  344. // Passing down all slots from parent
  345. scopedSlots: this.$scopedSlots
  346. }),
  347. h('child', {
  348. // Passing down single slot from parent
  349. scopedSlots: {
  350. default: this.$scopedSlots.default
  351. }
  352. })
  353. ])
  354. },
  355. components: {
  356. child: {
  357. render(this: Vue, h: CreateElement) {
  358. const defaultSlot = this.$scopedSlots['default']!({ msg: 'hi' })
  359. defaultSlot &&
  360. defaultSlot.forEach(vnode => {
  361. vnode.tag
  362. })
  363. return h('div', [
  364. defaultSlot,
  365. this.$scopedSlots['item']!({ msg: 'hello' })
  366. ])
  367. }
  368. }
  369. }
  370. })
  371. Vue.component('narrow-array-of-vnode-type', {
  372. render(h): VNode {
  373. const slot = this.$scopedSlots.default!({})
  374. if (typeof slot === 'string') {
  375. // <template slot-scope="data">bare string</template>
  376. return h('span', slot)
  377. } else if (Array.isArray(slot)) {
  378. // template with multiple children
  379. const first = slot[0]
  380. if (!Array.isArray(first) && typeof first !== 'string' && first) {
  381. return first
  382. } else {
  383. return h()
  384. }
  385. } else if (slot) {
  386. // <div slot-scope="data">bare VNode</div>
  387. return slot
  388. } else {
  389. // empty template, slot === undefined
  390. return h()
  391. }
  392. }
  393. })
  394. Vue.component('functional-component', {
  395. props: ['prop'],
  396. functional: true,
  397. inject: ['foo'],
  398. render(createElement, context) {
  399. context.props
  400. context.children
  401. context.slots()
  402. context.data
  403. context.parent
  404. context.scopedSlots
  405. context.listeners.click
  406. return createElement('div', {}, context.children)
  407. }
  408. })
  409. Vue.component('functional-component-object-inject', {
  410. functional: true,
  411. inject: {
  412. foo: 'foo',
  413. bar: Symbol(),
  414. baz: { from: 'baz' },
  415. qux: { default: 1 },
  416. quux: { from: 'quuz', default: () => ({ value: 1 }) }
  417. },
  418. render(h) {
  419. return h('div')
  420. }
  421. })
  422. Vue.component('functional-component-check-optional', {
  423. functional: true
  424. })
  425. Vue.component('functional-component-multi-root', {
  426. functional: true,
  427. render(h) {
  428. return [
  429. h('tr', [h('td', 'foo'), h('td', 'bar')]),
  430. h('tr', [h('td', 'lorem'), h('td', 'ipsum')])
  431. ]
  432. }
  433. })
  434. Vue.component('async-component', (resolve, reject) => {
  435. setTimeout(() => {
  436. resolve(Vue.component('component'))
  437. }, 0)
  438. return new Promise(resolve => {
  439. resolve({
  440. functional: true,
  441. render(h: CreateElement) {
  442. return h('div')
  443. }
  444. })
  445. })
  446. })
  447. Vue.component('functional-component-v-model', {
  448. props: ['foo'],
  449. functional: true,
  450. model: {
  451. prop: 'foo',
  452. event: 'change'
  453. },
  454. render(createElement, context) {
  455. return createElement('input', {
  456. on: {
  457. input: new Function()
  458. },
  459. domProps: {
  460. value: context.props.foo
  461. }
  462. })
  463. }
  464. })
  465. Vue.component('async-es-module-component', () => import('./es-module'))
  466. Vue.component('directive-expression-optional-string', {
  467. render(createElement) {
  468. return createElement('div', {
  469. directives: [
  470. {
  471. name: 'has-expression',
  472. value: 2,
  473. expression: '1 + 1'
  474. },
  475. {
  476. name: 'no-expression',
  477. value: 'foo'
  478. }
  479. ]
  480. })
  481. }
  482. })