lit-elementでTypeScriptを試す

lit-elementというWeb Componentsを作るライブラリの公式にTypeScriptでの書き方が書いてあったので試してみる。

lit-element.polymer-project.org

package.json

  "devDependencies": {
    "ts-loader": "^6.0.4",
    "typescript": "^3.5.3",
    "lit-element": "^2.1.0",
    "webpack": "^4.31.0",
    "webpack-cli": "^3.3.2",
    "webpack-dev-server": "^3.3.1"
  }

tsconfig.json

lit-element.polymer-project.org

lit-elementのサイトにはmoduleはES2017と書かれていたが、どうやらtypescriptのmoduleはES2017を指定できないのでes2015を指定している(typescriptあまり詳しくないのでもしかしたら指定できるのかも?)

www.typescriptlang.org

Decoratorを使うため、experimentalDecoratorstrueで。

{
  "compilerOptions": {
    "target": "ES2017",
    "module": "es2015",
    "moduleResolution": "node",
    "lib": ["ES2017", "DOM"],
    "experimentalDecorators": true
  }
}

webpack.config.js

lit-elementだからといって特別な指定はなし。

const path = require('path');

module.exports = {
  entry: {
    raw: './src/js/raw.js',
    lit: './src/js/lit.js',
    ts: './src/js/ts.js'
  },
  output: {
    path: path.join(__dirname,'dist'),
    filename: '[name].js'
  },
  resolve: {
    extensions:['.ts', '.js']
  },
  devServer: {
    contentBase: path.join(__dirname,'dist')
  },
  module: {
    rules: [
      {
        test:/\.ts$/,
        loader:'ts-loader'
      }
    ]
  }
};

ts-my-element.ts

そもそもあんまりtypescriptを学んでないが、lit-elementのみで書く場合の差はcustomElements.defineとpropertyの指定の仕方くらい。

ちなみに、attributeで型の違うものを渡しても(下の例だとprop2に文字列)コンパイラがエラーを吐いたりしはしない。

普通にlit-elementで書くより行数は減る。

import { LitElement, html, customElement, css, property } from 'lit-element';

@customElement('ts-my-element')
export class MyElement extends LitElement {
    @property({type : String})  prop1 = 'Hello World';
    @property({type : Number})  prop2 = 5;
    @property({type : Boolean}) prop3 = true;
    @property({type : Array})   prop4 = [1,2,3];
    @property({type : Object})  prop5 = { subprop1: 'hi', thing: 'fasdfsf' };

    static get styles() {
        return css`
            p {
                display: block; 
                padding: 10px;
                border: 1px solid #e5e5e5;
            }
        `;
    }
    
    render() {
        return html`
          <p>prop1: ${this.prop1}</p>
          <p>prop2: ${this.prop2}</p>
          <p>prop3: ${this.prop3}</p>
    
          <p>prop4: ${this.prop4.map((item, index) =>
            html`<span>[${index}]:${item}&nbsp;</span>`)}
          </p>
    
          <p>prop5:
            ${Object.keys(this.prop5).map(item =>
            html`<span>${item}: ${this.prop5[item]}&nbsp;</span>`)}
          </p>
        `;
    }
}

typescriptをそもそもそんなに学んでいないので、ピンときていない・・・。

一応成果物

lit-element-sample.netlify.com