<commit_before>[![Build Status](https://travis-ci.org/wonderful-panda/vue-tsx-support.svg?branch=master)](https://travis-ci.org/wonderful-panda/vue-tsx-support)

# vue-tsx-support
TSX (JSX for TypeScript) support library for Vue

## Caution: BREAKING CHANGE
v1.0.0:
- Support Vue >= 2.5 only.
- `createComponent` is deprecated. use [componentFactory](#componentFactory) or [component](#component) instead.

v0.5.0:
- Rename `extend` to `extendFrom` (undocumented api)
v0.4.0:
- The way to enable compiler check has changed. See [Install and enable](#Install-and-enable)

## Install and enable

Install from npm:

```
npm install vue-tsx-support -S
```

And refer `vue-tsx-support/enable-check.d.ts` from somewhere to enable compiler check. (**CHANGED since v0.4.0**)

```typescript
///<reference path="node_modules/vue-tsx-support/enable-check.d.ts" />
// or
import "vue-tsx-support/enable-check"
```

or in `tsconfig.json`

```json
{
  compilerOptions: {
    ...
  },
  include: [
    ...,
    "node_modules/vue-tsx-support/enable-check.d.ts"
  ]
}
```

## Using intrinsic elements

Standard HTML elements are defined as intrinsic elements.
So, compiler can check attribute names and attribute types of them:

```jsx
// OK
<div id="title" />;
// OK
<input type="number" min={ 0 } max={ 100 } />;
// OK
<a href={ SOME_LINK } />;
// NG: because `href` is not a valid attribute of `div`
<div href={ SOME_LINK } />;
// NG: because `id` must be a number
<div id={ 1 } />;
```

## Using custom component

By default, `vue-tsx-support` does not allow unknown props.

For example, if you have this component :

```typescript
import Vue from "vue";

const MyComponent = Vue.extend({
    props: {
        text: { type: String, required: true },
        important: Boolean,
    },
    computed: {
        className() {
            return this.important ? "label-important" : "label-normal";
        }
    },
    methods: {
        onClick(event) { this.$emit("ok", event); }
    },
    template: "<span :class='className' @click='onClick'>{{ text }}</span>"
});
```

Below code will cause compilation error because compiler does not know
`MyComponent` has prop `text`.

```jsx
// Compilation error(TS2339): Property `text` does not exist on type '...'
<MyComponent text="foo" />;
```

You must add types to the component by apis memtions below, or enable `allow-unknown-props` option.

### available APIs to add type information

#### componentFactory

Create tsx-supported component from component options. (Partially compatible with `Vue.extend`)

##### Usage

```jsx
import * as tsx from "vue-tsx-support";
const MyComponent = tsx.componentFactory.create({
    props: {
        text: { type: String, required: true },
        important: Boolean,
    },
    computed: {
        className(): string {
            return this.important ? "label-important" : "label-normal";
        }
    },
    methods: {
        onClick(event) { this.$emit("ok", event); }
    },
    render(): VNode {
        return <span class={this.className} onClick={this.onClick}>{this.text}</span>;
    }
});
```

`componentFactory.create` can infer types of props from component options same as `Vue.extend`.
In the above example, props type will be `{ text?: string, important?: boolean }`.

NOTE: all props are regarded as optional even if `required: true` specified.

```jsx
// both `text` and `important` are regarded as optional
// So below 3 cases are all valid.
<MyComponent />;
<MyComponent text="foo" />;
<MyComponent important={true} />;
```

If you want to make some props required, you must specify required prop names as second parameter.

```typescript
import * as tsx from "vue-tsx-support";
const MyComponent = tsx.componentFactory.create({
    props: {
        text: { type: String, required: true },
        important: Boolean,
    },
    /* snip */
}, ["text"]);
```

In the above example, props type will be `{ text: string, important?: boolean }`.

```jsx
// NG: `text` is required
<MyComponent />;
// OK: `important` is optional
<MyComponent text="foo" />;
// OK
<MyComponent text="foo" important={true} />;
```

NOTE: shorthand props definition(like `props: ["foo", "bar"]`) is currently not supported.

```typescript
// Does not work
import * as tsx from "vue-tsx-support";
const MyComponent = tsx.componentFactory.create({
    props: ["text", "important"],
    /* snip */
}, ["text"]);
```

#### component
Shorthand of `componentFactory.create`

```typescript
import * as tsx from "vue-tsx-support";
const MyComponent = tsx.component({
    props: {
        text: { type: String, required: true },
        important: Boolean,
    },
    /* snip */
});
```

#### componentFactoryOf
Return componentFactory with additional types (events and scoped slots)

##### Usage
If your component has custom events, you may want to specify event listener.
But below example does not work.

```jsx
import * as tsx from "vue-tsx-support";

const MyComponent = tsx.component({
    render(): VNode {
        return <button onClick={this.$emit("ok")}>OK</button>;
    }
});

// Compilation error: 'onOK' is not a property of MyComponent
<MyComponent onOk={() => console.log("ok")} />;
```

In such situations, you must specify event types by `componentFactoryOf`

```typescript
import * as tsx from "vue-tsx-support";

interface Events {
    // all memebers must be prefixed by 'on'
    onOk: void;
    onError: { code: number, detail: string };
}

const MyComponent = tsx.componentFactoryOf<Events>().create({
    render(): VNode {
        return (
            <div>
              <button onClick={() => this.$emit("ok")}>OK</button>
              <button onClick={() => this.$emit("error", { code: 9, detail: "unknown" })}>Raise Error</button>
            </div>
        );
    }
});

// OK
<MyComponent onOk={() => console.log("ok")} />;
<MyComponent onError={p => console.log("ng", p.code, p.detail)} />;
```

You can also specify types of scoped slots if your component uses it.

```typescript
import * as tsx from "vue-tsx-support";

interface ScopedSlots {
    default: { text: string };
}

const MyComponent = tsx.componentFactoryOf<{}, ScopedSlots>().create({
    props: {
        text: String
    },
    render(): VNode {
        // type of `$scopedSlots` is checked statically
        return <div>
                 { this.$scopedSlots.default({ text: this.text || "default text" }) }
               </div>;
    }
});

// type of `scopedSlots` is checked statically, too
<MyComponent scopedSlots={{
        default: p => [<span>p.text</span>]
    }}
/>;

// NG: 'default' is missing in scopedSlots
<MyComponent scopedSlots={{
        defualt: p => [<span>p.text</span>]
    }}
/>;
```

#### Component
Base class of class base component

##### Usage

If you write your component with `vue-class-component`,
you can it tsx-supported by extending from this class.

```typescript
import component from "vue-class-component";
import * as tsx from "vue-tsx-support";

interface MyComponentProps {
    text: string;
    important?: boolean;
}

@component({
    props: {
        text: { type: String, required: true },
        important: Boolean
    },
    /* snip */
})
class MyComponent extends tsx.Component<MyComponentProps> {
    /* snip */
}
```

Unfortunately, you must write props interface and props definition separately.

If you want, you can specify event types and scoped slot types as 2nd and 3rd type parameter

```typescript
import component from "vue-class-component";
import * as tsx from "vue-tsx-support";

interface MyComponentProps {
    text: string;
    important?: boolean;
}

interface Events {
    onOk: void;
    onError: { code: number, detail: string };
}

interface ScopedSlots {
    default: { text: string };
}


@component({
    props: {
        text: { type: String, required: true },
        important: Boolean
    },
    /* snip */
})
class MyComponent extends tsx.Component<MyComponentProps, Events, ScopedSlots> {
    /* snip */
}
```

#### ofType

Make existing component tsx-supported.

##### Usage

If you can't modify existing component definition, wrap it by `ofType` and `convert`

```typescript
import ThirdPartyComponent from "third-party-library";
import * as tsx from "vue-tsx-support";

interface MyComponentProps { /* ... */ }

const MyComponent = tsx.ofType<MyComponentProps>().convert(ThirdPartyComponent);
```

Of course you can specify event types and scoped slot types if you want.

```typescript
const MyComponent = tsx.ofType<MyComponentProps, Events, ScopedSlots>().convert(ThirdPartyComponent);
```

### Other attributes

#### Native event listeners and dom properties

Sometimes you may want to specify native event listener or dom property to the component like below.
But unfortunately, `vue-tsx-support` does not support this.

```jsx
// NG: because `nativeOnClick` is not a prop of MyComponent
<MyComponent text="foo" nativeOnClick={ ... } />
// NG: because `domPropInnerHTML` is not a prop of MyComponent
<MyComponent text="foo" domPropInnerHTML={ ... } />
```

To avoid compilation error, you must use kebab-case attribute name.

```jsx
// OK
<Component nativeOn-click={ ... } />
// OK
<Component domProp-innerHTML={ ... } />
```

Or use JSX-spread style.

```jsx
// OK
<Component { ...{ nativeOn: { click: ... } } } />
// OK
<Component { ...{ domProps: { innerHTML: ... } } } />
```

For native events, there is an another solution. See `enable-nativeon` option.

#### HTML attributes attached to the root element

And sometimes, you may want to specify HTML attributes to the component like below.
But unfortunately, `vue-tsx-support` does not support this, too.

```jsx
// NG: because `min` and `max` are not props of SomeInputComponent
<SomeInputComponent min={ 0 } max={ 100 } />
```

To avoid compilation error, you must use JSX-spread style.

```jsx
// OK
<SomeInputComponent { ...{ attrs: { min: 0, max: 100 } } } />
```

Or enable `enable-html-attributes` option.

## Options

`vue-tsx-support` has some options which change behaviour globally.
See under the `options` directory.

To enable each options, import them somewhere

```typescript
// enable `allow-unknown-props` option
import "vue-tsx-support/options/allow-unknown-props";
```

NOTE: Scope of option is whole project, not a file.

### allow-element-unknown-attrs

Make enabled to specify unknown attributes to intrinsic elements

```jsx
// OK:`foo` is unknown attribute, but can be compiled
<div foo="foo" />;
```

### allow-unknown-props

Make enabled to specify unknown props to Vue component.

```jsx
const MyComponent = vuetsx.createComponent<{ foo: string }>({ /* ... */ });
// OK: `bar` is unknown prop, but can be compiled
<MyComponent foo="foo" bar="bar" />;
```

### enable-html-attrs

Make enabled to specify HTML attributes to Vue component.

```jsx
const MyComponent = vuetsx.createComponent<{ foo: string }>({ /* ... */ });
// OK: `min` and `max` are valid HTML attributes
<MyComponent foo="foo" min={ 0 } max={ 100 } />;
// NG: compiler checks type of `min` (`min` must be number)
<MyComponent foo="foo" min="a" />;
```

### enable-nativeon

Make enabled to specify native event listeners to Vue component.

```jsx
const MyComponent = vuetsx.createComponent<{ foo: string }>({ /* ... */ });
// OK
<MyComponent foo="foo" nativeOnClick={ e => ... } />; // and `e` is infered as MouseEvent
```

### enable-vue-router

Add definitions of `router-link` and `router-view`


## LICENSE
MIT
<commit_msg>trivial fixes in README<commit_after>[![Build Status](https://travis-ci.org/wonderful-panda/vue-tsx-support.svg?branch=master)](https://travis-ci.org/wonderful-panda/vue-tsx-support)

# vue-tsx-support
TSX (JSX for TypeScript) support library for Vue

## Caution: BREAKING CHANGE
v1.0.0:
- Support Vue >= 2.5 only.
- `createComponent` is deprecated. use [componentFactory](#componentfactory) or [component](#component) instead.

v0.5.0:
- Rename `extend` to `extendFrom` (undocumented api)
v0.4.0:
- The way to enable compiler check has changed. See [Install and enable](#Install-and-enable)

## Install and enable

Install from npm:

```
npm install vue-tsx-support -S
```

And refer `vue-tsx-support/enable-check.d.ts` from somewhere to enable compiler check. (**CHANGED since v0.4.0**)

```typescript
///<reference path="node_modules/vue-tsx-support/enable-check.d.ts" />
// or
import "vue-tsx-support/enable-check"
```

or in `tsconfig.json`

```json
{
  "compilerOptions": {
    "...snip...": "...snip..."
  },
  "include": [
    "node_modules/vue-tsx-support/enable-check.d.ts",
    "...snip..."
  ]
}
```

## Using intrinsic elements

Standard HTML elements are defined as intrinsic elements.
So, compiler can check attribute names and attribute types of them:

```jsx
// OK
<div id="title" />;
// OK
<input type="number" min={ 0 } max={ 100 } />;
// OK
<a href={ SOME_LINK } />;
// NG: because `href` is not a valid attribute of `div`
<div href={ SOME_LINK } />;
// NG: because `id` must be a number
<div id={ 1 } />;
```

## Using custom component

By default, `vue-tsx-support` does not allow unknown props.

For example, if you have this component :

```typescript
import Vue from "vue";

const MyComponent = Vue.extend({
    props: {
        text: { type: String, required: true },
        important: Boolean,
    },
    computed: {
        className() {
            return this.important ? "label-important" : "label-normal";
        }
    },
    methods: {
        onClick(event) { this.$emit("ok", event); }
    },
    template: "<span :class='className' @click='onClick'>{{ text }}</span>"
});
```

Below code will cause compilation error because compiler does not know
`MyComponent` has prop `text`.

```jsx
// Compilation error(TS2339): Property `text` does not exist on type '...'
<MyComponent text="foo" />;
```

You must add types to the component by apis memtions below, or enable `allow-unknown-props` option.

### available APIs to add type information

#### componentFactory

Create tsx-supported component from component options. (Partially compatible with `Vue.extend`)

##### Usage

```jsx
import * as tsx from "vue-tsx-support";
const MyComponent = tsx.componentFactory.create({
    props: {
        text: { type: String, required: true },
        important: Boolean,
    },
    computed: {
        className(): string {
            return this.important ? "label-important" : "label-normal";
        }
    },
    methods: {
        onClick(event) { this.$emit("ok", event); }
    },
    render(): VNode {
        return <span class={this.className} onClick={this.onClick}>{this.text}</span>;
    }
});
```

`componentFactory.create` can infer types of props from component options same as `Vue.extend`.
In the above example, props type will be `{ text?: string, important?: boolean }`.

NOTE: all props are regarded as optional even if `required: true` specified.

```jsx
// both `text` and `important` are regarded as optional
// So below 3 cases are all valid.
<MyComponent />;
<MyComponent text="foo" />;
<MyComponent important={true} />;
```

If you want to make some props required, you must specify required prop names as second parameter.

```typescript
import * as tsx from "vue-tsx-support";
const MyComponent = tsx.componentFactory.create({
    props: {
        text: { type: String, required: true },
        important: Boolean,
    },
    /* snip */
}, ["text"]);
```

In the above example, props type will be `{ text: string, important?: boolean }`.

```jsx
// NG: `text` is required
<MyComponent />;
// OK: `important` is optional
<MyComponent text="foo" />;
// OK
<MyComponent text="foo" important={true} />;
```

NOTE: shorthand props definition(like `props: ["foo", "bar"]`) is currently not supported.

```typescript
// Does not work
import * as tsx from "vue-tsx-support";
const MyComponent = tsx.componentFactory.create({
    props: ["text", "important"],
    /* snip */
}, ["text"]);
```

#### component
Shorthand of `componentFactory.create`

```typescript
import * as tsx from "vue-tsx-support";
const MyComponent = tsx.component({
    props: {
        text: { type: String, required: true },
        important: Boolean,
    },
    /* snip */
});
```

#### componentFactoryOf
Return componentFactory with additional types (events and scoped slots)

##### Usage
If your component has custom events, you may want to specify event listener.
But below example does not work.

```jsx
import * as tsx from "vue-tsx-support";

const MyComponent = tsx.component({
    render(): VNode {
        return <button onClick={this.$emit("ok")}>OK</button>;
    }
});

// Compilation error: 'onOK' is not a property of MyComponent
<MyComponent onOk={() => console.log("ok")} />;
```

In such situations, you must specify event types by `componentFactoryOf`

```typescript
import * as tsx from "vue-tsx-support";

interface Events {
    // all memebers must be prefixed by 'on'
    onOk: void;
    onError: { code: number, detail: string };
}

const MyComponent = tsx.componentFactoryOf<Events>().create({
    render(): VNode {
        return (
            <div>
              <button onClick={() => this.$emit("ok")}>OK</button>
              <button onClick={() => this.$emit("error", { code: 9, detail: "unknown" })}>Raise Error</button>
            </div>
        );
    }
});

// OK
<MyComponent onOk={() => console.log("ok")} />;
<MyComponent onError={p => console.log("ng", p.code, p.detail)} />;
```

You can also specify types of scoped slots if your component uses it.

```typescript
import * as tsx from "vue-tsx-support";

interface ScopedSlots {
    default: { text: string };
}

const MyComponent = tsx.componentFactoryOf<{}, ScopedSlots>().create({
    props: {
        text: String
    },
    render(): VNode {
        // type of `$scopedSlots` is checked statically
        return <div>
                 { this.$scopedSlots.default({ text: this.text || "default text" }) }
               </div>;
    }
});

// type of `scopedSlots` is checked statically, too
<MyComponent scopedSlots={{
        default: p => [<span>p.text</span>]
    }}
/>;

// NG: 'default' is missing in scopedSlots
<MyComponent scopedSlots={{
        defualt: p => [<span>p.text</span>]
    }}
/>;
```

#### Component
Base class of class base component

##### Usage

If you write your component with `vue-class-component`,
you can it tsx-supported by extending from this class.

```typescript
import component from "vue-class-component";
import * as tsx from "vue-tsx-support";

interface MyComponentProps {
    text: string;
    important?: boolean;
}

@component({
    props: {
        text: { type: String, required: true },
        important: Boolean
    },
    /* snip */
})
class MyComponent extends tsx.Component<MyComponentProps> {
    /* snip */
}
```

Unfortunately, you must write props interface and props definition separately.

If you want, you can specify event types and scoped slot types as 2nd and 3rd type parameter

```typescript
import component from "vue-class-component";
import * as tsx from "vue-tsx-support";

interface MyComponentProps {
    text: string;
    important?: boolean;
}

interface Events {
    onOk: void;
    onError: { code: number, detail: string };
}

interface ScopedSlots {
    default: { text: string };
}


@component({
    props: {
        text: { type: String, required: true },
        important: Boolean
    },
    /* snip */
})
class MyComponent extends tsx.Component<MyComponentProps, Events, ScopedSlots> {
    /* snip */
}
```

#### ofType

Make existing component tsx-supported.

##### Usage

If you can't modify existing component definition, wrap it by `ofType` and `convert`

```typescript
import ThirdPartyComponent from "third-party-library";
import * as tsx from "vue-tsx-support";

interface MyComponentProps { /* ... */ }

const MyComponent = tsx.ofType<MyComponentProps>().convert(ThirdPartyComponent);
```

Of course you can specify event types and scoped slot types if you want.

```typescript
const MyComponent = tsx.ofType<MyComponentProps, Events, ScopedSlots>().convert(ThirdPartyComponent);
```

### Other attributes

#### Native event listeners and dom properties

Sometimes you may want to specify native event listener or dom property to the component like below.
But unfortunately, `vue-tsx-support` does not support this.

```jsx
// NG: because `nativeOnClick` is not a prop of MyComponent
<MyComponent text="foo" nativeOnClick={ ... } />
// NG: because `domPropInnerHTML` is not a prop of MyComponent
<MyComponent text="foo" domPropInnerHTML={ ... } />
```

To avoid compilation error, you must use kebab-case attribute name.

```jsx
// OK
<Component nativeOn-click={ ... } />
// OK
<Component domProp-innerHTML={ ... } />
```

Or use JSX-spread style.

```jsx
// OK
<Component { ...{ nativeOn: { click: ... } } } />
// OK
<Component { ...{ domProps: { innerHTML: ... } } } />
```

For native events, there is an another solution. See `enable-nativeon` option.

#### HTML attributes attached to the root element

And sometimes, you may want to specify HTML attributes to the component like below.
But unfortunately, `vue-tsx-support` does not support this, too.

```jsx
// NG: because `min` and `max` are not props of SomeInputComponent
<SomeInputComponent min={ 0 } max={ 100 } />
```

To avoid compilation error, you must use JSX-spread style.

```jsx
// OK
<SomeInputComponent { ...{ attrs: { min: 0, max: 100 } } } />
```

Or enable `enable-html-attributes` option.

## Options

`vue-tsx-support` has some options which change behaviour globally.
See under the `options` directory.

To enable each options, import them somewhere

```typescript
// enable `allow-unknown-props` option
import "vue-tsx-support/options/allow-unknown-props";
```

NOTE: Scope of option is whole project, not a file.

### allow-element-unknown-attrs

Make enabled to specify unknown attributes to intrinsic elements

```jsx
// OK:`foo` is unknown attribute, but can be compiled
<div foo="foo" />;
```

### allow-unknown-props

Make enabled to specify unknown props to Vue component.

```jsx
const MyComponent = vuetsx.createComponent<{ foo: string }>({ /* ... */ });
// OK: `bar` is unknown prop, but can be compiled
<MyComponent foo="foo" bar="bar" />;
```

### enable-html-attrs

Make enabled to specify HTML attributes to Vue component.

```jsx
const MyComponent = vuetsx.createComponent<{ foo: string }>({ /* ... */ });
// OK: `min` and `max` are valid HTML attributes
<MyComponent foo="foo" min={ 0 } max={ 100 } />;
// NG: compiler checks type of `min` (`min` must be number)
<MyComponent foo="foo" min="a" />;
```

### enable-nativeon

Make enabled to specify native event listeners to Vue component.

```jsx
const MyComponent = vuetsx.createComponent<{ foo: string }>({ /* ... */ });
// OK
<MyComponent foo="foo" nativeOnClick={ e => ... } />; // and `e` is infered as MouseEvent
```

### enable-vue-router

Add definitions of `router-link` and `router-view`


## LICENSE
MIT

{'fraction_non_alphanumeric': 0.1522631946871723, 'fraction_numerical': 0.0034078993358965396, 'mean_word_length': 3.4401551891367603, 'pattern_counts': {'":': 3, '<': 119, '<?xml version=': 0, '>': 137, 'https://': 4, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1388582', 'n_tokens_mistral': 7210, 'n_tokens_neox': 6951, 'n_words': 2322}