Gathering detailed insights and metrics for vue-tsx-support
Gathering detailed insights and metrics for vue-tsx-support
Gathering detailed insights and metrics for vue-tsx-support
Gathering detailed insights and metrics for vue-tsx-support
@vitejs/plugin-vue-jsx
Provides Vue 3 JSX & TSX support with HMR.
@vitejs/plugin-vue2-jsx
Provides Vue 2 JSX & TSX support with HMR.
vue-cli-plugin-tsx-support
Enable TSX support for Vue.js
@rsbuild/plugin-vue-jsx
Provides support for Vue 3 JSX / TSX syntax. This plugin internally integrates [@vue/babel-plugin-jsx](https://github.com/vuejs/babel-plugin-jsx).
npm install vue-tsx-support
Typescript
Module System
67
Supply Chain
99.6
Quality
76.2
Maintenance
100
Vulnerability
99.6
License
TypeScript (98.4%)
JavaScript (1.6%)
Total Downloads
0
Last Day
0
Last Week
0
Last Month
0
Last Year
0
MIT License
579 Stars
335 Commits
39 Forks
4 Watchers
14 Branches
8 Contributors
Updated on Nov 09, 2024
Latest Version
3.2.0
Package Id
vue-tsx-support@3.2.0
Size
26.91 kB
Published on
Jun 19, 2021
Cumulative downloads
Total Downloads
Last Day
0%
NaN
Compared to previous day
Last Week
0%
NaN
Compared to previous week
Last Month
0%
NaN
Compared to previous month
Last Year
0%
NaN
Compared to previous year
2
24
TSX (JSX for TypeScript) support library for Vue
If your project already uses vue-tsx-support v2, see Migration from V2 section.
Vue >= 2.6.0, < 3.0.0
TypeScript >= 3.8.0 (3.9.2 or later recommended)
vue-tsx-support
does not support Vue 3 because Vue 3 has it's own JSX type checker and there are some incompatibilities with Vue 2.
If you want to use composition API with vue-tsx-support
, you can use @vue/composition-api.
Create Vue project with TypeScript and babel support.
vue-tsx-support is a type checker for TypeScript, not a transpiler.
You must install babel presets (@vue/babel-preset-app or @vue/babel-preset-jsx) separatedly.
Vue CLI may help you.
:bulb: If you want use @vue/composition-api, @vue/babel-preset-jsx
>= 1.2.1 or babel-preset-vue-vca is needed.
Install vue-tsx-support from npm
yarn add vue-tsx-support -D
In tsconfig.json
, set "preserve"
to jsx
and "VueTsxSupport"
to jsxFactory
1{ 2 "compilerOptions": { 3 "jsx": "preserve", 4 "jsxFactory": "VueTsxSupport", 5 "...": "..." 6 }, 7 "include": [ 8 "..." 9 ] 10}
import vue-tsx-support/enable-check.d.ts
somewhere,
1import "vue-tsx-support/enable-check"
or add it to "include" in tsconfig.json
1{ 2 "compilerOptions": { 3 "...": "..." 4 }, 5 "include": [ 6 "node_modules/vue-tsx-support/enable-check.d.ts", 7 "..." 8 ] 9}
In tsconfig.json
, set "VueTsxSupport"
to jsxFactory
Enable allow-props-object
option (Optional)
Standard HTML elements are defined as intrinsic elements. So, compiler can check attribute names and attribute types of them:
1// OK 2<div id="title" />; 3// OK 4<input type="number" min={ 0 } max={ 100 } />; 5// OK 6<a href={ SOME_LINK } />; 7// NG: because `href` is not a valid attribute of `div` 8<div href={ SOME_LINK } />; 9// NG: because `id` must be a string 10<div id={ 1 } />;
Lower case tags are treated as unknown intrinsic element. TypeScript checks nothing for such tags.
1// OK 2<foo id="unknown" unknownattr={ 1 } />
Basically, vue-tsx-support
checks three types for each component.
Prop types
Determine name, type, and required or optional of each props.
When using existing component as-is, you must specify prop types manually.
When writing component with APIs of vue-tsx-support
, prop types are automatically obtained from component definition.
Custom event types (optional)
If the component has custom events, you can specify custom event types additionally,
and vue-tsx-support
will check if event names and argument types are correct or not.
Scoped slot types (optional)
If the component has uses scoped slots, you can specify scoped slot types additionally,
and vue-tsx-support
will check if scoped slot names and argument types are correct or not.
By default, vue-tsx-support
does not allow unknown props.
For example, below code causes compilation error.
1import Vue from "vue"; 2import AwesomeButton from "third-party-library/awesome-button"; 3 4export default Vue.extend({ 5 render() { 6 // ERROR: because TypeScript does not know that AwesomeButton has 'text' prop. 7 return <AwesomeButton text="Click Me!" />; 8 } 9});
You can add type information to existing component without modifying component itself, like below:
1import AwesomeButtonOrig from "third-party-library/awesome-button"; 2import * as tsx from "vue-tsx-support"; 3 4type AwesomeButtonProps = { 5 text: string; 6 raised?: boolean; 7 rounded?: boolean; 8} 9 10// Now, AwesomeButton has 1 required prop(text) and 2 optional props(raised, rounded) 11export const AwesomeButton = tsx.ofType<AwesomeButtonProps>().convert(AwesomeButtonOrig);
You also can specify custom event types as second type parameter, and scoped slot types as third type parameter.
For example:
1import AwesomeListOrig from "third-party-library/awesome-list"; 2import * as tsx from "vue-tsx-support"; 3 4type Item = { id: string, text: string }; 5 6type AwesomeListProps = { 7 items: ReadonlyArray<Item>; 8 rowHeight: number; 9} 10 11type AwesomeListEvents = { 12 // member name must be ['on' + event name(with capitalizing first charactor)] 13 onRowClicked: { item: Item, index: number }; 14} 15 16type AwesomeListScopedSlots = { 17 row: { item: Item } 18} 19 20export const AwesomeList = tsx.ofType< 21 AwesomeListProps, 22 AwesomeListEvents, 23 AwesomeListScopedSlots 24>().convert(AwesomeListOrig);
Then you can use AwesomeList like below:
1import { VNode } from "vue"; 2const App = Vue.extend({ 3render(): VNode { 4 return ( 5 <AwesomeList 6 items={this.items} 7 rowHeight={32} 8 onRowClicked={p => console.log(`${p.item.text} clicked!`)} 9 scopedSlots={{ 10 row: item => <div>{item.text}</div> 11 }} 12 /> 13 ); 14} 15});
Vue.extend
)If you use Vue.extend()
, just replace it by componentFactory.create
and your component becomes TSX-ready.
Props type is infered from props definition automatically.
For example, props type will be { text: string, important?: boolean }
in below code.
:warning: In some environment, as const
may be needed to make prop required properly.
1import { VNode } from "vue"; 2import * as tsx from "vue-tsx-support"; 3const MyComponent = tsx.componentFactory.create({ 4 props: { 5 text: { type: String, required: true }, 6 important: Boolean, 7 } as const, // `as const` is needed in some cases. 8 computed: { 9 className(): string { 10 return this.important ? "label-important" : "label-normal"; 11 } 12 }, 13 methods: { 14 onClick(event: Event) { this.$emit("ok", event); } 15 }, 16 render(): VNode { 17 return <span class={this.className} onClick={this.onClick}>{this.text}</span>; 18 } 19});
:bulb: You can use component
as as shorthand of componentFactory.create
.
1import * as tsx from "vue-tsx-support"; 2const MyComponent = tsx.component({ 3 /* snip */ 4});
If your component has custom events or scoped slots, use componentFactoryOf
instead.
1import { VNode } from "vue"; 2import * as tsx from "vue-tsx-support"; 3 4type AwesomeListEvents = { 5 onRowClicked: { item: {}, index: number }; 6} 7 8type AwesomeListScopedSlots = { 9 row: { item: {} } 10} 11 12export const AwesomeList = tsx.componentFactoryOf< 13 AwesomeListEvents, 14 AwesomListScopedSlots 15>().create({ 16 name: "AwesomeList", 17 props: { 18 items: { type: Array, required: true }, 19 rowHeight: { type: Number, required: true } 20 }, 21 computed: { /* ... */}, 22 method: { 23 emitRowClicked(item: {}, index: number): void { 24 // Equivalent to `this.$emit("rowClicked", { item, index })`, 25 // And event name and payload type are statically checked. 26 tsx.emitOn(this, "onRowClicked", { item, index }); 27 } 28 }, 29 render(): VNode { 30 return ( 31 <div class={style.container}> 32 { 33 this.visibleItems.map((item, index) => ( 34 <div style={this.rowStyle} onClick={() => this.$emit("rowClicked", { item, index })}> 35 { 36 // slot name ('row') and argument types are statically checked. 37 this.$scopedSlots.row({ item }) 38 } 39 <div> 40 ) 41 } 42 </div> 43 ); 44 } 45});
vue-class-component
and/or vue-property-decorator
)If you prefer class-style component by using vue-class-component
and/or vue-property-decorator
,
there are some options to make it tsx-ready.
Component
class provided by vue-tsx-support
1import { VNode } from "vue"; 2import { Component, Prop } from "vue-property-decorator"; 3import * as tsx from "vue-tsx-support"; 4 5type MyComponentProps = { 6 text: string; 7 important?: boolean; 8} 9 10@Component 11export class MyComponent extends tsx.Component<MyComponentProps> { 12 @Prop({ type: String, required: true }) 13 text!: string; 14 @Prop(Boolean) 15 important?: boolean; 16 17 get className() { 18 return this.important ? "label-important" : "label-normal"; 19 } 20 onClick(event: MouseEvent) { 21 this.$emit("ok", event); 22 } 23 render(): VNode { 24 return <span class={this.className} onClick={this.onClick}>{this.text}</span>; 25 } 26}
:warning: Unfortunately, vue-tsx-support
can't infer prop types automatically in this case, so you must write type manually.
_tsx
field to tell type information to TypeScript.1import { VNode } from "vue"; 2import { Component, Prop } from "vue-property-decorator"; 3import * as tsx from "vue-tsx-support"; 4 5@Component 6export class MyComponent extends Vue { 7 _tsx!: { 8 // specify props type to `props`. 9 props: Pick<MyComponent, "text" | "important"> 10 }; 11 12 @Prop({ type: String, required: true }) 13 text!: string; 14 @Prop(Boolean) 15 important?: boolean; 16 17 get className() { 18 return this.important ? "label-important" : "label-normal"; 19 } 20 render(): VNode { 21 return <span class={this.className}>{this.text}</span>; 22 } 23}
You can use DeclareProps<T>
instead of { props: T }
.
1import { Component, Prop } from "vue-property-decorator"; 2import * as tsx from "vue-tsx-support"; 3 4@Component 5export class MyComponent extends Vue { 6 _tsx!: tsx.DeclareProps<Pick<MyComponent, "text" | "important">>; 7 8 /* ...snip... */ 9}
:bulb: PickProps
is more convenient than Pick
here, it removes attributes from Vue
from completion candidates. (e.g. $data
, $props
, and so on)
1import { Component, Prop } from "vue-property-decorator"; 2import * as tsx from "vue-tsx-support"; 3 4@Component 5export class MyComponent extends Vue { 6 _tsx!: tsx.DeclareProps<tsx.PickProps<MyComponent, "text" | "important">>; 7 8 /* ...snip... */ 9}
:bulb: When you can make all data, computed and methods private, you can use AutoProps
instead.
AutoProps
picks all public members other than members from component options(render
, created
etc).
1import { Component, Prop } from "vue-property-decorator"; 2import * as tsx from "vue-tsx-support"; 3 4@Component 5export class MyComponent extends Vue { 6 _tsx!: tsx.DeclareProps<tsx.AutoProps<MyComponent>> 7 8 @Prop({ type: String, required: true }) 9 text!: string; 10 11 @Prop(Boolean) 12 important?: boolean; 13 14 // data 15 private count = 0; 16 // computed 17 private get className() { 18 return this.important ? "label-important" : "label-normal"; 19 } 20 // methods 21 private onClick() { 22 this.count += 1; 23 } 24 25 render(): VNode { 26 return ( 27 <span class={this.className} onClick={this.onClick}> 28 {`${this.text}-${this.count}`} 29 </span> 30 ); 31 } 32}
:bulb: If your component has custom events, you can specify events handlers type additionally.
1import { Component, Prop } from "vue-property-decorator"; 2import * as tsx from "vue-tsx-support"; 3 4@Component 5export class MyComponent extends Vue { 6 _tsx!: tsx.DeclareProps<PickProps<MyComponent, "text" | "important">> & 7 tsx.DeclareOnEvents<{ onOk: string }>; 8 9 /* ...snip... */ 10}
:bulb: If your component uses scoped slots, you should add type to $scopedSlots
by tsx.InnerScopedSlots
.
1import { Component, Prop } from "vue-property-decorator"; 2import * as tsx from "vue-tsx-support"; 3 4@Component 5export class MyComponent extends Vue { 6 _tsx!: tsx.DeclareProps<PickProps<MyComponent, "text" | "important">>; 7 8 $scopedSlots!: tsx.InnerScopedSlots<{ default?: string }>; 9 10 /* ...snip... */ 11}
@vue/composition-api
)Vue 3 is not supported.
To use composition api with Vue 2, You can use @vue/composition-api
.
There are 2 babel presets which support JSX syntax with @vue/composition-api
.
@vue/babel-preset-jsx
>= 1.2.1 (You must enable composition-api support explicitly by specifying { compositionAPI: true }
)babel-preset-vca-jsx
To make TSX-ready component by composition api, use component
of vue-tsx-support/lib/vca
instead of defineComponent
of @vue/composition-api
.
1import { computed } from "@vue/composition-api"; 2import * as vca from "vue-tsx-support/lib/vca"; 3 4const MyComponent = vca.component({ 5 name: "MyComponent", 6 props: { 7 text: { type: String, required: true }, 8 important: Boolean, 9 }, 10 setup(p) { 11 const className = computed(() => p.important ? "label-important" : "label-normal"); 12 return () => ( 13 <span class={className.value}>{p.text}</span>; 14 ); 15 } 16});
If your component has custom event or scoped slots, specify them types in 2nd argument of setup
.
1import { computed, onMounted } from "@vue/composition-api"; 2import * as vca from "vue-tsx-support/lib/vca"; 3 4type AwesomeListEvents = { 5 onRowClicked: { item: {}, index: number }; 6} 7 8type AwesomeListScopedSlots = { 9 row: { item: {} } 10} 11 12export const AwesomeList = vca.component({ 13 name: "AwesomeList", 14 props: { 15 items: { type: Array, required: true }, 16 rowHeight: { type: Number, required: true } 17 }, 18 setup(p, ctx: vca.SetupContext<AwesomeListEvents, AwesomeListScopedSlots>) { 19 const visibleItems = computed(() => ... ); 20 const emitRowClicked = (item: {}, index: number) => { 21 // Equivalent to `ctx.emit("rowClicked", { item, index })`, 22 // And event name and payload type are statically checked. 23 vca.emitOn(ctx, "onRowClicked", { item, index }); 24 } 25 26 return () => ( 27 <div class={style.container}> 28 { 29 visibleItems.value.map((item, index) => ( 30 <div onClick={() => emitRowClicked(item, index)}> 31 { 32 // slot name ('row') and argument types are statically checked. 33 ctx.slots.row({ item }) 34 } 35 <div> 36 ) 37 } 38 </div> 39 ); 40 } 41});
vue-tsx-support
has some options which change behaviour globally.
See under the options
directory.
To enable each options, import them somewhere
1// enable `allow-unknown-props` option 2import "vue-tsx-support/options/allow-unknown-props";
:warning: Scope of option is whole project, not a file.
Make enabled to specify unknown attributes to intrinsic elements
1// OK:`foo` is unknown attribute, but can be compiled 2<div foo="foo" />;
Make enabled to specify unknown props to Vue component.
1const MyComponent = vuetsx.createComponent<{ foo: string }>({ /* ... */ }); 2// OK: `bar` is unknown prop, but can be compiled 3<MyComponent foo="foo" bar="bar" />;
Make enabled to specify HTML attributes to Vue component.
1const MyComponent = vuetsx.createComponent<{ foo: string }>({ /* ... */ }); 2// OK: `min` and `max` are valid HTML attributes 3<MyComponent foo="foo" min={ 0 } max={ 100 } />; 4// NG: compiler checks type of `min` (`min` must be number) 5<MyComponent foo="foo" min="a" />;
Make enabled to specify native event listeners to Vue component.
1const MyComponent = vuetsx.createComponent<{ foo: string }>({ /* ... */ }); 2// OK 3<MyComponent foo="foo" nativeOnClick={ e => ... } />; // and `e` is infered as MouseEvent
Add definitions of router-link
and router-view
Make enabled to pass props as "props".
1const MyComponent = vuetsx.createComponent<{ foo: string }>({ /* ... */ }); 2// OK 3<MyComponent props={{ foo: "foo" }} />;
Event handler wrappers which work like some event modifiers available in template
1import { modifiers as m } from "vue-tsx-support"; 2 3// Basic usage: 4// Equivalent to `<div @keydown.enter="onEnter" />` 5<div onKeydown={m.enter(this.onEnter)} />; 6 7// Use multiple modifiers: 8// Equivalent to `<div @keydown.enter.prevent="onEnter" />` 9<div onKeydown={m.enter.prevent(this.onEnter)} />; 10 11// Use without event handler: 12// Equivalent to `<div @keydown.esc.prevent />` 13<div onKeydown={m.esc.prevent} />; 14 15// Use multiple keys: 16// Equivalent to `<div @keydown.enter.esc="onEnterOrEsc" />` 17<div onKeydown={m.keys("enter", "esc")(this.onEnterOrEsc)} />; 18 19// Use exact modkey combination: 20// Equivalent to `<div @keydown.65.ctrl.alt.exact="onCtrlAltA" />` 21<div onKeydown={m.keys(65).exact("ctrl", "alt")(this.onCtrlAltA)} />;
esc
, tab
, enter
, space
, up
, down
, del
, left
, right
Execute event handler only when specified key is pressed.
:warning: del
allows not only DELETE, but also BACKSPACE.
:warning: left
and right
have another behavior when specified to mouse event
:warning: combination of key modifiers (e.g. m.enter.esc
) does not work. See keys
left
, right
, middle
Execute event handler only when specified mouse button is pressed.
:warning: left
and right
have another behavior when specified to keyboard event
ctrl
, shift
, alt
, meta
Execute event handler only when specified system modifier key is pressed.
noctrl
, noshift
, noalt
, nometa
Execute event handler only when specified system modifier key is not pressed.
self
Execute event handler only when event.target is the element itself (not from children).
prevent
, stop
Call preventDefault
or stopPropagation
of event object before executing event handler.
keys(...args)
Execute event handler only when one of specified key is pressed.
Known key name("esc", "tab", "enter", ...) or number can be specified.
1// when enter or esc pressed 2<div onKeydown={m.keys("enter", "esc")(handler)} />; 3// when 'a' pressed 4<div onKeydown={m.keys(65)(handler)} />;
exact(...args)
Execute event handler only when specified system modifier keys are all pressed, and others are not pressed.
1// when CTRL, SHIFT are both pressed, and ALT, META are both not pressed 2<div onClick={m.exact("ctrl", "shift")(handler)} />;
MIT
No vulnerabilities found.
Reason
no dangerous workflow patterns detected
Reason
no binaries found in the repo
Reason
license file detected
Details
Reason
0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Reason
detected GitHub workflow tokens with excessive permissions
Details
Reason
Found 1/15 approved changesets -- score normalized to 0
Reason
dependency not pinned by hash detected -- score normalized to 0
Details
Reason
no effort to earn an OpenSSF best practices badge detected
Reason
security policy file not detected
Details
Reason
project is not fuzzed
Details
Reason
branch protection not enabled on development/release branches
Details
Reason
SAST tool is not run on all commits -- score normalized to 0
Details
Reason
21 existing vulnerabilities detected
Details
Score
Last Scanned on 2025-07-07
The Open Source Security Foundation is a cross-industry collaboration to improve the security of open source software (OSS). The Scorecard provides security health metrics for open source projects.
Learn More