かずきのBlog@hatena

すきな言語は C# + XAML の組み合わせ。Azure Functions も好き。最近は Go 言語勉強中。日本マイクロソフトで働いていますが、ここに書いていることは個人的なメモなので会社の公式見解ではありません。

TypeScriptでmaterial-ui-mdiを使う

material-uiのアイコンセットでmaterial-ui-mdiっていうのがあります。

github.com

ちょっとアイコンセットがほしかったので試そうとしたらTypeScriptの型定義がないorz

ということで無ければ作ればいいじゃない?ということで、こんな感じのT4 Templateを書いてみました。

<#@ template debug="false" hostspecific="true" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ output extension=".d.ts" #>

///<reference path='../react/react.d.ts' />

import React = __React;
<#
var files = Directory
    .GetFiles(this.Host.ResolvePath(@".\..\..\node_modules\material-ui-mdi\icons"))
    .Select(x => Path.GetFileNameWithoutExtension(x))
    .Select(x =>
    {
        var tokens = x.Split('-');
        tokens = tokens.Select(y => char.ToUpper(y[0]) + y.Substring(1)).ToArray();
        return new { NS = x, CN = string.Concat(tokens) };
    });
#>

<#
foreach (var x in files)
{
#>
declare module 'material-ui-mdi/icons/<#= x.NS #>' {
    class <#= x.CN #> extends React.Component<{}, {}> {}
    export = <#= x.CN #>;
}
<#
}
#>

何十個もあるファイルから型定義を手動で書く(しかも機械的)はめんどかったのでT4 Templateでさくっとやりました。こんな感じの型定義がつくられます。

///<reference path='../react/react.d.ts' />

import React = __React;



declare module 'material-ui-mdi/icons/access-point-network' {
    class AccessPointNetwork extends React.Component<{}, {}> {}
    export = AccessPointNetwork;
}

declare module 'material-ui-mdi/icons/access-point' {
    class AccessPoint extends React.Component<{}, {}> {}
    export = AccessPoint;
}

... 続く ...

使うときはこんな感じで

import * as React from 'react';
import {AppBar, IconMenu, IconButton} from 'material-ui';
import DotsHorizontal = require('material-ui-mdi/icons/dots-horizontal');

export interface HeaderProps extends React.Props<{}> {
}

export interface HeaderState {
}

export class Header extends React.Component<HeaderProps, HeaderState> {
    render() {
        return <AppBar
            title='Material UI TODO アプリケーション'
            iconElementRight={
                <IconMenu iconButtonElement={<IconButton><DotsHorizontal /></IconButton>}>
                </IconMenu>
            }/>;
    }
}

ちゃんと水平に並んだどっとが表示されました。

f:id:okazuki:20151230131722p:plain