かずきのBlog@hatena

日本マイクロソフトに勤めています。XAML + C#の組み合わせをメインに、たまにASP.NETやJavaなどの.NET系以外のことも書いています。掲載内容は個人の見解であり、所属する企業を代表するものではありません。

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