特定のキーを除く型(Omitをネストさせる)
type NestedOmit<T, K extends keyof T> = { [P in keyof Omit<T, K>]: T[P] extends Array<infer R> ? K extends keyof R ? Array<NestedOmit<R, K>> : Array<R> : K extends keyof T[P] ? NestedOmit<T[P], K> : T[P] };
例えばレシピとその材料を表す以下のinterfaceがあったとき
interface Recipe { id: number; name: string; ingredients: Ingredient[]; } interface Ingredient { id: number; name: string; }
作成apiにpostするデータとしては、idは不要。そのデータにつけるための型を用意する場合、色々やり方はあるが、例えば以下のようにしなければいけない
interface PostData { name: string; ingredients: Omit<Ingredient, "id">[]; }
idが共通して不要な場合、これはめんどくさいし、元のRecipeの型が変わったとき変更についていくのがだるそう
ので、冒頭に書いたようなねすとするOmitを定義してみた。
type PostData = NestedOmit<Recipe, "id">;
楽でいいな〜と思いつつ、こういうのってみなさんどうしてるんですかねと思った
GAEでcronを使って定時実行処理をする
定期的に処理を実行したいときがありますね。GAEはcronの設定ができます。
cron設定
アプリケーションのルートディレクトリにcron.yaml
ファイルを作成します。中身はこんな感じ
// cron.yaml cron: - description: "ゴミ出し通知" url: /cron schedule: every day 22:30 timezone: Asia/Tokyo
description
は省略できます。
以下、各プロパティの説明
url
cron設定をしておくと、このurlに対してscheduleした時間にGETリクエストを送ってくれます。定期的に実行したい処理を、GETリクエスト受けたときに実行できるようにアプリを書いておきます。
schedule
いつ実行するかを記述します。上のyaml設定例だと、毎日22:30に実行されます。 構文はここを参考に→ https://cloud.google.com/appengine/docs/flexible/go/scheduling-jobs-with-cron-yaml?hl=ja#Go_cron_yaml_The_schedule_format
timezone
schedule
のタイムゾーン。省略できます。省略した場合はUTC
デプロイ
あとはデプロイすればOKです。
$ gcloud app deploy cron.yaml
ここハマりました。普段どおり、gcloud app deploy
でアプリのデプロイすればcron反映されると思っていました。が、上のように、cron.yaml
指定してデプロイしないとだめでした。
参考
React useContextとemotion-themingを使ってテーマ切り替え機能を実装する🌔
emotion-themingを利用して、テーマ切り替え機能を実装します。Twitterのと一緒です。ボタン押して、toggleできるものを目指します。
Install
とりあえず
npx create-react-app dark-mode --typescript
emotion
yarn add @emotion/core @emotion/styled emotion-theming
モード切り替え
React.Contextに今どのモードなのかを保存、useContextを使って、コンポーネントからモード切り替えをします。
まずはContextを用意
// themeContext.ts import { createContext, useContext } from 'react'; interface ThemeContextType { colorMode: ColorMode; setColorMode: () => void; } const defaultContext: ThemeContextType = { colorMode: 'light', // 現在のモードを管理 setColorMode: () => {}, // colorMode書き換え用の関数を渡す }; export const ThemeContext = createContext<ThemeContextType>(defaultContext); export const useTheme = () => useContext(ThemeContext);
setColorMode
にcolorMode
を書き換えるための関数を渡します。(Providerのvalue propsで)
Theme用意
この辺はなんでもいいです。
import { ColorMode, Theme } from './types'; const lightTheme: Theme = { background: '#ffffff', color: '#000000', }; const darkTheme: Theme = { background: '#222639', color: '#f0f5fa', }; export function getTheme(colorMode: ColorMode): Theme { // mode受けてテーマ返す switch (colorMode) { case 'light': return lightTheme; case 'dark': return darkTheme; default: return lightTheme; } }
Providerの用意
上で定義した、getTheme()を使って、テーマを切り替えます
// ThemeProvider.tsx import React, { useState } from 'react'; import { ThemeProvider as EmotionProvider } from 'emotion-theming'; import { ThemeContext } from '../themeContext'; import { getTheme } from '../theme'; type ColorMode = 'light' | 'dark'; const ThemeProvider: React.FC = ({ children }) => { const [colorMode, setColorMode] = useState<ColorMode>('light'); function toggleColorMode() { // colorMode切り替え用関数 setColorMode(colorMode === 'light' ? 'dark' : 'light'); } return ( <EmotionProvider theme={getTheme(colorMode)}> <ThemeContext.Provider value={{ colorMode, setColorMode: toggleColorMode, }} > {children} </ThemeContext.Provider> </EmotionProvider> ); }; export default ThemeProvider;
あとは、コンポーネントから、useTheme() を使ってテーマを切り替えるだけ!
// App.tsx import React from 'react'; import './App.css'; import { useTheme } from './themeContext'; import styled from './components/styled'; const App: React.FC = () => { const { colorMode, setColorMode } = useTheme(); return ( <Container> <p>current color mode: {colorMode}</p> <button onClick={setColorMode}>toggle color mode</button> </Container> ); }; export default App; const Container = styled.div` height: 100%; background: ${props => props.theme.background}; color: ${props => props.theme.color}; `;
Typescriptを使っていると、emotionからimportしたstyled
を使うとtheme内にProviderで渡したプロパティの型情報が含まれていないため、使えないです。
styledに型情報をもたせて、それを替わりに使います。
参考:https://emotion.sh/docs/typescript#define-a-theme
// styled.tsx import styled, { CreateStyled } from '@emotion/styled'; import { Theme } from '../types'; export default styled as CreateStyled<Theme>; // 今回のthemeの型
やったね!
やったね。
おわり
以上です。Githubにあげてあります。
ExpressをTypescriptで書く
インストール
Express, Typescript, webpackをインストール
yarn add express yarn add -D @types/express typescript ts-loader webpack webpack-cli
ファイルの変更を検知してnode再起動してくれる nodemon をインストール
yarn add -D nodemon
Webpackの設定
webpack.config.js
const path = require('path'); module.exports = { mode: 'development', entry: './src/server.ts', target: 'node', devtool: 'inline-source-map', module: { rules: [ { loader: 'ts-loader', test: /\.ts$/, exclude: [/node_modules/], options: { configFile: 'tsconfig.json', }, }, ], }, resolve: { extensions: ['.ts', '.js'], }, output: { filename: 'server.js', path: path.resolve(__dirname, 'dist'), }, };
tsconfig
なんでもいいと思います。
{ "compilerOptions": { "noImplicitAny": true, "module": "es6", "target": "es5", "jsx": "react", "lib": ["es2018", "dom"], "moduleResolution": "node", "removeComments": true, "strict": true, "noUnusedLocals": true, "noUnusedParameters": false, "noImplicitReturns": true, "noFallthroughCasesInSwitch": true, "strictFunctionTypes": false, "strictNullChecks": true } }
express
動作確認程度。
src/server.ts
import * as Express from 'express'; const app = Express(); app.get('/', (req: Express.Request, res: Express.Response) => { return res.send('Hello world.'); }); app.listen(3000, () => { console.log('Example app listening on port 3000!'); }); export default app;
起動
package.json
に起動用のコマンドを追加。
webpack —watch
してnodemon
でoutput先を見張ります。
{ "scripts": { "dev": "webpack --config webpack.config.dev.js --watch & nodemon ./dist/server.js" }, "dependencies": { "express": "^4.17.1" }, "devDependencies": { "@types/express": "^4.17.0", "nodemon": "^1.19.1", "ts-loader": "^6.0.4", "typescript": "^3.5.2", "webpack": "^4.35.2", "webpack-cli": "^3.3.5" } }
以上です。
Githubに公開しておきました↓
Webpackとは(今更)
いつもなんとなくでググって出てくるものをコピペしてたので、自分で構成できるよう、調べた。
Webpack?
webpack is a static module bundler for modern JavaScript applications.
https://webpack.js.org/concepts/
module bundler?
モジュールをまとめてくれるツール
モジュールを組み合わせてアプリケーションを開発すれば、それぞれのモジュールは小さく、デバッグやテストをしやすい。 しかし、ファイル数が増えると、それだけリクエスト数は多くなってしまう。(遅延につながる) module bundlerを使えば、各ファイルを1つのファイルにまとめてくれる!(設定による)
設定については別の記事で書く予定です(多分)
今日から書くぞと意気込んでから76日も経ってるとは、、
今日から。
いままで技術系のアウトプットを(公開されているところで)したことがなかったので、今日から始める。
毎日は難しいかもしれないが、技術的につまずいたこと、調べたことはどんどん残していく。